【Python】顺序/二分查找,冒泡/鸡尾酒排序

目录

一、顺序查找

代码实现

时间复杂度

 二、二分查找(Binary Search)

基本思路

示例:在这个列表中查找 第四个元素 25。

代码实现(非递归)

         递归实现:

      代码如下

 时间复杂度: O(log2n)

三、冒泡排序  (Bubble Sort)

1、基本思路:

2、代码实现(1.0)

3、代码实现(2.0)

4、代码实现(3.0)

四、鸡尾酒排序(Cocktail Sort/Shaker Sort)

1.基本思路

2.代码实现;

3.评价:


一、顺序查找

代码实现

arr = [12,53,25,66,52,1,7,5,8,3.14,85]
n = int(input("请输入要查找的数字哈"))
ok = False # 判断是否找到
for each in arr:
    if each == n:
        ok = True
        break # 找到了就退出循环
if ok:
    print("找到了!")
else:
    print("没找到。")

eg:输入 85 输出 "找到了!"

时间复杂度:

其时间复杂度是O(n)

如果一个序列中数据元素的个数为n,且每个元素被查找的概率是均等的(1/n),在查找成功的情况下,第1、2、3、…、n元素的比较次数分别为1、2、3、…、n,因此,查找成功的情况下查找一个元素的平均比较次数是1(1/n)+2(1/n)+...+n(1/n)=(n+1)/2,即平均需要比较的次数是表长的一半。


 二、二分查找(Binary Search)

假如要在一个有序序列  li  中查找某个元素item,则可以让item首先和  li  的中间元素比较

基本思路:

• 如果相等,则成功;
• 如果小于中间元素,则在左半区间查找;
• 如果大于等于中间元素,则在右边半区间查找。

示例:在这个列表中查找 第四个元素 25。

L:左位置

H:右位置

Middle:中间位置


 代码实现

def binarySearch(li, v):
    L = 0 # 区间左端点
    H = len(li)-1
    OK = False
    while L<H:  # 区间(L,H)存在
        Middle = (L+H)//2
        if li[Middle] == v:
            return "你所查找的元素在第{}个".format(Middle+1)
        else:
            if v < li[Middle]: # 在左区间找
                H = Middle-1
            else: # 在右区间找
                L=Middle + 1
    return "没找到"

ali = [5,7,12,25,34,37,43,46,58,80,82,105]
print(binarySearch(ali, 25))
print(binarySearch(ali, 520))

输出:

递归实现:

可分解为三个子问题:

(1)和中间的元素的直接比较问题;

(2)左区间上的查找问题;

(3)右区间上的查找问题。

代码如下

# 二分法递归实现
def binarySearch(li,v):
    if len(li) == 0:
        return -1
    else:
        Middle = len(li)//2
        if li[Middle] == v:
            return Middle
        else:
            if v< li[Middle]: # 左区间
                return binarySearch(li[:Middle],v)
            else: # 右区间
                return binarySearch(li[Middle+1:],v)

def pr(l,v):
    index = binarySearch(l,v)
    if index !=-1:
        print("你所查找的数字在第{}个元素".format(index+1))
    else:
        print("没找到这个数字!")

test = [5,7,12,25,34,37,44,55,58,80,82,105,52]
pr(test,25)
pr(test,520)

输出如下

你所查找的数字在第4个元素
没找到这个数字!

 时间复杂度: O(log2n)

二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x.

时间复杂度即是while循环的次数。

总共有n个元素,

渐渐跟下去就是n,n/2,n/4,....n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数

由于你n/2^k取整后>=1

即令n/2^k=1

可得k=log2n,(是以2为底,n的对数)

所以时间复杂度可以表示O(h)=O(log2n)

三、冒泡排序  (Bubble Sort)

1、基本思路:

冒泡排序的思想是对相邻元素比较大小,如果逆序就交换它们。

对于n个元素的序列,需要进行n-1趟冒泡。

2、代码实现(1.0)

li = [49,38,27,97,76,13,27,49]
index = 1
for i in range(len(li)-1,0,-1): # 外循环 次数n-1
    for j in range(i):
        if li[j] > li[j+1]:
            li[j],li[j+1] = li[j+1],li[j] # 假如前面的大于后面的元素,则交换
    print("第{1}轮排序:{0}".format(li,index))
    index +=1
