python3.8各大经典排序算法(复习)

目录

1、排序算法一览表

2、collections、heapq模块

2、冒泡排序

3、选择排序

4、插入排序

5、希尔排序

6、归并排序

7、快速排序

8、堆排序


1、排序算法一览表

算法平均时间复杂度最优时间复杂度最坏时间复杂度辅助空间稳定性
冒泡排序O(n^2)O(n)O(n^2)O(1)稳定
选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
插入排序O(n^2)O(n)O(n^2)O(1)稳定
希尔排序O(nlog2n)-O(n^2)O(n^1.3)O(n^2)O(1)不稳定
归并排序O(nlog2n)O(nlog2n)O(nlog2n)O(n)稳定
快速排序O(nlog2n)O(nlog2n)O(n^2)O(log2n)-O(n)不稳定
堆排序O(nlog2n)O(nlog2n)O(nlog2n)O(1)不稳定

2、collections、heapq模块

        2.1、collections模块

                常用的函数

deque()类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop),双端队列
Counter()字典的子类,提供了可哈希对象的计数功能
OrderedDict()字典的子类,保存了他们被添加的顺序

                deque用法:

(1)maxlen参数:默认为None,deque的长度为任意长度;设置maxlen=n,则长度为n,当deque满后,曾经的元素会从左边pop出去;

from collections import deque

dq = deque(maxlen=10)

for i in range(13):
    dq.append(i)

print(dq)  # deque([3, 4, 5, 6, 7, 8, 9, 10, 11, 12], maxlen=10)

 (2)append():末尾追加完整元素 / appendleft():队首追加完整元素

from collections import deque

dq = deque([1,2,3])

# append()
dq.append([3,4])
print(dq)  # deque([1, 2, 3, [3, 4]])

# appendleft()
dq.appendleft((5,4))
print(dq)  # deque([(5, 4), 1, 2, 3, [3, 4]])

(3)clear():清空deque所有的元素;

(4)count(x):统计x元素有多少个;

(5)extend():队尾追加元素 / extendleft():队首追加元素

from collections import deque

dq = deque([1,2,3])

# extend()
dq.extend([3,4])
print(dq)  # deque([1, 2, 3, 3, 4])

# extendleft()
dq.extendleft((5,4))
print(dq)  # deque([4, 5, 1, 2, 3, 3, 4])

(6)index(x, start, stop):在start-stop这个范围内,查询x的第一个出现的位置;

(7)insert(i, x):在位置i,插入x;但是如果被限制了maxlen,deque满后,插入会报错;

from collections import deque

dq = deque([1,2,3], maxlen=3)
dq.insert(1, 10)
print(dq)

"""
执行结果

Traceback (most recent call last):
  File "d:/python_算法/双端队列.py", line 5, in <module>
    dq.insert(1, 10)
IndexError: deque already at its maximum size
"""

(8)pop():弹出队尾的第一个元素  / popleft():弹出队首的第一个元素;如果没有元素的话,就都会引发一个IndexError

(9)remove(value):删除deque中的第一个value的元素,如果没有的话就引发ValueError;

(10)reverse():逆序;

(11)rotate(n=1):向右循环移动 n 步。 如果 n 是负数,就向左循环。

from collections import deque

dq = deque([1,2,3,4,5])
dq.rotate(2)
print(dq)  # deque([4, 5, 1, 2, 3])

dq.rotate(-3)
print(dq)  # deque([2, 3, 4, 5, 1])

如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft()) 。 

                Counter用法:

(1)基本用法:将内部字符串/标志好的单词,进行统计,返回类似dict的对象

from collections import Counter

test_str = "hellowordhellohadoop"
test_dic = {"red":2, "blue":3, "blake":1}

test1 = Counter(red=3, blue=2, hadoop=1)  # Counter({'red': 3, 'blue': 2, 'hadoop': 1})
test2 = Counter(test_str)  # Counter({'o': 5, 'l': 4, 'h': 3, 'e': 2, 'd': 2, 'w': 1, 'r': 1, 'a': 1, 'p': 1})
test3 = Counter(test_dic)  # Counter({'blue': 3, 'red': 2, 'blake': 1})
 

(2)elements():返回一个迭代器,其中每个元素将重复出现计数值所指定次。 元素会按首次出现的顺序返回。 如果一个元素的计数值小于1,elements()会自动忽略。

from collections import Counter

test1 = Counter(red=3, blue=2, hadoop=1, spark=0, hive=-2)   

print(sorted(test1.elements()))  # ['blue', 'blue', 'hadoop', 'red', 'red', 'red']

(3)most_common(n):返回最多的n个元素;返回一个列表,其中包含 n 个最常见的元素及出现次数,按常见程度由高到低排序。 如果 n 被省略或为None,将返回计数器中的 所有 元素。计数值相等的元素按首次出现的顺序排序。

from collections import Counter

