学习笔记(数据结构与算法)
1.顺序查找__O(N)
直接按顺序遍历列表的下标,最好的情况“对比”一次就找到,最差的情况“对比”N次。因此时间复杂度为O(N)
def sequantialSearch(alist,item):
found = False # 控制查找结束
pos = 0
while pos < len(alist) and not found:
if alist[pos] == item:
found = True
else:
pos += 1
return found
2.二分查找__O(logN) (仅针对有序表有效)
def binarySearch(alist,item):
found = False
first = 0
last = len(alist)-1
while first <= last and not found:
midpoint = (first+last)//2
if alist[midpoint] == item:
found = True
else:
if alist[midpoint] > item:
last = midpoint - 1
else:
first = midpoint + 1
return found
#递归 采用了切片会更复杂
def binarySearch(alist,item):
if len(alist) == 0:
return False
else:
midpoint = len(alist)//2
if alist[midpoint] == item:
return True
else:
if alist[midpoint] > item:
return binarySearch(alist[:midpoint],item)
else:
return binarySearch(alist[midpoint+1:],item)
3.冒泡排序__O(n²)
长度为n的列表,第一次遍历,从第一项开始,如果和下一项是逆序,则交换位置,经过n-1次对比后,第n项即是最大项。第二次遍历又从头开始,和下一项逆序则交换位置,经过n-2次对比,第n-1项即是第二大项,一次类推…
def bubbleSort(alist):
exchange = True #如果某趟对比没有发生交换,表示已经排好序,提前结束循环。
passnum = len(alist)-1
while passnum>0 and exchange:
for i in range(passnum):
exchange = False
if alist[i] > alist[i+1]:
exchange = True
alist[i], alist[i+1] = alist[i+1], alist[i]
passnum = passnum - 1
4.选择排序__O(n²)
与冒泡排序类似,不同的是,冒泡排序是对比一次,有逆序就立刻交换位置。选择排序是记录最大值的位置,最后与再最右端的数据交换位置。
def selectSort(alist):
for passnum in range(len(alist)-1,0,-1):
posOfMax = 0 # 记录最大值位置
for i in range(1,passnum+1):
if alist[i] > alist[posOfMax]:
posOfMax = i
alist[passnum], alist[posOfMax] = alist[posOfMax], alist[passnum] #每一趟结束交换位置
5.插入排序__O(n²)
对每一个数据进行寻找插入位置的操作。比如:从第二个数据项开始currentPos=1,如果比前一项小,就将第一个数据项右移;如果当前为第三个数据currentValue,比第二个数据项小,就将第二个数据项右移,当前位置变为第二,再与前一个数据,也就是第一个数据比,如果第一个数据更大,则将第一个数据右移,当前位置变为第一,此时,while循环结束。将alist[currentPos]=currentValue
def insertSort(alist):
for i in range(1,len(alist)):
currentPos = i
currentValue = alist[i]
while currentPos > 0 and alist[currentPos-1] > currentValue:
alist[currentPos] = alist[currentPos-1]
currentPos = currentPos - 1
alist[currentPos] = currentValue
6.谢尔排序__O(n)~O(n²)
是在对无序表进行间隔划分,比如将有n个数据项的列表每隔n/2个数据划分,得到n/2个子列表,对每个子列表进行插入排序,然后再缩小划分间隔,变成n/4,再对每个子列表进行插入排序…直到间隔为1,即是标准的插入排序,由于之前进行的子列表排序,此时的列表已接近有序,只需要稍微调整几个位置即可,对比的次数很少。
def shellSort(alist):
space = len(alist) // 2
while space >= 1:
for start in range(space):
gapInsertSort(alist,start,space)
space = space //2
def gapInsertSort(alist,start,gap):
for i in range(start+gap,len(alist),gap):
currentValue = alist[i]
currentPos = i
while currentPos > 0 and alist[currentPos-gap] > currentValue:
alist[currentPos] = alist[currentPos-gap]
currentPos -= gap
alist[currentPos] = currentValue
7.归并排序__O(nlogn)
先递归:将列表分为两半,分别对两半进行排序。基本结束条件是当列表被分到不能再分的时候即里面不足2个数。
再创建一个空列表进行归并。
def mergeSort(alist):
if len(alist) <= 1:
return alist
else:
mid = len(alist) // 2
left = mergeSort(alist[:mid])
right = mergeSort(alist[mid:])
merge = []
while left and right: #当左右都不是空列表
if left[0] < right[0]: # 若左边最小的大于右边最小的
merge.append(left.pop(0)) #加入mergt,并且在left中删除
else:
merge.append(right.pop(0))
merge.extend(right if right else left) #当某一边列表有剩余时,直接加入merge末尾
return merge
8.快速排序__O(nlogn)~O(n²)
依据一个“中值”,将列表分为:大于“中值”的子列表和小于“中值”的子列表。每个子列表再选“中值”继续分…将此过程递归。
为了方便一遍都直接选取列表的第一项为“中值”,这种方法的时间复杂度受选取的“中值”影响很大,若选取的“中值”刚好将整个列表分为数量相等的两个子列表,则时间复杂度为O(nlogn)。若不幸,选取的“中值”分成的左右两列表数量差距很大,甚至其中一边几乎没有数据,那么复杂度为O(n²)。
def quickSortHelp(alist):
quickSort(alist,0,len(alist)-1)
def quickSort(alist,first,last):
if first < last: #基本结束条件
mid = partition(alist,first,last)
quickSort(alist,first,mid-1) #调用自身
quickSort(alist,mid+1,last)
def partition(alist,first,last):
pivotValue = alist[first]
leftmark = first+1
rightmark = last
stop = False
while not stop:
while leftmark <= rightmark and alist[leftmark]<=pivotValue:
leftmark += 1
while rightmark >= leftmark and alist[rightmark] >= pivotValue:
rightmark -= 1
if leftmark > rightmark:
stop = True
else:
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
temp = alist[rightmark]
alist[rightmark] = pivotValue
alist[first] = temp
return rightmark