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 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构与算法-排序(2) -> 正文阅读

[数据结构与算法]数据结构与算法-排序(2)

1.快速排序(原地排序)

思路:取一个元素p(第一个元素),使p归位;列表被p分为两部分,左边都比p小,右边都比p大;递归完成排序。

关键代码:归位的实现。

def partition(li,left,right):
    tmp=li[left]
    while left<right:#列表中至少两个值
        while left<right and li[right]>=tmp:#一旦left和right重合,就退出
            right-=1
        li[left]=li[right]#把右边比第一个值小的数放到左边空位
        while left<right and li[left]<=tmp:
            left+=1
        li[right]=li[left]#把左边比第一个值大的数放到右边空位
    li[left]=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)

时间复杂度:O(nlogn)

快速排序的问题:递归:递归最大深度;最坏情况:时间复杂度O(n^2)

修改最大深度代码:

import sys
sys.setrecurtionlimit(10000)

2.推排序(原地排序)

·堆:一种特殊的完全二叉树结构

·大根堆:一个完全二叉树,满足任一节点都比其他孩子节点大,根节点为最大元素

·小根堆:一个完全二叉树,满足任一节点都比其他孩子节点小,根节点为最小元素

·堆的向下调整:假设节点的左右子树都是堆,但本身不是堆,通过向下调整根节点使其变成堆。

·堆排序过程:

(1)建立堆;(农村包围城市,从最下面开始调整,直到整个堆完成)

(2)得到堆顶元素,为最大元素;

(3)去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序;

(4)堆顶元素为第二大元素;

(5)重复步骤(3),直到堆变空。

关键代码:向下调整和出数

向下调整代码:

def sift(li,low,high):
    i=low#i开始指向根节点
    j=2*i+1#j开始是左孩子
    tmp=li[i]
    while j<=high:#只要j位置有效
        if j+1<=high and li[j+1]>li[j]:#如果右孩子有并且比较大
            j=j+1
        if li[j]>tmp:
            li[i]=li[j]
            i=j#往下看一层
            j=2*i+1
        else:#tmp更大,把tmp放在i的位置上
            li[i]=temp#把tmp放在某一级领导位置上
            break
    else:
        li[i]=temp#把tmp放到叶子节点上
#大根堆

时间复杂度:O(logn)

构造堆+出数:

def heap_sort(li):
    n=len(li)
    for i in range((n-1-1)//2,-1,-1):#i表示所需调整的堆的根节点的位置
        sift(li,i,n-1)
    #建堆完成
    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    

堆排序时间复杂度:O(nlogn)

堆的内置模块:

import heapq
import random

li=list(range(100))
random.shuffle(li)
heapq.heapify(li)#建堆(小根堆)
n=len(li)
for i in range(n):
    print(heapq.heappop(li),end=',')#每次弹出一个最小值

堆排序-topk问题:现在有n个数,设计算法得到前k大的数(k<n)

解决方法:

(1)排序后切片:O(nlogn)

(2)简单排序三人组:O(kn)

(3)堆排序:O(nlogk)

解决思路:

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

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

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

代码实现:

def sift(li,low,high):
    i=low#i开始指向根节点
    j=2*i+1#j开始是左孩子
    tmp=li[i]
    while j<=high:#只要j位置有效
        if j+1<=high and li[j+1]<li[j]:#如果右孩子有并且比较小
            j=j+1
        if li[j]<tmp:
            li[i]=li[j]
            i=j#往下看一层
            j=2*i+1
        else:#tmp更小,把tmp放在i的位置上
            li[i]=temp#把tmp放在某一级领导位置上
            break
    else:
        li[i]=temp#把tmp放到叶子节点上
#小根堆
def topk(li,k):
    heap=li[0:k]#取前k个数
    sift(heap,0,k-1)#建堆
    for i in range(k,len(li)-1):
        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

3.归并排序(非原地排序)

归并:假设现在有两个有序的列表,如何合并成一个有序的列表,这种操作称为一次归并。

思路:两个有序列表的开头分别有一个指针,比较两个指针所指位置值的大小,将小的先放到新的列表,另一个再放,直到其中一个列表变为空,将另外一个列表的剩余元素放到这个新列表中即可。

归并代码实现:

def merge(li,low,mid,high):
    i=low
    j=mid+1
    ltmp=[]
    while i<=mid and j<=high:#左右两个列表中都有值
        if li[i]<li[j]:
            ltmp.append(li[i])
            i+=1
        else:
            ltmp.append(li[j])
            j+=1
    #while结束意味着其中一个列表变为空
    while i<=mid:#左边序列有值
        ltmp.append(li[i])
        i+=1
    while j<=high:#右边序列有值
        ltmp.append(li[j])
        j+=1
    li[low:high+1]=ltmp

归并排序的思路:(递归)

分解:将列表越分越小,直至分成一个元素

终止条件:一个元素是有序的

合并:将两个有序列表归并,列表越来越大

?代码实现:

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

时间复杂度:O(nlogn)

空间复杂度:O(n)

总结:

(1)快速排序、堆排序、归并排序的时间复杂度都是O(nlogn);

(2)一般情况下,就运行时间而言:快速排序<归并排序<堆排序;

(3)三种排序算法缺点:

? ? ? ? 快速排序:极端情况下排序效率低

? ? ? ? 归并排序:需要额外的内存开销

? ? ? ? 堆排序:在快的排序算法中相对较慢

(4)递归有空间开销;

(5)稳定的排序能保证相等元素的相对位置不变(相邻元素依次比较就是稳定排序)。

说明:

本篇博客只是作为个人的听课笔记使用。具体课程为b站上清华大学博士讲解的数据结构与算法,课程讲的非常详细易懂,有需要的可以移步观看。

清华大学博士讲解Python数据结构与算法(完整版)全套100节_哔哩哔哩_bilibili

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 11:07:37  更:2022-08-06 11:10:29 
 
开发: 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 22:29:25-

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