test1 = Counter(red=3, blue=2, hadoop=1, spark=10, hive=2)  
print(test1.most_common(3))  # [('spark', 10), ('red', 3), ('blue', 2)]

(4)subtract():求两个Counter的差;

from collections import Counter

test1 = Counter(red=3, blue=2, hadoop=1, spark=10, hive=-2)  
test2 = Counter(red=4, blue=1, hadoop=1, spark=-2)
test1.subtract(test2)  # Counter({'spark': 12, 'blue': 1, 'hadoop': 0, 'red': -1, 'hive': -2})

print(test1)

(5)update():求两个Counter的和

from collections import Counter

test1 = Counter(red=3, blue=2, hadoop=1, spark=10, hive=-2)  
test2 = Counter(red=4, blue=1, hadoop=1, spark=-2)
test1.update(test2)  # Counter({'spark': 8, 'red': 7, 'blue': 3, 'hadoop': 2, 'hive': -2})

print(test1)

        OrderedDict用法:

(1)基础用法:

from collections import OrderedDict

test_str = "ababsq"
a = OrderedDict.fromkeys(test_str)  # OrderedDict([('a', None), ('b', None), ('s', None), ('q', None)])

print(a)

(2)popitem(last=True):有序字典的popitem()方法移除并返回一个 (key, value) 键值对。 如果 last 值为真,后进先出的顺序返回键值对,否则就按先进先出的顺序返回键值对。

from collections import OrderedDict

test_str = "ababsq"

# 设置last为默认,true
a = OrderedDict.fromkeys(test_str)  # OrderedDict([('a', None), ('b', None), ('s', None), ('q', None)])
a.popitem(last=True)
print(a)  # OrderedDict([('a', None), ('b', None), ('s', None)])

# 设置last为false
b = OrderedDict.fromkeys(test_str)  # OrderedDict([('a', None), ('b', None), ('s', None), ('q', None)])
b.popitem(last=False)
print(b)  # OrderedDict([('b', None), ('s', None), ('q', None)])

(3)move_to_end(key, last=True):将现有 key 移动到有序字典的任一端。 如果 last 为真值(默认)则将元素移至末尾;如果 last 为假值则将元素移至开头。如果 key 不存在则会触发KeyError。

from collections import OrderedDict

test_str = "ababsq"

# 设置last为默认,true
a = OrderedDict.fromkeys(test_str)  # OrderedDict([('a', None), ('b', None), ('s', None), ('q', None)])
a.move_to_end('b', last=False)
print(a)  # OrderedDict([('b', None), ('a', None), ('s', None), ('q', None)])

a.move_to_end('a', last=True)
print(a)  # OrderedDict([('b', None), ('s', None), ('q', None), ('a', None)])

        2.2、heapq模块:内置库模块,生成最小堆

                基本用法:

(1)heapq.heapify(x):将list x 转换成堆,原地,线性时间内;

import heapq

ls = [6,1,4,5,3,2]

heapq.heapify(ls)
print(ls)  # [1, 3, 2, 5, 6, 4]

(2)heapq.heappush(heap, item):将 item 的值加入 heap 中,保持堆的不变性 ;也可以用该方法生成堆

import heapq

ls = []

# 加入数据
for i in range(10,1,-1):
    heapq.heappush(ls, i)

print(ls)  # [2, 3, 5, 4, 8, 9, 6, 10, 7]

(3)heapq.heappop(heap):弹出并返回 heap 的最小的元素,保持堆的不变性。如果堆为空,抛出IndexError。使用heap[0],可以访问最小值,而不弹出;

import heapq

ls = []

# 加入数据
for i in range(10,1,-1):
    heapq.heappush(ls, i)

print(ls) # [2, 3, 5, 4, 8, 9, 6, 10, 7]
print(heapq.heappop(ls)) # 2
print(ls) # [3, 4, 5, 7, 8, 9, 6, 10]

(4)heapq.heappushpop(heap, item) :将 item 放入堆中,然后弹出并返回 heap 的最小元素。该组合操作比先调用heappush()再调用heappop()更优;

(5)heapq.heapreplace(heap, item):弹出并返回 heap 中最小的一项,同时推入新的 item。 堆的大小不变。 如果堆为空则引发IndexError;这个步骤比heappop()再调用heappush()更高效;

(6)heapq.nlargest(n, iterable, key=None):从 iterable 所定义的数据集中返回前 n 个最大元素组成的列表。 

(7)heapq.nsmallest(n, iterable, key=None):从 iterable 所定义的数据集中返回前 n 个最小元素组成的列表。

3、冒泡排序

说明:

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数,也就是有序部分;
  • 针对所有的元素重复以上的步骤,除了有序部分;
  • 重复步骤1~3,直到排序完成。
import random

ls = list(range(1000))
random.shuffle(ls)
nums = len(ls)

for i in range(nums):
    for j in range(0, nums-i-1):
        if ls[j] > ls[j+1]: ls[j], ls[j+1] = ls[j+1], ls[j]

