IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构与算法:排序 -> 正文阅读

[数据结构与算法]数据结构与算法:排序

排序介绍

列表排序:将无序列表变成有序列表(升序或降序)

内置排序函数:sort()

常见排序算法:

LB三人组:冒泡排序、选择排序、插入排序

NB三人组:快速排序、堆排序、归并排序

其他排序: 希尔排序、计数排序、基数排序、桶排序

冒泡排序

列表每两个相邻的数,如果前面比后面大,则交换这两个数。(逐一比较)一趟排序完成后,无序区减少一个数,有序区增加一个数。(每一趟都会把无序区的最大数挑出来)

代码关键点:无序区、有序区、趟、无序区的范围

import random
def bubble_sort(li):
    for i in range(len(li)-1):
        #标志位
        exchange = False #优化排序,局部有顺序,可以减少一定的排序步骤
        for j in range(len(li)-i-1):#无序区
            if li[j]>li[j+1]:##此为升序,降序就需要改为<
                li[j],li[j+1] = li[j+1],li[j]#相邻两元素进行交换
                exchange = True
        if not exchange:
            return #一趟都不用发生交换,表明已经排好序,不用进行多余的步骤


lii = [random.randint(0,10000) for i in range(1000)]
print(lii)
bubble_sort(lii)
print(lii)

选择排序

每趟排序都记录最小的数,将其依次放在前面的位置。

代码关键点:有序区、无序区、无序区最小数的位置

#选择最小的放在一个空列表中
def select_sort_sample(li):
    li_new=[]#生成两个列表,占用更多内存;O(n^2)
    for i in range(len(li)):
        min_val = min(li)
        li_new.append(min_val)
        li.remove(min_val)
    return li_new

li = [2,1,6,9,6,7,3,2,6]
#print(select_sort_sample(li))

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]#将最小的数放在前面,与之交换的元素放在其原来的位置
select_sort(li)
print(li)

插入排序

初始的列表是有序的,每次从无序区中拿出一个数,将其插入到有序的列表中。

def insert_sort(li):
    for i in range(1,len(li)):
        tmp = li[i]
        j = i-1
        while j>=0 and li[j]>tmp:#比摸到的牌大的数往后移,j相当于一个小指针
            li[j+1] = li[j]
            j -= 1
        li[j+1] = tmp
li = [2,3,1,3,2,8,3,2,4]
insert_sort(li)
print(li)

快速排序

思路:

1.取一个元素p,使其归位;

2.列表被p分成两部分,左边都比p小,右边都比p大(找位置需要用到反向双指针)

3.递归完成排序

##修改递归最大深度
import sys
sys.setrecursionlimit(10000000)


##随机快速排序,避免最坏情况 ##https://blog.csdn.net/The_Shiled/article/details/121777268
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:
            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)

堆排序

二叉树:度不超过2的树。每个节点最多有两个子节点。

满二叉树:一个二叉树,如果每一层的节点树都达到最大值,则这个树为满二叉树。

完全二叉树:叶节点只能出现在最下层和次下层,并且最下层的节点都集中在该层的最左边的若干个位置的二叉树。

?二叉树的存储方式有链式存储方式、顺序存储方式。这里采用的是顺序存储方式。

堆:一种特殊的完全二叉树结构。有顺序的

大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大。

小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小。

堆的向下调整:假设节点左右子树都是堆,但自身不是堆。可以通过向下调整变成堆。

堆排序过程:

1.建立堆。

2.得到堆顶元素,此为最大元素。

3.去掉堆顶,将堆最后一个元素放到堆顶,此时可以通过一次向下调整重新使堆有序。

4.堆顶元素为第二大元素。

5.重复步骤3,指导堆变空。

#大根堆
def sift(li,low,high):
    '''
    li:列表
    low:堆的根节点位置
    high:堆的最后一个节点的位置
    '''
    i = low#i最开始指向根节点,之后指向每一子树的根节点 找父节点与子节点的关系
    j = 2*i+1#j开始是左孩子
    tmp = li[low]#把堆顶存起来
    while j <= high:#只要j位置有数
        if j+1<= high and li[j+1]>li[j]:#如果右孩子存在且较大
            j = j+1#j指向右孩子
        if li[j]>tmp:
            li[i] = li[j]
            i = j #往下看一层
            j = 2*i+1
        else:
            break#结束循环
    li[i] = tmp#最后一层了 两次结束循环,都需要把tmp放回来
