平均查找长度ASL(Average Search Length)
- 定义:为确定元素在列表中的位置,需要和给定值进行比较的关键字个数的期望值,称之为查找算法成功时的平均查找长度.
ASL = P 1 C 1 + P 2 C 2 + ⋯ + P n C n = ∑ i = 1 n P i C i \text{ASL} = P_1C_1 + P_2C_2 + \cdots + P_nC_n = \sum_{i=1}^{n} P_iC_i ASL=P1C1+P2C2+⋯+PnCn=i=1∑nPiCi
其中,P为第i个元素的概率,C为找到列表中第i个元素时,已经进行过的关键字比较次数.
顺序表查找法
- 简单粗暴的查找方法,从头开始扫描,直到查找到或扫描结束.
# 1.顺序表查找法
class SeqList:
def __init__(self, items):
# 顺序表
self.items = items
def seqSearch(self, key):
# 顺序表查找法
index = -1
for i in range(len(self.items)):
if self.items[i] == key:
index = i + 1
return index
if __name__ == '__main__':
print('PyCharm')
# 1.顺序表调试
nums = [15, 22, 83, 54, 6, 65, 96, 72, 38, 46]
sqlist = SeqList(nums)
print(sqlist.seqSearch(72))
- 运行结果
- 顺序表查找法的ASL:
- 假设长度为n,
- 假设最后一个元素为查找目标,需比较n次,
- 倒数第二个元素为查找目标,需比较n-1次,
- 依此类推,
- 第一个元素为查找目标,需比较1次.
- 设每个元素为目标元素的概率一致,则概率值为1/n.
ASL = 1 × 1 n + 2 × 1 n + ⋯ + n × 1 n = ( 1 + 2 + ⋯ + n ) × 1 n = n + 1 2 \text{ASL} = 1 \times \frac{1}{n} + 2 \times \frac{1}{n} + \cdots + n \times \frac{1}{n} = \left(1 + 2 + \cdots + n\right) \times \frac{1}{n} = \frac{n+1}{2} ASL=1×n1+2×n1+⋯+n×n1=(1+2+⋯+n)×n1=2n+1
折半查找法
-
前提条件:
- 1.采用顺序存储结构
- 2.必须按关键字大小有序排列
-
基本思想:
-
关键字先与中间元素比较:
- 若相等,则查找成功
- 若关键字大,则与后一子表的中间元素比较大小,
- 若关键字小,则与前一子表的中间元素比较大小,
-
重复查找,直到查找成功,或比较结束,未查找到.
-
-
查找失败情况
-
查找成功情况
# 2.折半查找法
class SeqList:
def __init__(self, items):
# 有序的顺序表
self.items = items
def binarySearch(self, key):
# 折半查找法
index = -1
low = 0
high = len(self.items) - 1
while high >= low:
mid = (low + high) // 2
if self.items[mid] == key:
index = mid + 1
break
elif self.items[mid] > key:
high = mid - 1
else:
low = mid + 1
return index
if __name__ == '__main__':
print('PyCharm')
# 2.折半查找调试
nums = [6, 12, 15, 18, 22, 25, 28, 35, 46, 58, 60]
sqlist = SeqList(nums)
num = 12
index = sqlist.binarySearch(num)
if index == -1:
print(f"{num}在{nums}中未找到")
else:
print(f"{num}在{nums}中的位置为{index}")
num = 50
index = sqlist.binarySearch(num)
if index == -1:
print(f"{num}在{nums}中未找到")
else:
print(f"{num}在{nums}中的位置为{index}")
- 运行结果
- 折半查找法的ASL:
ASL = ∑ i = 1 n P i C i = 1 n ∑ j = 1 n j × 2 j − 1 = n + 1 n log 2 ( n + 1 ) − 1 ≈ log 2 ( n + 1 ) − 1 \text{ASL} = \sum_{i=1}^{n} P_i C_i = \frac{1}{n} \sum_{j=1}^{n} j \times 2^{j-1} = \frac{n+1}{n} \log_2(n+1) - 1 \approx \log_2(n+1) - 1 ASL=i=1∑nPiCi=n1j=1∑nj×2j−1=nn+1log2(n+1)−1≈log2(n+1)−1
-
优点:
- 比较次数少,查找速度快,平均性能好.
-
缺点:
- 要求待查表为有序表且插入/删除困难.
索引顺序查找法
-
分块查找法,介于顺序查找法和折半查找法之间的一种查找方法.
-
关键:建立索引表
-
前提条件:要求将列表组织称索引顺序结构
-
索引表示意图
# 3.索引顺序查找表
class Block:
def __init__(self, key, low, high):
self.key = key
self.low = low
self.high = high + 1
class SeqList:
def __init__(self, blocks, items):
self.blocks = blocks
self.items = items
def seqSearch(self, cur, key):
# 索引顺序查找
index = -1
low = self.blocks[cur].low
high = self.blocks[cur].high
for i in range(low, high):
if self.items[i] == key:
index = i + 1
return index
def blockSearch(self, key):
low = 0
high = len(self.blocks) - 1
mid = 0
while low <= high:
mid = (low+high)//2
if mid == 0 or mid == len(self.blocks) -1:
break
elif key < self.blocks[mid].key and key > self.blocks[mid-1].key:
break
elif key > self.blocks[mid].key:
low = mid + 1
elif key < self.blocks[mid].key:
high = mid - 1
index = self.seqSearch(mid, key)
return index
if __name__ == '__main__':
print('PyCharm')
# 3.索引表查找调试
nums = [18, 14, 12, 25, 8, 28, 32, 45, 36, 58, 60, 88, 71]
blocks = [Block(25, 0, 4),Block(58, 5, 9),Block(88, 10, 12)]
sqlist = SeqList(blocks, nums)
num = 36
print(f"{num}在{nums}中的位置为{sqlist.blockSearch(num)}")
- 运行结果
-
36查找的过程:
- 将36与索引表中最大关键字25与58比较,介于他们之间,则表明36在第二块索引表中.
- 从第二块索引表的起始地址开始扫描,最后找到36所在位置.
-
索引表查找的ASL:
- 其中,n为数组数量,s是每块含有元素的个数.
ASL = 1 2 ( n s + s ) + 1 \text{ASL} = \frac{1}{2} \left( \frac{n}{s} + s \right) + 1 ASL=21(sn+s)+1