VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > 简明python教程 >
  • Python知识点(4)

复制代码
'''
二分查找(升序)
arr:传入的序列
data:需要查找的数据
'''

def binarySearch(arr,data):
    len_arr = len(arr)
    mid = len_arr // 2
    
    if len_arr >= 1:
        if arr[mid] > data:
            return binarySearch(arr[0:mid],data)
        elif arr[mid] < data:
            return binarySearch(arr[mid+1:],data)
        else:
            return True
    # 列表长度小于1,代表查询结束,没有找到需要的数据
    else:
        return False

l = [1,2,3,4,5]
print(binarySearch(l,2)) # True
print(binarySearch(l,9)) # False
复制代码

 

 

 

 

120.找出列表中的重复数字

复制代码
l = [2,1,3,3,6,2,4,7,2]
# 方法一
from collections import Counter
print(Counter(l)) # 打印Counter({2: 3, 3: 2, 1: 1, 6: 1, 4: 1, 7: 1})

# 方法二
d = {}
for i in l:
    d[i] = l.count(i)
print(d)


# 方法三
s = set(l)
for i in s:
    print('%s有%s个' %(i,l.count(i)))
复制代码

 

 

 

 

121.写一个冒泡排序、快速排序、拓扑排序

  • 冒泡排序 
    • 原理:一组无序的列表,遍历整个列表,依次比较相邻的两个数,如果后面的数比前面的小,则两数交换位置,第一轮排序过后最大的数字就被排到了末尾,下一轮只用遍历到倒数第二个数即可,以此类推,直到整个列表变为有序(升序)列表即可退出循环。
  • 快速排序
    • 原理:在一组序列中选取一个基准值(可以随便选,最好选取中间位置的值),循环查找出比基准值小的放在左边,比基准值大的放在右边,然后在左右两边递归重复上面的步骤,知道列表的长度为1或0表示排序结束,返回列表。
    • 缺点:
      • 基准值的选取对排序的性能有决定性的影响
      • 不稳定,比如基准值前后都有和基准值相同的数据,那么相同值就会被放在一边,打乱了之前的相对顺序
      • 对于小规模的数据集性能不是很好
复制代码
l = [33,218,7,96,45,11,4,99,63,28]

# 冒泡排序
def bubbling_sort(l):
    len_l = len(l)
    # 外层循环控制循环的次数
    for i in range(len_l - 1):
        # 内层循环控制遍历到哪一位
        for j in range(len_l - 1 - i):
            # 如果后一位比前一位小,则交换位置
            if l[j+1] < l[j]:
                l[j],l[j+1] = l[j+1],l[j]
    return l