print(ls)

4、选择排序

说明:

  • 选择排序分为有序区(最开始是空的)和无序区;
  • 每次寻找无序区中的最小值放入有序区中;
  • 直到无序区为空。
import random

ls = list(range(1000))
random.shuffle(ls)
nums = len(ls)

# 方法一:只要比对应位的值大,就发生交换
# for i in range(nums):
#     for j in range(i+1, nums):
#         if ls[i] > ls[j]:ls[i], ls[j] = ls[j], ls[i]

# 方法二:记录最小值的下标
for i in range(nums):
    min_index = i
    for j in range(i+1, nums):
        if ls[min_index] > ls[j]:min_index = j
    ls[i], ls[min_index] = ls[min_index], ls[i]


print(ls)  

5、插入排序

说明:

  • 分为有序区和无序区,默认第一位为有序的;
  • 无序区的第一位元素和前面有序的元素进行比较,插入对应位置;
  • 直到无序区为空。
import random

ls = list(range(1000))
random.shuffle(ls)
nums = len(ls)

for i in range(1, nums):
    flag = ls[i]
    flag_index = i
    # 判断:如果当前数比前一个数小的话,则前一个数向后移动一位
    while flag_index > 0 and flag < ls[flag_index-1]:
        ls[flag_index] = ls[flag_index-1]
        flag_index = flag_index - 1
    ls[flag_index] = flag

print(ls) 

6、希尔排序

说明:

  • 希尔排序就是每次将元素进行基本有序的排序;
  • 每次对间隔为n的元素进行比较,然后排序,n=len(ls)//2,下一次为n//2,以此类推;
  • 当间个为1的时候,即可将ls排序完成。
import random

ls = list(range(1000))
random.shuffle(ls)
nums = len(ls)

# 进行排序
def insert_sort_gap(ls, gap):
    for i in range(gap, len(ls)):
        tmp = ls[i]
        j = i - gap
        while j >= 0 and ls[j] > tmp:
            ls[j+gap] = ls[j]
            j -= gap
        ls[j+gap] = tmp

def shell_sort(ls):
    d = len(ls) // 2
    while d >= 1:
        insert_sort_gap(ls, d)
        d //= 2

shell_sort(ls)
print(ls)

7、归并排序

说明:

  • 将一个ls,进行不断的分区,直到每个区只有一个元素,一个元素都可认为是有序的;
  • 再将只有一个元素的区进行向上归并,将小的元素先放入新的ls,再将新的ls覆盖曾经的ls对应的位置;
  • 重复以上步骤,最后归并结束,ls有序。
import random

# 归并
def merge(ls, low, mid, high):
    i = low
    j = mid+1
    ltmp = []
    # 两边都有数
    while i <= mid and j <= high:
        if ls[i] < ls[j]:
            ltmp.append(ls[i])
            i += 1
        else:
            ltmp.append(ls[j])
            j += 1
    # 循环结束,有一部分没数
    while i <= mid:
        ltmp.append(ls[i])
        i += 1
    while j <= high:
        ltmp.append(ls[j])
        j += 1
    ls[low:high+1] = ltmp

# 进行分区
def merge_sort(ls, low, high):
    if low < high:
        mid = (low + high) // 2
        merge_sort(ls, low, mid)
        merge_sort(ls, mid+1, high)
        merge(ls, low, mid, high)


ls = list(range(1000))
random.shuffle(ls)

merge_sort(ls, 0, len(ls)-1)
print(ls)

8、快速排序

说明:

  • 定义双端指针,left,right,一般情况下left第一位为基准值;
  • left和right相等的时候,则代表第一次遍历结束,left=right的位置是有序的,且left往前的部分都是小于right往后的部分;
  • 对left=right这个位置进行切割,成两部分,重复上面的操作。
import random

ls = list(range(1000))
random.shuffle(ls)

def partition(ls, left, right):
    tmp = ls[left]
    while left < right:
        while left < right and ls[right] >= tmp:
            right -= 1
        ls[left] = ls[right]
        while left < right and ls[left] <= tmp:
            left += 1
        ls[right] = ls[left]
    ls[left] = tmp
    return left

def quick_sort(ls, left, right):
    if left < right:
        mid = partition(ls, left, right)
        quick_sort(ls, left, mid-1)
        quick_sort(ls, mid+1, right)

quick_sort(ls, 0, len(ls)-1)
print(ls)

9、堆排序

说明:

  • 堆分为最大堆和最小堆,堆顶为最大值、最小值;
  • 每次pop出最大值、最小值,存入新的ls即为有序;
  • 以下方法使用heapq模块,生成最小堆。
import heapq, random

ls = list(range(1000))
random.shuffle(ls)

ls1 = []
# 生成最小堆
heapq.heapify(ls)
for i in range(len(ls)):
    # 每次pop出最小值
    ls1.append(heapq.heappop(ls))

print(ls1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值