排序与查找代码总结-数据结构与算法python版

代码来源于北京大学的数据结构与算法课(Python版),注释为本人自己加上的,可供学习使用,不可用于商业转载,有错误烦请指出,感谢~

目录

二分查找

普通版

递归版

冒泡排序

普通版

加了是否发生交换的监测

选择排序

插入排序

希尔排序

归并排序

普通版

python风格版

快速排序

基数排序


二分查找

普通版

# 二分查找
def binarySearch(alist, item):
    first = 0  # 查找范围第一项的下标
    last = len(alist)-1   # 查找范围最后一项的下标
    found = False

    while first<=last and not found:
        midpoint = (first + last)//2   # 中间项下标
        # 若列表alist的中间项与查找项item相等,则查找成功,found置为True
        # 否则就需要缩小比对范围,分为两种情况:
        # 1.查找项比中间项小,说明查找项在前半部分,更改last
        # 2.查找项比中间项大,说明查找项在后半部分,更改first
        if alist[midpoint] == item:
            found = True
        else:
            if item < alist[midpoint]:
                last = midpoint-1
            else:
                first = midpoint+1

    return found

testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
print(binarySearch(testlist, 3))
print(binarySearch(testlist, 13))

输出:

False
True

递归版

# 递归的二分查找
def binarySearch(alist, item):
    if len(alist) == 0:  # 递归的基本结束条件
        return False
    else:
        midpoint = len(alist)//2
        if alist[midpoint]==item:
          return True
        else:   # 缩小规模
            # 若查找项小于中间项,则需要递归调用自身来实现对前半部分(从最开始到中间)的查找,返回递归的结果
            # 否则查找项大于中间项,则需要递归调用自身来实现对后半部分(从中间到最后)的查找,返回递归的结果
            if item<alist[midpoint]:
                return binarySearch(alist[:midpoint],item)
            else:
                return binarySearch(alist[midpoint+1:],item)

testlist = [0, 1, 2, 8, 13, 17, 19, 32, 42,]
print(binarySearch(testlist, 3))
print(binarySearch(testlist, 13))

输出:

False
True

冒泡排序

普通版

# 冒泡排序
def bubbleSort(alist):
    for passnum in range(len(alist)-1,0,-1):  # passnum从n-1开始,一直减到1,总共进行n-1趟排序
        for i in range(passnum):   # i从0开始,一直到(passnum-1),包括了这一趟比较的范围
            # 对第i项和相邻的第i+1进行比较
            # 如果是逆序的,就交换
            if alist[i]>alist[i+1]:
                temp = alist[i]
                alist[i] = alist[i+1]
                alist[i+1] = temp

alist = [10,1,35,61,89,36,55]
#alist = [54,26,93,17,77,31,44,55,20]
bubbleSort(alist)
print(alist)

输出:

[1, 10, 35, 36, 55, 61, 89]

加了是否发生交换的监测

def shortBubbleSort(alist):
    exchanges = True    # 通过exchanges监测每趟比对是否发生过交换
    passnum = len(alist)-1     # passnum从n-1开始
    while passnum > 0 and exchanges:  # 当还未完成n-1趟排序 且 上一趟排序发生了交换,则继续下一趟排序
        # 每趟排序首先将exchanges置为False,只要发生了交换就将其置为True
        exchanges = False
        for i in range(passnum):
            if alist[i]>alist[i+1]:
                exchanges = True
                temp = alist[i]
                alist[i] = alist[i+1]
                alist[i+1] = temp
        passnum = passnum-1

alist=[20,30,40,90,50,60,70,80,100,110]
shortBubbleSort(alist)
print(alist)

输出:

[20, 30, 40, 50, 60, 70, 80, 90, 100, 110]

选择排序

def selectionSort(alist):
   for fillslot in range(len(alist)-1,0,-1):   # fillslot从n-1开始,一直减到1,总共进行n-1趟排序
       positionOfMax=0    # 用于记录当前最大项所在的位置
       for location in range(1,fillslot+1):
           # 对列表中的数据进行比较,得到最大项所在的位置
           if alist[location]>alist[positionOfMax]:
               positionOfMax = location

       # 交换位置
       temp = alist[fillslot]
       alist[fillslot] = alist[positionOfMax]
       alist[positionOfMax] = temp