# 快速排序
def fast_sort(l):
    # 如果列表的长度等于0或1表示排序结束,返回列表
    if len(l) < 2:
        return l
    else:
        # 选取基准值
        mid = l[len(l) // 2]
        # 先把基准值从列表中排序,不然会有重复
        l.remove(mid)
        left = [i for i in l if i < mid]
        right = [j for j in l if j > mid]
        return fast_sort(left) + [mid] + fast_sort(right)
        
        

print('冒泡排序的结果:%s' %bubbling_sort(l))
print('快速排序的结果:%s' %fast_sort(l))
复制代码

 

 

 

 

 

122.python 实现一个二进制计算

a = '10010' # 18
b = '11000' # 24

a,b = int(a,2),int(b,2) # int()第二个参数表示传入的字符串进制数,默认十进制,返回结果十进制
print(bin(a+b)[2:]) # bin(a+b) 返回0b101010,所以要从第三位开始取

 

 

 

 

123.有一组“+”和“-”符号,要求将“+”排到左边,“-”排到右边,写出具体的实现方法

复制代码
def symbol_sort(symbols):
    l1 = list()
    l2 = list()
    for s in symbols:
        if s == '+':
            l1.append(s)
        else:
            l2.append(s)
        
    l1.extend(l2)
    return l1
sym = '+--+++-'
print(symbol_sort(sym))
复制代码

 

 

 

 

124.单链表反转

  反转链表的图例,便于理解:https://blog.csdn.net/songyunli1111/article/details/79416684

复制代码
class ListNone():
    def __init__(self,val):
        self.val = val
        self.next = None
        
'''
主要逻辑步骤:
1.先把第一个节点后的数据保存赋值给一个变量
2.把第一个变量的next赋值为空,即从链表分裂掉第一个节点
3.把声明的指针指向分裂出来的节点
4.最后把链表的头部指针赋值给下一个节点,即指针往后移动一位
如此循环......
'''        
def reverseList(head):
    last = None
    while head:
        tmp = head.next
        head.next = last
        last = head
        head = tmp
    return last

l = ListNone(1)
l.next = ListNone(3)
l.next.next = ListNone(9)
l1 = reverseList(l)
print(l1.val,l1.next.val,l1.next.next.val) # 打印  9  3  1
复制代码

 

 

 

 

125.交叉链表的交叉点(若两个链表有一个公共结点,则该公共节点之后的所有结点都是重合的,及它们的最后一个结点必然重合)

复制代码
'''
交叉链表逻辑:
若两个链表有一个公共结点,则该公共节点之后的所有结点都是重合的,及它们的最后一个结点必然重合(结构是Y字形)
利用这个特性,可以先获取两个列表的长度,然后长的列表比短的链表先走(len(长)-len(短))个长度,然后两个链表的指针同时往后走
直到找到公共节点,没有找到相交节点返回None
'''

class ListNode():
    def __init__(self,val,next=None):
        self.val = val
        self.next = next
        

# 获取链表长度
def get_length(head):
    length = 0 
    while head:
        length += 1
        head = head.next
    return length


# 获取公共节点
def get_cross_node(list_a,list_b):
    len_a = get_length(list_a)
    len_b = get_length(list_b)
    
     # 给两个链表各声明一个指针
    cur_a = list_a
    cur_b = list_b
    if len_a > len_b:
        for i in range(len_a - len_b):
            cur_a = list_a.next
    else:
        for i in range(len_b - len_a):
            cur_b = list_b.next
            
    
    flag = False
    while cur_a and cur_b:
        if cur_a.val == cur_b.val:
            print(cur_a.val)
            flag = True
            break
        else:
            cur_a,cur_b = cur_a.next,cur_b.next
    
    if not flag:
        print("链表没有交叉节点")
    
list_a = ListNode('a1',ListNode('a2',ListNode('c1',ListNode('c2',ListNode('c3')))))
list_b = ListNode('b1',ListNode('b2',ListNode('b3',ListNode('c1',ListNode('c2',ListNode('c3'))))))
get_cross_node(list_a,list_b)
复制代码

 

 

 

 

126.用队列实现栈

复制代码
'''
栈:先进后出
队列:先进先出


方法一:

逻辑:
进栈push:在一个空的队列中添加元素,然后把另一个非空队列中的元素弹出并追加到该队列后面,所以,总会有一个队列是空的,以此循环追加即可
删除栈顶元素pop: 进栈时已把元素重新排序,所以直接弹出栈顶元素即可




方法二:

使用列表的insert()方法,指定每次插入的元素都放在最前面
'''


# 方法一
class Stack1():
    
    def __init__(self):
        self.queue_a = []
        self.queue_b = []
    
    
    # 进栈
    def push(self,n):
        if len(self.queue_a) == 0:
            self.queue_a.append(n)
        elif len(self.queue_b) == 0:
            self.queue_b.append(n)
        
        # 把队列b中的元素追加到a的后面
        if len(self.queue_a) == 1 and len(self.queue_b) > 1:
            for i in range(len(self.queue_b)):
                self.queue_a.append(self.queue_b.pop(0))
        elif len(self.queue_b) == 1 and len(self.queue_a) >= 1:
            for i in range(len(self.queue_a)):
                self.queue_b.append(self.queue_a.pop(0))
                
    # 删除栈顶元素
    def pop(self):
        if self.queue_a:
            return self.queue_a.pop(0)
        elif self.queue_b:
            return self.queue_b.pop(0)
        else:
            return None
    
    # 查询当前栈内元素
    def get_stack(self):
        if self.queue_a:
            return self.queue_a
        elif self.queue_b:
            return self.queue_b
        else:
            return None
    
    # 查询栈顶元素:
    def peek(self):
        if self.queue_a:
            return self.queue_a[0]
        elif self.queue_b:
            return self.queue_b[0]
        else:
            return None

    # 查询当前栈长度
    def len_stack(self):
        if self.queue_a:
            return len(self.queue_a)
        elif self.queue_b:
            return len(self.queue_b)
        else:
            return None


        
# 方法二
class Stack2():
    def __init__(self):
        self.list_a = list()
        
    def push(self,num):
        self.list_a.insert(0,num)
    
    def get_stack(self):
        return self.list_a
    
    

s = Stack1()
s2 = Stack2()

for i in range(5):
    s.push(i)
    s2.push(i)
    
print(s.get_stack()) # [4,3,2,1,0]
print(s.pop())
print(s.get_stack())
print(s.pop())
print(s.get_stack())
print(s.pop())
print(s.get_stack())
print('*'*50)
print(s2.get_stack()) # [4,3,2,1,0]
复制代码

 

 

 

 

127.找出数据流的中位数

  • 中位数:有序列表中间的数。如果列表元素个数是偶数,中位数是中间两个数的平均数;如果是奇数,则就是中间的数
复制代码
def get_mid(l):
    l.sort()
    if len(l) == 0:
        return
    elif len(l) == 1:
        return l[0]
    else:
        if len(l) % 2 == 0:
            mid = (l[len(l) // 2] + l[len(l) // 2 - 1]) / 2
        else:
            mid = l[len(l) // 2]
            
        return mid
    
l = [2,15,7,3,100,10]
print(get_mid(l)) # 8.5
复制代码

 

 

 

 

128.二叉搜索树中第 K 小的元素

  • 关于二叉树:https://www.jianshu.com/p/9503238394df
  • 关于二叉搜索树:https://www.cnblogs.com/lliuye/p/9118591.html
  • 算法:利用二叉搜索树特点(左树都比根节点小,右树都比根节点大),使用中序遍历后结果保存在列表中,其结果一定是有序排序,找出第K-1位元素即可
复制代码
class Node():
    def __init__(self,n):
        self.val = n
        self.left = None
        self.right = None
        
'''
数据域:节点中存储数据元素的部分
指针域:节点中存储数据元素之间的链接信息,即链接到下一节点地址的部分
内嵌函数: 内部函数需要递归调用并不能实现全部功能,外层函数完成剩余功能,也可以分开写

'''
def kthSmallest(root,k):
        
#         l = list()
        def search_min(root):
            if not root:
                return []
            # 在内层函数申明列表是因为只需返回最后一次递归的结果,即[10, 12, 15, 16, 20, 21, 22, 23]
            # 若是申明在外部,则会把每一层递归的结果都追加的列表里 [10,10,12,10,10,12,15,10,10,12,15,16........]
            l = list()
            # 递归查询左树数据域
            l.extend(search_min(root.left))
            l.append(root.val)
            # 递归查询右树数据域
            l.extend(search_min(root.right))
            return l
        return search_min(root)[k-1]

n1 = Node(20)
n1.left = Node(15)
n1.right = Node(22)
n1.left.left = Node(12)
n1.left.right = Node(16)
n1.left.left.left = Node(10)
n1.right.left = Node(21)
n1.right.right = Node(23)


kthSmallest(n1,6) # 21
复制代码

 

 

 

 

129.TCP 和 UDP 的区别

  • TCP协议在传送数据段的时候要给段标号;UDP不用
  • TCP协议可靠;UDP不可靠
  • TCP协议是面向连接;UDP采用无连接
  • TCP协议负载较高,采用虚电路;UDP采用无连接
  • TCP协议发送方要确认接收方是否收到数据段(三次握手协议)
  • TCP协议采用窗口技术和流控制

 

 

 

 

130.简要介绍三次握手和四次挥手

  • 三次握手
    • 第一次握手
      • Client端首先发送一个SYN包告诉Server端我的初始序列号是X,Client进入SYN-SENT(同步已发送)状态
    • 第二次握手
      • Server端收到SYN包后回复给Client端一个ACK确认包,告诉Client端我收到了,Server端进入SYN-RCVD(同步收到)状态
      • Server端也需要告诉Client端一个初始序列号,于是,Server端也发送一个SYN包告诉Client端我的初始序列号是Y
    • 第三次握手
      • Client收到后,回复给Server端一个ACK确认包说我知道了,之后Client和Server进入ESTABLISHED(已建立连接)状态,完成三次挥手
  • 四次挥手
    • 第一次挥手
      • Client端发送一个FIN包告诉Server端我的初始序列号是X,用来关闭Client到Server的数据传送,Client端进入FIN_WAIT_1(主动关闭,已经发送关闭请求,等待确认)状态
    • 第二次挥手
      • Server端收到FIN包后,发给Client端一个ACK确认包,Server端进入CLOSE_WAIT(被动关闭,收到对方关闭请求,已经确认)状态
    • 第三次挥手
      • Server端发送一个FIN包告诉Client端我的序列号是Y,用来关闭Server端到Client端的数据传送,同时发送给Client一个ACK确认包,Server端进入LAST_ACK(被动关闭,等待最后一个关闭确认,并等待所有分组死掉)状态
    • 第四次挥手
      • Client端收到FIN包后进入TIME_WAIT(完成双向关闭,并等待所有分组死掉)状态,接着发给给Server端一个ACK确认包,Server端进入CLOSED(关闭状态,没有连接活动或正在进行)状态,完成四次挥手

 

  扩展:三次握手改成两次握手可以吗?不可以,主要防止已经失效的请求连接突然又传送到了服务器,从而产生错误

 

 

 

 

132.TIME_WAIT状态的作用

  主动关闭的那端最后经历的状态,一般为2MSL秒(1~4分钟)

  • 保证当最后一个ACK包丢失后,能收到对端重新传的FIN包
  • 保证ACK包消失,不会影响下一个连接

 

 

 

 

132.什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?

  定义:在接收数据时,一次性多接收了其他请求发送来的数据(即多包接收)。比如,对方第一次发送hello,第二次发送world,在接收时应该接收两次,一次是hello,一次是world,但事实上一次收到

     helloworld,一次收到空,这种现象叫粘包。

  原因:主要是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的

  会发生的情况:

  • 发送端需要等缓存区满才发送出去,造成粘包(发送数据时间间隔很短,数据很小,会合到一起,产生粘包) 
  • 接收方不及时接收缓存区的包,造成多个包接收(客户端发送了一段数据,服务端只接收了一小部分,服务端下次再收的时候还是从缓存区拿上次遗留的数据,产生粘包)   

 

 

 

133.举例说明 concurrent.futures 中的线程池的用法

  concurrent.futures模块的基础是Exectuor,Exectuor是一个抽象类,不能直接被调用,它的子类ThreadPoolExectuor和ProcessPoolExectuor,分别用来创建线程池和进程池,可以将相应的tasks放入相应

  的线程池/进程池,不需要维护Queue来操心死锁的问题,线程池/进程池会自动调度

复制代码
from concurrent.futures import ThreadPoolExecutor
import time

def ret_msg(msg):
    time.sleep(2)
    return msg

pool = ThreadPoolExecutor(max_workers=2) # 最多加入两个task

future1 = pool.submit(ret_msg,("hello")) # 加入task1
future2 = pool.submit(ret_msg,("world")) # 加入task2

print(future1.done()) # 查看task1任务是否完成 打印False
time.sleep(3)
print(future2.done()) # 打印True
print(future1.result()) # 查看task1结果
print(future2.result())
复制代码

 

 

 

 

134.说一说多线程,多进程和协程的区别

  • 线程与进程比较
    • 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
    • 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
    • 线程是处理器调度的基本单位,但进程不是
    • 二者均可并发执行
    • 每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口,但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
  • 线程与协程比较
    • 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU
    • 线程进程都是同步机制,而协程是异步
    • 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

 

 

 

 

135.进程之间如何通信

  共享内存、信号量、互斥锁、消息队列等

 

 

 

 

136.IO 多路复用的作用

  I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要

  在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间

 

 

 

 

137.select、poll、和epoll模型的区别

 

 

 

 

138.什么是并发和并行

 

 

 

 

139.一个线程 1 让线程 2 去调用一个函数怎么实现

复制代码
import threading

def func1(t2):
    print("我是func1")
    t2.start()
    
    
t2 = threading.Thread()
t1 = threading.Thread(target=func1,args=(t2,))
t1.start()
复制代码

 

 

 

 

140.解释什么是异步非阻塞

  当一个异步过程调用发出后,调用者不会立刻得到结果。实际处理这个调用的部件是在调用发出后,通过状态、通知来通知调用者,或通过回调函数处理这个调用;非阻塞的意思是,不能立刻得到结果

  之前,该函数不会阻塞当前线程,而会立刻返回

 

 

 

 

141.threading.local 的作用

  Python提供了 threading.local 类,将这个类实例化得到一个全局对象,但是不同的线程使用这个对象存储的数据其它线程不可见(本质上就是不同的线程使用这个对象时为其创建一个独立的字典)

 

 

 

 

142.说说你知道的 git 命令

 

 

 

143.git 如何查看某次提交修改的内容

  知道commit id的情况下:

  1. 获取commit id

       git log 

 

  2. 查看commit内容

       git show commit_id

 

  查看最近n次提交的修改

       git log -p -n

  指定n为1则可以查看最近一次修改的内容

 

并行”指两个或两个以上事件或活动在同一时刻发生。在多道程序环境下,并行性使多个程序同一时刻可在不同CPU上同时执行


相关教程
          
关于我们--广告服务--免责声明--本站帮助-友情链接--版权声明--联系我们       黑ICP备07002182号