print("排序完成后:{}".format(li))

输出结果:

可以发现:其实在第五轮就已经排好序了,可是还是进行了后面的排序

那么有没有改进方法?

3、代码实现(2.0)

基本思路:在上面情况下,如果能判断出数列已经有序,并做出标记,那么剩下的几轮排序就不必执行了。

# 2.0
def bubble_sort(array):
    index = 1
    for i in range(len(array)-1):
        # 有序标记
        is_sorted = True
        for j in range(len(array)-i-1):   # 第i轮排序进行n-i-1次交换
            if array[j] > array[j+1]:
                array[j],array[j+1] = array[j+1],array[j]
                # 有元素交换,所有不是有序的
                is_sorted = False
        if is_sorted:
            break
        else: # 进行了交换
            print("第{1}轮排序:{0}".format(array,index))
            index += 1

li = [49,38,27,97,76,13,27,49]
bubble_sort(li)
print("最后排序的结果为\n{}".format(li))

输出结果为:

4、代码实现(3.0)

基本思路:假如有一这样的序列:

这个数列的特点是,前半部分的元素无序,后半部分的元素按升序排列,并且后半部分元素中的最小值也大于前半部分元素的最大值。

按2.0来看:

第一轮:将执行n-i-1即为7轮

3和4,不变

4和2,交换

4和1,交换

4和5,不变

5和6,不变

6和7,不变

7和8,不变

那么问题在哪:在后半部分已经是有序的了,可是每一轮还是白白地比较了许多次。

解决:这个问题的关键点在于对数列有序区的界定。

我们可以在每一轮排序后,记录下最后一次元素交换的位置,该位置即为无序数列的边界,再往后就是有序区了。

代码如下

# 3.0
def bubble_sort(array):
    index = 1
    # 记录最后一次交换位置
    lase_exchange_index = 0
    # 无序数列的边界,比较只用比到这里
    sort_border = len(li)-1
    for i in range(len(array)-1):
        # 有序标记
        is_sorted = True
        for j in range(sort_border):
            if array[j] > array[j+1]:
                array[j],array[j+1] = array[j+1],array[j]
                # 有元素交换,所有不是有序的
                is_sorted = False
                # 更新无序边界
                lase_exchange_index = j
        sort_border = lase_exchange_index
        if is_sorted:
            break
        else: # 进行了交换
            print("第{1}轮排序:{0}".format(array,index))
            index += 1

li = [3,4,2,1,5,6,7,8]
bubble_sort(li)
print("最后排序的结果为\n{}".format(li))

输出结果:

四、鸡尾酒排序(Cocktail Sort/Shaker Sort)

1.基本思路

鸡尾酒排序是基于冒泡排序的一种升级排序法。

鸡尾酒排序的元素比较和交换过程是双向的

奇数轮从左往右,偶数轮从右往左

eg:由8个数字组成一个无序数列{2,3,4,5,6,7,8,1},希望对其进行从小到大的排序。

按照冒泡排序看,只有1位置不对,却还要进行七轮排序:

代码实现;

import time
def cock_tail_sort(li):
    for i in range(len(li)//2):
        # 有序标记
        is_sorted = True
        # 奇数轮,从左往右比较和交换
        for j in range(i,len(li)-i-1):   # 第i轮排序进行n-i-1次交换
            if li[j] > li[j+1]:
                li[j],li[j+1] = li[j+1],li[j]
                # 有元素交换,所有不是有序的
                is_sorted = False
        if is_sorted:
            break
        # 偶数轮:从右往左
        is_sorted = True
        for j in range(len(li)-i-1,i,-1):   # 第i轮排序进行n-i-1次交换
            if li[j] < li[j-1]:
                li[j],li[j-1] = li[j-1],li[j]
                # 有元素交换,所有不是有序的
                is_sorted = False
        if is_sorted:
            break

li = list([3,4,14,1,5,6,7,8,1,-1,0,9,11])
li1 = [2,3,4,5,6,7,8,1]
cock_tail_sort(li)
print(li)
a = time.time()
cock_tail_sort(li1)
b = time.time()
print("时间为:{}".format(b-a))
print(li1)

 输出:

评价:

优点是能够在特定条件下,减少排序的回合数;而缺点也很明显,就是代码量几乎增加了1倍。它能发挥出优势的场景,是大部分元素已经有序的情况

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值