排序和搜索

搜索的算法过程就是在一些项的集合中找到一个特定的项,我们感兴趣的是这些算法的工作原理以及他们相互比较的优劣

顺序搜索

从列表的第一项开始,直到发现正在寻找的数据项或者遍历所有数据项
无序表顺序搜索的比对
无序表顺序搜索的比对
在这里插入图片描述

二分法搜索

二分法必须用于有序的列表中,二分搜索的复杂度是O(log(n))

def binarySearch(alist,item):
    """二分法搜索"""
    first = 0
    last = len(alist)-1
    found = False
    while first<=last and not found:
        midpoint = (first+last)//2
        if alist[midpoint] == item:
            found = True
        else:
            if item<alist[midpoint]:
                last = midpoint-1
            elif item>alist[midpoint]:
                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)

散列

散列表是一种数据的集合,其中的每个数据都通过某种特定的方式进行存储以方面日后的查找。散列表的每一个位置叫做槽,能够存放一个数据项,并以从0开始递增的整数命名。
在这里插入图片描述
如果散列函数过于复杂,导致花费大量的时间去计算槽的名称,还不如进行简单的顺序搜索或者二分法搜索。

当两个数据散列到相同的槽,我们必须用一种系统化的方法将第二个数据放到散列表里。这个过程叫做冲突解决,是实现散列函数的重要部分

简单的方法就是从发生冲突的位置开始顺序向下开始寻找,直到我们遇到第一个空的槽。注意到
我们可能需要回到第一个槽(循环)来实现覆盖整个散列

class HashTable():
    def __init__(self):
        self.size = 11
        self.slots = [None]*self.size
        self.data = [None]*self.size
        
    def put(self,key,data):
        hashvalue = self.hashfunction(key,len(self.slots))
        
        #当对应的哈希值的槽为空时,分别将key和data分别插入到slots[]和data中
        if self.slots[hashvalue] == None:
            self.slots[hashvalue] = key
            self.data[hashvalue] = data
        else:
            #如果非空槽已包含key,则将以前的data替换为新的data
            if self.slots[hashvalue] == key:
                self.data[hashvalue] = data
            else:
                #使用rehash()函数重新计算hashvalue(nextslot),即下一个空槽的位置
                nextslot = self.rehash(hashvalue,len(self.slots))
                while self.slots[nextslot] != None and self.slots[nextslot] != key:
                    nextslot = self.rehash(nextslot,len(self.slots))
                
                #找到空槽,插入key和data
                if self.slots[nextslot] == None:
                    self.slots[nextslot] = key
                    self.data[nextslot] = data
                #或者找到包含key的非空槽,更新data
                else:
                    self.data[nextslot] = data
                  
    def hashfunction(self,key,size):
        """用于计算首次的hashvalue"""
        return key%size
    
    def rehash(self,oldhash,size):
        #用于解决冲突
        return (oldhash+1)%size
    
    def get(self,key):
        startslot = hashfunction(key,len(self.slots))
        data = None
        stop = False
        found = False
        position = startslot
        while not stop and not found and self.slots[position] != None:
            if self.slots[position] == key:
                found = True
                data = self.data[position]
            else:
                position = self.rehash(position,len(self.slots))
                if position == startslot:
                    stop =True
        return data
    def __getitem__(self,key):
        return self.get(key)
    def __setitem__(self, key, data):
        return self.put(key, data)

在分析散列表的使用情况时最重要的因素是负载因子。从概念上来看,如果较小,那么发生冲突的概率就较低,这意味着数据项有更大的可能填充在它们本该处于的位置上。如果较大,这意味着整个散列表接近于被填满,紧接着会造成越来越多的冲突。冲突的解决也会变得越来越困难,需要越来越多的比对操作来找到一个空槽。如果通过数据链方法解决冲突,逐渐增多的冲突预示着在每条链上会存储越来越多的数据项

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值