Python 学习 第三册 第10章 一些简单的算法

---用教授的方式学习。

目录

10.1 搜索算法

10.1.1 线性搜索与间接引用元素

10.1.2 二分查找和利用假设

10.2 排序算法

10.2.1 归并排序

10.2.2 将函数用作参数

10.3 散列表


10.1 搜索算法

本节会研究两种搜索列表的算法,每种方法都满足以下规范:

def search(L, e):
    """假设L是列表
    如果e是L中的元素,则返回True,否则返回False"""

10.1.1 线性搜索与间接引用元素

Python使用以下算法确定列表中是否有某个元素:

for i in range(len(L)): 
    if L[i] == e: 
       return True 
return False

10.1.2 二分查找和利用假设

有序列表的线性搜索

def search(L, e): 
    """假设L是列表,其中元素按升序排列。
        ascending order. 
    如果e是L中的元素,则返回True,否则返回False""" 
   for i in range(len(L)): 
      if L[i] == e: 
         return True 
      if L[i] > e: 
         return False 
    return False

这种算法可以缩短平均运行时间,但不会改变最差情形下的算法复杂度,因为在最差情形下还是需要检查L中的每个元素。

二分查找的思路非常简单:

(1) 选择一个可以将列表L大致一分为二的索引i;

(2) 检查是否有L[i] == e;

(3) 如果不是,检查L[i]大于还是小于e;

(4) 根据上一步的结果,确定在L的左半部分还是右半部分搜索e。

给定算法结构之后,很显然,实现二分查找的最简单直接的方式就是使用递归,如下所示。

递归二分查找

def search(L, e): 
    """假设L是列表,其中元素按升序排列。
       ascending order. 
    如果e是L中的元素,则返回True,否则返回False""" 
    def bSearch(L, e, low, high): 
       #Decrements high – low 
       if high == low: 
          return L[low] == e 
    mid = (low + high)//2 
    if L[mid] == e: 
       return True 
    elif L[mid] > e: 
       if low == mid: #nothing left to search 
          return False 
       else: 
          return bSearch(L, e, low, mid - 1) 
       else: 
          return bSearch(L, e, mid + 1, high) 
    if len(L) == 0: 
       return False 
    else: 
       return bSearch(L, e, 0, len(L) - 1)

10.2 排序算法

从一个简单但是低效的算法开始:选择排序。

def selSort(L): 
    """假设L是列表,其中的元素可以用>进行比较。
       compared using >. 
      对L进行升序排列""" 
    suffixStart = 0 
    while suffixStart != len(L): 
       #检查后缀集合中的每个元素
       for i in range(suffixStart, len(L)): 
          if L[i] < L[suffixStart]: 
             #交换元素位置
             L[suffixStart], L[i] = L[i], L[suffixStart] 
       suffixStart += 1

10.2.1 归并排序

def merge(left, right, compare): 
    """假设left和right是两个有序列表,compare定义了一种元素排序规则。
       返回一个新的有序列表(按照compare定义的顺序),其中包含与
        (left+right)相同的元素。""" 
    result = [] 
    i,j = 0, 0 
    while i < len(left) and j < len(right): 
       if compare(left[i], right[j]): 
          result.append(left[i]) 
          i += 1 
       else: 
          result.append(right[j]) 
          j += 1 
    while (i < len(left)): 
        result.append(left[i]) 
        i += 1 
    while (j < len(right)): 
        result.append(right[j]) 
        j += 1 
     return result 
def mergeSort(L, compare = lambda x, y: x < y): 
    """假设L是列表,compare定义了L中元素的排序规则
       on elements of L 
     返回一个新的具有L中相同元素的有序列表。""" 
    if len(L) < 2: 
       return L[:] 
   else: 
       middle = len(L)//2 
       left = mergeSort(L[:middle], compare) 
       right = mergeSort(L[middle:], compare) 
       return merge(left, right, compare)

10.2.2 将函数用作参数

def lastNameFirstName(name1, name2): 
    arg1 = name1.split(' ') 
    arg2 = name2.split(' ') 
    if arg1[1] != arg2[1]: 
       return arg1[1] < arg2[1] 
    else: #姓相同,则按照名排序
       return arg1[0] < arg2[0] 
def firstNameLastName(name1, name2): 
    arg1 = name1.split(' ') 
    arg2 = name2.split(' ') 
    if arg1[0] != arg2[0]: 
       return arg1[0] < arg2[0] 
    else: #名相同,则按照姓排序
       return arg1[1] < arg2[1] 
L = ['Tom Brady', 'Eric Grimson', 'Gisele Bundchen'] 
newL = mergeSort(L, lastNameFirstName) 
print('Sorted by last name =', newL) 
newL = mergeSort(L, firstNameLastName) 
print('Sorted by first name =', newL)

运行图10-6中的代码,会输出以下结果:

Sorted by last name = ['Tom Brady', 'Gisele Bundchen', 'Eric Grimson'] 

Sorted by first name = ['Eric Grimson', 'Gisele Bundchen', 'Tom Brady'] 

10.3 散列表

如果字典中只包含10 000(104 )个人员的条目,就会浪费大量空间。

为了解决这个问题,我们引入散列函数。它会将一个大规模的输入空间(如所有自然数)映射为一个小规模的输出空间(如0~5000的自然数)。所以,可以使用散列函数将数量巨大的键转换为数量较少的整数索引。

我们使用一个简单的散列函数

class intDict(object): 
     """键为整数的字典""" 
     def __init__(self, numBuckets): 
         """创建一个空字典""" 
         self.buckets = [] 
         self.numBuckets = numBuckets 
         for i in range(numBuckets): 
            self.buckets.append([]) 
    def addEntry(self, key, dictVal): 
        """假设key是整数。添加一个字典条目。""" 
        hashBucket = self.buckets[key%self.numBuckets] 
        for i in range(len(hashBucket)): 
           if hashBucket[i][0] == key: 
              hashBucket[i] = (key, dictVal) 
              return 
        hashBucket.append((key, dictVal)) 
    def getValue(self, key): 
       """假设key是整数。
           返回键为key的字典值""" 
        hashBucket = self.buckets[key%self.numBuckets] 
        for e in hashBucket: 
           if e[0] == key: 
           return e[1] 
        return None 
    def __str__(self): 
       result = '{' 
       for b in self.buckets: 
          for e in b: 
              result = result + str(e[0]) + ':' + str(e[1]) + ',' 
       return result[:-1] + '}' #result[:-1] omits the last comma

上述实现的基本思想是通过散列桶列表表示intDict类的实例,每个散列桶都是一个元组形

式的键/值对列表。通过这种每个桶都是一个列表的方式,我们可以将散列到同一个桶的所有值

都保存在列表里,从而解决碰撞问题。

-----end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_38135241

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值