# alist = [54,26,93,17,77,31,44,55,20]
alist = [49,38,65,97,76,13,27,49]
selectionSort(alist)
print(alist)

输出:

[13, 27, 38, 49, 49, 65, 76, 97]

插入排序

def insertionSort(alist):
    for index in range(1,len(alist)):  # 需要将第1个数据项后的n-1个数据项插入到有序子列表,循环n-1次
        currentvalue = alist[index]  # 当前的插入项
        position = index
        # 进行比较和移动
        while position>0 and alist[position-1]>currentvalue:
            alist[position]=alist[position-1]
            position = position-1
        # 插入新项
        alist[position]=currentvalue

alist = [54,26,93,17,77,31,44,55,20]
insertionSort(alist)
print(alist)

输出:

[17, 20, 26, 31, 44, 54, 55, 77, 93]

希尔排序

def shellSort(alist):
    sublistcount = len(alist) // 2   # 设定初始增量为n/2
    while sublistcount > 0:  # 不断缩小增量,进行多趟排序
        for startposition in range(sublistcount):  # 每进行一次循环就对某一个子列表进行排序
            # 调用gapInsertionSort函数对子列表进行排序
            gapInsertionSort(alist,startposition,sublistcount)
        print("增量为",sublistcount,":",alist)
        sublistcount = sublistcount // 2

# 带间隔的插入排序
def gapInsertionSort(alist,start,gap):
    for i in range(start+gap,len(alist),gap):  # 循环的次数表示插入排序的趟数
        currentvalue = alist[i]   # 当前插入项的值
        position = i    # 当前插入项所在的位置
        # 当 position-gap 位置有数据项 且 当前插入项小于 position-gap 位置的数据项,就不断地进行以下操作
        # 将 position-gap 位置的数据项在子列表中向右移动一个位置
        # position 指向 position-gap 位置
        while position>=gap and alist[position-gap]>currentvalue:
            alist[position]=alist[position-gap] 
            position = position-gap
        alist[position]=currentvalue   # 找到当前插入项的插入位置
        
alist = [54,26,93,17,77,31,44,55,20]
#alist = [49,38,65,97,76,13,27]
#alist = [30,20,40,90,50,60,80,70,110,100]

shellSort(alist)
print(alist)

输出:

增量为 4 : [20, 26, 44, 17, 54, 31, 93, 55, 77]
增量为 2 : [20, 17, 44, 26, 54, 31, 77, 55, 93]
增量为 1 : [17, 20, 26, 31, 44, 54, 55, 77, 93]
[17, 20, 26, 31, 44, 54, 55, 77, 93]

归并排序

普通版

def mergeSort(alist):
    #print("Splitting ",alist)
    if len(alist)>1:  # 基本结束条件
        mid = len(alist)//2
        lefthalf = alist[:mid]
        righthalf = alist[mid:]
        # 递归调用mergeSort来对切片得到左半部分和右半部分进行排序
        mergeSort(lefthalf)
        mergeSort(righthalf)
        i=0
        j=0
        k=0
        # 此时左半部分和右半部分都已排好序,接下来需要对排好序的左右两半进行合并
        while i<len(lefthalf) and j<len(righthalf):
            # 拉链式交错把左右半部分从小到大归并到结果列表中
            if lefthalf[i]<righthalf[j]:
                alist[k]=lefthalf[i]
                i=i+1
            else:
                alist[k]=righthalf[j]
                j=j+1
            k=k+1
        # 归并左半部分的剩余项
        while i<len(lefthalf):
            alist[k]=lefthalf[i]
            i=i+1
            k=k+1
        # 归并右半部分的剩余项
        while j<len(righthalf):
            alist[k]=righthalf[j]
            j=j+1
            k=k+1
    #print("Merging ",alist)
    
alist = [54,26,93,17,77,31,44,55,20]
mergeSort(alist)
print(alist)

输出:

[17, 20, 26, 31, 44, 54, 55, 77, 93]

python风格版

