Python 数据结构与算法分析 三、搜索

搜索

二分搜索的递归实现

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+1],item)
            else:
                return BinarySearch(alist[:midpoint],item)

二分搜索算法的时间复杂度是O(logn)
尽管二分搜索通常优于顺序搜索,但当n较小时,排序引起的额外开销可能并不划算。世纪上应该始终考虑,为了提高搜索效率,额外排序是否值得。如果排序一次后能够搜索多次,那么排序的开销不值一提。然而对于大型列表而言,只排序一次也会有昂贵的计算成本,因此从头进行顺序搜索可能是更好的选择

散列

散列函数

我们的目标是创建这样的一个散列函数:冲突数最少,计算方便,元素均匀分布与散列表中

实现映射抽象数据类型

字典是存储键-值对的数据类型,键用来查找关联的值,这个概念常常被称作映射

使用字典的一大优势是,给定一个键,能很快找到其关联的值。为了提供这种快速查找能力,需要能支持高效搜索的实现方案。虽然可以使用列表进行顺序搜索或二分搜索,但用散列表更好,这是因为散列搜索算法的时间复杂度可以达到O(1)

使用两个列表创建HashTable类,以此实现映射抽象抽象数据类型

class HashTable:
    def __init__(self):
        self.size = 11
        self.slots = [None]*self.size
        self.data = [None]*self.size
    
    def hashfunction(self, key, size):
        return key%size
    
    def rehash(self, oldhash, size):
        return (oldhash + 1)%size

    def put(self, key, data):
        hashvalue = self.hashfunction(key, len(self.slots))
        if self.slots[hashvalue] == None:
            self.slots[hashvalue] = key
            self.data[hashvalue] = data
        else:
            if self.slots[hashvalue] == key:
                self.data[hashvalue] = data # 替换
            else:
                nextslot = self.rehash(hashvalue, len(self.slots))
                while self.slots[nextslot] != None and self.slots[nextslot] != key:
                    nextslot = self.rehash(nextslot, len(self.slots))
                if self.slots[nextslot] == None:
                    self.slots[nextslot] = key
                    self.data[nextslot] = data
                else:
                    self.data[nextslot] = data # 替换

    def get(self, key):
        startslot = self.hashfunction(key, len(self.slots))

        data = None
        stop = False
        found = False
        position = startslot

        while self.slots[position] != None and not found and not stop:
            if self.slots[position] == key:
                found = True
                data = self.data[position]
            else:
                position = self.rehash(startslot, len(self.slots))
                if startslot == startslot:
                    stop = True
        return data
    
    def __getitem__(self,key):
        return self.get(key)

    def __setitem__(self, key, data):
        self.put(key, data)

排序

冒泡排序

选择排序

插入排序

希尔排序

归并排序

它是递归算法,每次将一个列表一分为二。
如果列表为空或只有一个元素,那么从定义上来说它就是有序的。
如果列表不止一个元素,就将列表一分为二,并对两部分都递归调用归并排序。
当两部分都有序后,就进行归并这一基本操作。归并是指将两个较小的有序列表归并为一个有序列表的过程。

以下代码中,函数以处理基本情况开始。如果列表的长度小于或等于1,说明它已经是有序列表,因此不需要做额外的处理,如果长度大于1,则通过Python的切片操作得到左半部分和右半部分。

第二部分部分实现了对左右两个子列表进行排序合并功能(其实就是按顺序比较大小填充数据),这里注意左右两个子列表都是已经排序过的列表,代码如下

def SecondPart(alist):
    mid = len(alist) // 2
    lefthalf = alist[:mid]
    righthalf = alist[mid:]

    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

check([1,5,2,3,4])

以下是整体函数实现:

def mergeSort(alist):
    print("Splitting", alist)
    if len(alist) > 1:
        mid = len(alist) // 2
        lefthalf = alist[:mid]
        righthalf = alist[mid:]

        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)
mergeSort([1,3,2,4,7])
Splitting [1, 3, 2, 4, 7]
Splitting [1, 3]
Splitting [1]
Merging [1]
Splitting [3]
Merging [3]
Merging [1, 3]
Splitting [2, 4, 7]
Splitting [2]
Merging [2]
Splitting [4, 7]
Splitting [4]
Merging [4]
Splitting [7]
Merging [7]
Merging [4, 7]
Merging [2, 4, 7]
Merging [1, 2, 3, 4, 7]

快速排序

快速排序函数quickSort调用了递归函数quickSortHelper。quickSortHelper首先处理和归并排序相同的基本情况。如果列表的长度小于或等于1,说明它已经是有序列表;如果长度大于1,则进行划分操作并递归地排序。

def quickSort(alist):
    quickSortHelper(alist, 0, len(alist)-1)

def quickSortHelper(alist, first, last):
    if first < last:
        splitpoint = partition(alist, first, last)

        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 alist[rightmark] >= pivotvalue and rightmark >= leftmark:
            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

猜你喜欢

转载自blog.csdn.net/Winds_Up/article/details/113243792