数据结构与算法之列表查找与列表排序

一、查找

  • 查找:在一些数据元素中,通过一定的方法找出与指定关键字相同的数据元素的过程;
  • 列表查找(线性表查找):从列表中查找元素
    1)输入:列表、待查找元素;
    2)输出:元素下标(未找到元素时一般返回None或-1)
  • 内置列表查找函数:index()

1.1 顺序查找(Linear Search)

  • 顺序查找:叫线性查找,从列表的第一个元素开始,顺序进行搜索,直到找到元素或搜索到列表最后一个元素为止。
def linear_search(data_set, val):
	for i in range(len(data_set)):
		if data_set[i]==val:
			return i
	return 
#实践复杂度为O(n)

1.2 二分查找(Binary Search)

  • 二分查找:又叫折半查找,从有序列表的初始候选区li[0:n]开始,通过对待查找的值与候选中间值的比较,可以使得候选区域减少一半;
#写一个装饰器,计算时间
import time
def cal_time(func):
    def wrapper(*args,**kwargs):
        t1=time.time()
        result=func(*args,**kwargs)
        t2=time.time()
        print("%s running time: %s secs."%(func.__name__, t2-t1))
        return result
    return wrapper
@cal_time
def binary_search(data_set,val):
    left,right=0,len(data_set)-1
    while left<=right: #候选区域
        mid=(left+right)//2
        if data_set[mid]>val: #待查找值在候选区域左侧
            right=mid-1
        elif data_set[mid]<val: #待查找值在候选区域右侧
            left=mid+1
        elif data_set[mid]==val:
            return mid
        else:
            return None 
#实践复杂度O(logn)        
binary_search([i for i in range(10)],3)
#结果:
binary_search running time: 0.0 secs.
3

二、排序

  • 排序:将一组无序的记录序列调整为有序的记录序列;
  • 列表排序:将无序列表变为有序列表;
    1)输入:列表
    2)输出:有序列表
  • 升序与降序;
  • 内置排序函数:sort();
序号排序算法类型
1冒泡排序低级方法
2选择排序低级方法
3插入排序低级方法
4快速排序高级方法
5堆排序高级方法
6归并排序高级方法
7希尔排序其他方法
8计数排序其他方法
9基数排序其他方法

2.1 冒泡排序(Bubble Sort)

  • 列表每相邻的2个数,如果前面比后面大,则交换这2个数;一次排序完成后,则无序区域减少一个数,有序区域增加一个数;
def bubble_sort(li):
    for i in range(len(li)-1): #排序n-1轮
        for j in range(len(li)-i-1): #每一轮排序完成会减少一个未排序元素
            if li[j]>li[j+1]:
                li[j],li[j+1]=li[j+1],li[j]
        print(li)