#python风格的归并排序
def merge_sort(lst):
    # 递归结束条件
    if len(lst) <= 1:
        return lst
    # 分解问题,并递归调用
    middle = len(lst) // 2
    left = merge_sort(lst[:middle])  # 左半部分排序
    right = merge_sort(lst[middle:])  # 右半部分排序
    # 合并左右半部,完成排序
    merged = []
    # 只要左右部分还有数据,就进行合并
    # 将左半部分的首个数据(位置为0的数据)与右半部分的首个数据进行比较
    # 把更小的数据添加到merged列表中,同时把它从原来所在列表中删除(下一次比较还是从0位置开始)
    while left and right:
        if left[0] <= right[0]:
            merged.append(left.pop(0))
        else:
            merged.append(right.pop(0))
    # 合并未合并的部分
    merged.extend(right if right else left)
    # 返回结果
    return merged


alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(merge_sort(alist))

输出:

[17, 20, 26, 31, 44, 54, 55, 77, 93]

快速排序

# 快速排序
def quickSort(alist):
    quickSortHelper(alist,0,len(alist)-1)

# 指定当前排序列表开始(first)和结束(last)位置的快速排序
def quickSortHelper(alist,first,last):
    if first<last:   # 当列表至少包含两个数据项时,做以下操作
        # 调用partition函数对当前排序列表进行拆分,返回分割点splitpoint
        splitpoint = partition(alist,first,last)
        # 递归调用quickSortHelper函数对拆分得到的左部分和右部分进行快速排序
        quickSortHelper(alist,first,splitpoint-1)
        quickSortHelper(alist,splitpoint+1,last)

# 拆分列表
def partition(alist,first,last):
    pivotvalue = alist[first]  # 选定基准值为列表的第一个数据项

    leftmark = first+1   # 左标
    rightmark = last     # 右标

    done = False
    while not done:
        # 将左标向右移动,直至遇到一个大于基准值的数据项
        while leftmark <= rightmark and  alist[leftmark] <= pivotvalue:
            leftmark = leftmark + 1
        # 将右标向左移动,直至遇到一个小于基准值的数据项
        while rightmark >= leftmark and alist[rightmark] >= pivotvalue:
            rightmark = rightmark -1
        # 右标小于左标时,结束移动
        if rightmark < leftmark:
            done = True
        # 否则将左、右标所指位置的数据项交换
        else:
            temp = alist[leftmark]
            alist[leftmark] = alist[rightmark]
            alist[rightmark] = temp
    # 将基准值就位
    temp = alist[first]
    alist[first] = alist[rightmark]
    alist[rightmark] = temp

    return rightmark    # 返回基准值位置,即分割点
   
alist = [54,26,93,17,77,31,44,55,20]
quickSort(alist)
print(alist)

输出:

[17, 20, 26, 31, 44, 54, 55, 77, 93]

基数排序

# 队列
class Queue:
    def __init__(self):
        self.items = []

    def isEmpty(self):     # 判空
        return self.items == []

    def enqueue(self, item):     # 入队
        self.items.insert(0,item)

    def dequeue(self):     # 出队
        return self.items.pop()

    def size(self):     # 求队列元素个数
        return len(self.items)

# 基数排序
def radix_sort(s):
    main = Queue()
    for n in s:
        main.enqueue(n)   # 所有数据项入队
    d = len(str(max(s)))  # 求出最大数据项的位数
    dstr = "%%0%dd" % d    # 前导零的模板,把数据项补齐为d位,位数不够的前面置0,如"%05d"表示补齐成五位数
    nums = [Queue() for _ in range(10)]   # 准备10个队列
    for i in range(-1, -d-1, -1):   # i的取值为-1到-d,代表从个位到最高位
        while not main.isEmpty():   # 进行分配
            n = main.dequeue()
            dn = (dstr % n)[i]  # 得到出队数据的第i位,转成类似"00345"[-2],即得到倒数第二位的4
            nums[int(dn)].enqueue(n)  # 放到对应的队列中

        for k in range(10):   # 从10个队列中收集到main
            while not nums[k].isEmpty():
                main.enqueue(nums[k].dequeue())
    # 从main导出为列表
    result = []
    while not main.isEmpty():
        result.append(main.dequeue())
    return result

输出:

[20, 30, 40, 50, 60, 70, 80, 90, 100, 110]

猜你喜欢

转载自blog.csdn.net/zhyue77yuyi/article/details/113182378