def heap_sort(li):
    n = len(li)
    for i in range((n-2)//2,-1,-1):#i表示建堆时调整部分根的下标
        sift(li,i,n-1) #设high指最后一层
    #建堆完毕
    for i in range(n-1,-1,-1):#i指向当前堆的最后一个节点的位置
        li[0],li[i] = li[i],li[0]
        sift(li,0,i-1)#i-1是新的high
li = [i for i in range(100)]
# li = list(range(100))
import random
random.shuffle(li)
print(li)
# heap_sort(li)
# print(li)

##堆排序的内置代码

import heapq#优先队列  小的先出,或大的先出
heapq.heapify(li)#建堆 小根堆
#heapq.heappop(li)#向外弹出最小元素  升序
lii = []
for i in range(len(li)):
    lii.append(li[i])
print(lii)

堆排序——topk问题

现在有n个数,设计算法得到前k个大的数。

取列表前k个元素建立一个小根堆,堆顶就是目前第k大的数。

依次向后遍历原列表,对于列表中的元素,如果小于堆顶,则忽略;如果大于堆顶,则将堆顶更换为该元素,并且对堆进行一次调整。

遍历列表所有元素后,倒序弹出堆顶。

def sift(li,low,high):#小根堆
    '''
    li:列表
    low:堆的根节点位置
    high:堆的最后一个节点的位置
    '''
    i = low#i最开始指向根节点,之后指向每一子树的根节点
    j = 2*i+1#j开始是左孩子
    tmp = li[low]#把堆顶存起来
    while j <= high:#只要j位置有数
        if j+1<= high and li[j+1]<li[j]:#如果右孩子存在且较小
            j = j+1#j指向右孩子
        if li[j]<tmp:
            li[i] = li[j]
            i = j #往下看一层
            j = 2*i+1
        else:
            break#结束循环
    li[i] = tmp#最后一层了 两次结束循环,都需要把tmp放回来

def topk(li,k):
    heap=li[0:k]
    for i in range((k-2)//2,-1,-1):#i表示建堆时调整部分根的下标
        sift(li,i,k-1) #设high指最后一层
    for i in range(k,len(li)):#遍历
        if li[i]>heap[0]:
            heap[0] = li[i]
            sift(heap,0,k-1)
    for i in range(k-1,-1,-1):#出数
        heap[0],heap[i] = heap[i],heap[0]
        sift(heap,0,i-1)
    return heap

def heap_sort(li):
    n = len(li)
    for i in range((n-2)//2,-1,-1):#i表示建堆时调整部分根的下标
        sift(li,i,n-1) #设high指最后一层
    #建堆完毕
    for i in range(n-1,-1,-1):#i指向当前堆的最后一个节点的位置
        li[0],li[i] = li[i],li[0]
        sift(li,0,i-1)#i-1是新的high

import random
li = list(range(1000))
random.shuffle(li)
print(li)
print(topk(li,100))

归并排序

假设现在的列表分成两段有序,如何将其合成一个有序列表,这样的操作称为一次归并。

#局部有序的排序
def merge(li,low,mid,high):#同向双指针
    i = low
    j = mid+1
    l_tmp = []
    while i <= mid and j <= high:#需要两边都有数
        if li[i]<li[j]:
            l_tmp.append(li[i])
            i += 1
        else:
            l_tmp.append(li[j])
            j += 1
    #执行完while后,肯定有一部分没有数
    while i <= mid :
        l_tmp.append(li[i])
        i += 1
    while j <= high:
        l_tmp.append(li[j])
        j+= 1
    li[low:high+1] = l_tmp

li = [2,4,5,7,4,6,7,8]
merge(li,0,3,7)
#print(li)

def merge_sort(li,low,high):
    mid = (low+high)//2
    if low < high:#至少有两个元素
        merge_sort(li,low,mid)
        merge_sort(li,mid+1,high)
        merge(li,low,mid,high)
merge_sort(li,0,7)
print(li)

希尔排序

一种分组插入排序。

首先取一个整数d1=n/2,将元素分为d组,每组相邻元素之间距离为d1,在各组内进行直接插入排序;

取第二个整数d2=d1/2,重复上述分组排序过程,直到di=1,即所有元素在同一组内进行直接插入排序。

希尔排序每趟并不是使某些元素有序,而是使整体数据越来越接近有序,最后一趟排序才能使数据有序。

def insert_sort_gap(li,gap):
    for i in range(gap,len(li)):
        tmp = li[i]
        j = i-gap
        while j>=0 and li[j]>tmp:#比摸到的牌大的数往后移,j相当于一个小指针
            li[j+gap] = li[j]
            j -= gap
        li[j+gap] = tmp

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

计数排序

对列表进行排序,已知列表中的数范围都在0到100之间。

#不是比较方法

def count_sort(li,max_count=100):
    count = [0 for _ in range(max_count+1)]
    for val in li:
        count[val] += 1
    li.clear()
    for ind, val in enumerate(count):#得到每一个数字出现的频数
        for i in range(val):
            li.append(ind)

import random
li = [random.randint(0,100) for _ in range(100)]
print(li)
count_sort(li,max_count=100)
print(li)
# li = [1,2,3,6,3,4,2,1]
# count_sort(li,max_count=100)
# print(li)


桶排序

在计数排序中,如果元素的范围比较大,可以使用桶排序。

桶排序:首先将元素分在不同的桶中,再对每个桶中的元素排序。

def bucket_sort(li,n = 100,max_num = 10000):
    bucket = [[] for _ in range(n)]#创建一个二维列表
    for val in li:
        i = min(val//(max_num//n),n-1)#放到第几号桶中,对于最后一个数,选择放在最后一个桶中
        bucket[i].append(val)
        #排序 类似于冒泡排序 从后往前逐一地与前面地数进行比较
        for j in range(len(bucket[i])-1,0,-1):
            if bucket[i][j]<bucket[i][j-1]:
                bucket[i][j],bucket[i][j-1] = bucket[i][j-1],bucket[i][j]
            else:
                break
    sorted_li = []
    for buc in bucket:
        sorted_li.extend(buc)## extend:追加列表,列表被拆分为一个一个元素
    return sorted_li
import random
li = [random.randint(0,10000) for i in range(100)]
print(li)
#bucket_sort(li)
print(bucket_sort(li))









基数排序

多关键字排序:如加入现在有一个员工表,要求先按照薪资排序,年龄相同的员工按照年龄排序。

#类似于多关键词排序
#多次装桶,按照位数从小到大装桶,最后输出,没有桶内排序的过程
#个位进桶,十位进桶,百位进桶等
def radix_sort(li):
    max_num = max(li)
    it = 0
    while 10**it <= max_num:
        buckets = [[] for _ in range(10)]
        for val in li :
            digit = (val // 10**it)%10
            buckets[digit].append(val)
        li.clear()
        for buc in buckets:
            li.extend(buc)
        it += 1
li = [234,678,945,34,65,78,231,765,987]
radix_sort(li)
print(li)

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:52:38  更:2022-09-21 00:52:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:36:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码