li=[8,4,7,3,1,5,2,9,6,0]
bubble_sort(li)
li
#时间复杂度$O(n^2)$
#结果
"""
[4, 7, 3, 1, 5, 2, 8, 6, 0, 9]
[4, 3, 1, 5, 2, 7, 6, 0, 8, 9]
[3, 1, 4, 2, 5, 6, 0, 7, 8, 9]
[1, 3, 2, 4, 5, 0, 6, 7, 8, 9]
[1, 2, 3, 4, 0, 5, 6, 7, 8, 9]
[1, 2, 3, 0, 4, 5, 6, 7, 8, 9]
[1, 2, 0, 3, 4, 5, 6, 7, 8, 9]
[1, 0, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
  • 冒泡排序优化:
  • 如果冒泡排序中的一轮排序中没有发生交换,则说明列表已经有序,可以直接结束算法
def bubble_sort(li):
    for i in range(len(li)-1): #排序n-1轮
        exchange=False
        for j in range(len(li)-i-1): #每一轮排序完成会减少一个未排序元素,即第i轮减少i个未排序元素
            if li[j]>li[j+1]:
                li[j],li[j+1]=li[j+1],li[j]
                exchange=True
        if not exchange: #如果为False,即不需要排序,直接跳出算法
            return
        print(li)
li=[8,4,7,3,1,5,2,9,6,0]
bubble_sort(li)
li
#时间复杂度$O(n^2)$
#结果
"""
[4, 7, 3, 1, 5, 2, 8, 6, 0, 9]
[4, 3, 1, 5, 2, 7, 6, 0, 8, 9]
[3, 1, 4, 2, 5, 6, 0, 7, 8, 9]
[1, 3, 2, 4, 5, 0, 6, 7, 8, 9]
[1, 2, 3, 4, 0, 5, 6, 7, 8, 9]
[1, 2, 3, 0, 4, 5, 6, 7, 8, 9]
[1, 2, 0, 3, 4, 5, 6, 7, 8, 9]
[1, 0, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""

2.2 选择排序(Select Sort)

  • 列表中依次找到最小元素放置到列表的前端;
li=[3,4,2,1,5,7,8,9,6]
def select_sort_simple(li):
    li_new=[]
    for i in range(len(li)):
        min_val=min(li)
        li_new.append(min_val)
        li.remove(min_val)
    return li_new

print(select_sort_simple(li))
#结果
[1, 2, 3, 4, 5, 6, 7, 8, 9]
#上一个方法需要新建一个列表存储,现在实现原地排序
li=[3,4,2,1,5,7,8,9,6]
def select_sort(li):
    for i in range(len(li)-1):
        min_loc=i
        for j in range(i+1,len(li)):
            if li[j]<li[min_loc]:
                min_loc=j
        li[i],li[min_loc]=li[min_loc],li[i]
        print(li)
select_sort(li)
print('\n',li)
#结果
[1, 4, 2, 3, 5, 7, 8, 9, 6]
[1, 2, 4, 3, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 6, 8, 9, 7]
[1, 2, 3, 4, 5, 6, 7, 9, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

[1, 2, 3, 4, 5, 6, 7, 8, 9]

2.3 插入排序

  • 初始时有一个数字(有序),接下来每次在有序的列表中插入数字,使列表仍有序;(通俗的意思就是摸到的牌往已有的有序的牌里插)
li=[3,4,2,1,5,7,8,9,6]
def insert_sort(li):
    for i in range(1,len(li)):#i表示摸到的牌的下标
        tmp=li[i]
        j=i-1 #j表示手里牌的下标
        while j>=0 and li[j]>tmp:#手里有牌并且手里的牌比摸到的牌大
            li[j+1]=li[j]
            j-=1
        li[j+1]=tmp
        print(li)
#复杂度O(n^2)
insert_sort(li)
li

#结果
[3, 4, 2, 1, 5, 7, 8, 9, 6]
[2, 3, 4, 1, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 7, 8, 9, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

[1, 2, 3, 4, 5, 6, 7, 8, 9]

2.4 快速排序

在这里插入图片描述

def partition(li,left,right):
    tmp=li[left]
    while left<right:
        while left<right and li[right]>=tmp: #从右侧找出比tmp小的数
            right-=1 #左移
        li[left]=li[right] #把右侧的数写到左边空位上
        while left<right and li[left]<=tmp: #从左侧找出比tmp大的数
            left+=1
        li[right]=li[left] #把左侧的数写到右边空位上
    li[left]=tmp #tmp归位
    return left
def quick_sort(li,left,right):
    if left<=right:
        mid=partition(li,left,right)
        quick_sort(li,left,mid-1)
        quick_sort(li,mid+1,right)
li=[3,4,2,1,5,7,8,9,6]
quick_sort(li,0,len(li)-1)
print(li)
#结果
[1, 2, 3, 4, 5, 6, 7, 8, 9]
  • 时间复杂度:如下图所示,对于长度为16的列表,每次按照left和right进行左右分组,理想情况下,分组后的元素个数减半,即需要分4层( 4 = log ⁡ 2 16 4=\log_2 16 4=log216),此时的复杂度为 l o g n logn logn,每次分组后都需要遍历所有元素,即时间复杂度为 n n n,综上时间复杂度为: O ( n l o g n ) O(nlogn) O(nlogn)
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值