python 实现数据结构八种内部排序算法
目录
一、插入排序
二、希尔排序
三、冒泡排序
四、快速排序
五、选择排序
六、堆排序
七、归并排序
八、基数排序
一、插入排序
array_test = [8,3,5,1,10,4,2,6,7,9]
# 插入排序
# 将数组分为“已排序好”“未排序”两部分
# 每次循环依次从“未排序”中拿出一个 插入到“已排序好”的合适位置
def InsertSort(array):for i in range(1,len(array)): # 默认0号位置已经排好if array[i] < array[i-1]: # 如果比已排序好的列表最大的元素还大 就不需要比较temp = array[i]# 思路:将temp放到合适位置 并将temp后的元素向后移j = i-1k = i# 找到temp的合适位置while array[j] > temp and j >= 0:j = j - 1# 注意此时j指向的是待插入元素的前一个位置# 所以不能移动array[j] 从后到前移动到array[j+1]while k > j+1:array[k] = array[k-1]k = k - 1# 把temp放进来array[j+1] = tempreturn array
print(InsertSort(array_test))
空间复杂度:O(1)
最好时间复杂度:O(n) 数组原来就有序,只需要每次比较,不需要移动
最坏时间复杂度:O(n)
平均时间复杂度:O(n²)
稳定性:稳定
折半插入排序:在寻找插入位置时,通过改用折半查找以减少比较次数,提升效率:
def InsertSort(array):for i in range(1,len(array)): # 默认0号位置已经排好if array[i] < array[i-1]: # 如果比已排序好的列表最大的元素还大 就不需要比较temp = array[i]# 思路:将temp放到合适位置 并将temp后的元素向后移high = i-1low = 0k = i# 找到temp的合适位置while low <= high:mid = (low+high)/2if array[mid] > temp:high = mid - 1else:low = mid + 1# 注意此时j多减了1 已经是temp之前的位置# 把合适位置后的所有元素向后移位时 j要加一while k > high+1:array[k] = array[k-1]k = k - 1# 把temp放进来array[high+1] = tempreturn array
在代码中,我们需要注意的是二分查找进行了一点小改动,取消了array[mid] == temp的情况,这是因为即时二者相等,出于排序算法稳定性的考虑,我们希望“原本位置靠后的元素”仍可以排在“值相等、但原本靠前的元素”之后。
折半插入排序优化了比较时间复杂度(O(nlogn)),但由于其移动的时间复杂度仍为O(n²),故其总的时间复杂度为O(n²)。
二、希尔排序
array_test = [8, 3, 5, 1, 10, 4, 2, 6, 7, 9]
# 希尔排序
# 希尔排序是基于“插入排序对有序表/基本有序表效率高”产生的
# 先追求部分有序 再追求全局有序
# 排序增量为d的子表[i,i+d,i+2d...] 不断缩小增量d
def ShellSort(array):d = len(array)//2while d >= 1:for i in range(d, len(array)):if array[i] < array[i-d]: # 则需要将array[i]插入有序子表# 插入排序temp = array[i]j = i - 1k = iwhile array[j] > temp and j >= 0:j = j - 1while k > j + 1:array[k] = array[k - 1]k = k - 1array[j + 1] = tempd = d//2 # 步长折半return arrayprint(ShellSort(array_test))
d=1时,即为对一个基本有序的序列进行插入排序。
空间复杂度:O(1)
时间复杂度:还不能由数学推导
稳定性:不稳定
三、冒泡排序
array_test = [8, 3, 5, 1, 10, 4, 2, 6, 7, 9]
# 冒泡排序
# 从后向前依次对比 每一轮都把最小的放在最前面
# 一共需要进行n-1次
def swap(i,j):return j,idef BubbleSort(array):n = len(array)for i in range(0, n-1):j = n-1while j > i:if array[j] < array[j-1]:array[j],array[j-1] = swap(array[j],array[j-1])j = j - 1return arrayprint(BubbleSort(array_test))
“完全版”的冒泡排序会设立一个flag标记,当某次比较并没有发生元素移动时,则停止下一轮比较,提前结束排序。
空间复杂度:O(1)
最好时间复杂度:O(n)
最坏时间复杂度:O(n²)
平均时间复杂度:O(n²)
稳定性:稳定
四、快速排序
array_test = [8, 3, 5, 1, 10, 4, 2, 6, 7, 9]
# 快速排序
# 每次选择一个元素作为基准 将表“划分”为左右两个部分
# 递归的对子表选择基准 进行划分
def QuickSort(array,low,high):if low < high: # 递归终止条件# low == high 的时候即为划分后为两个元素的情况pivotpos = Partition(array,low,high)QuickSort(array,low,pivotpos-1)QuickSort(array, pivotpos+1,high)return arraydef Partition(array,low,high):privot = array[low] # 第一个元素作为privot# 因为已经用privot保存了第一个元素的值 所以可以将low指针指向的位置视为空while low < high:# 此时,可以将low指针指向的位置视为空# 先移动high指针while low < high and array[high] >= privot:high = high - 1array[low] = array[high] # 比privot小的放左边# 此时,可以将high指针指向的位置视为空while low < high and array[low] <= privot:low = low + 1array[high] = array[low] # 比privot大的放右边array[low] = privot # 此时low == high 将privot元素放置于此return low # 返回存放privot的位置print(QuickSort(array_test,0,len(array_test)-1))
快速排序递归调用的层数就是二叉树的高度。
最好空间复杂度:O(logn)
最坏空间复杂度:O(n)
最好时间复杂度:O(nlogn)
最坏时间复杂度:O(n²)
稳定性:不稳定
五、选择排序
array_test = [8, 3, 5, 1, 10, 4, 2, 6, 7, 9]
# 选择排序
# 从左向右 每次选择最小的值,放到未排序序列的首部
# 一共需要n-1次
def swap(i,j):return j,i
def SelectSort(array):n = len(array)for i in range(0,n-1):min_pos = i # 记录最小元素位置for j in range(i+1,n):if array[j]<array[min_pos]:array[j],array[min_pos] = swap(array[j],array[min_pos])return arrayprint(SelectSort(array_test))
空间复杂度:O(1)
时间复杂度:O(n²)
稳定性:不稳定
六、堆排序
array_test = [8, 3, 5, 1, 10, 4, 2, 6, 7, 9]
# 堆排序
# 建立大根堆
# 将堆顶元素和待排序序列中的最后一个交换
# 将剩余的[0,n-i]个元素调整为大根堆
def swap(i, j):return j, i# 将k为根结点的树 调整为大根堆
def HeadAjust(array, k, len):temp = array[k] # 保存要判断的结点 直到下降到满足大根堆的位置i = 2*k # 左孩子while i < len: # 存在左孩子if i+1 < len and array[i] < array[i+1]: # 存在右孩子# 比较左右孩子的大小i = i + 1# 若以该结点为根节点的树不是最大堆,以上操作已经找到了应该成为根节点的孩子if temp >= array[i]: # 如果已经满足了最大堆breakelse:array[k] = array[i] # 与较大子树的值交换# 小元素逐层下坠k = i # 此时还不能直接完成交换 仍要继续向下比较i = i * 2array[k] = temp# 建立大根堆
def BuildMaxHeap(array,len):# 只需要处理非叶结点k = len // 2 # 一颗完全二叉树的叶子结点数为 n/2向上取整while k >= 0:HeadAjust(array, k, len)k = k - 1 # 自底向上调整# 堆排序
def HeapSort(array):n = len(array)# 建立大根堆BuildMaxHeap(array, n)# 指向待排序数组的最后位置i = n-1while i > 0:array[i], array[0] = swap(array[i], array[0])# 将根节点为0的调整为大根堆 即选出了数组中最大的元素 放到array[i]的位置HeadAjust(array, 0, i-1)# 每次待排序的长度都减一i = i - 1return arrayprint(HeapSort(array_test))
建堆:O(n)
排序:O(nlogn)
总时间复杂度:O(nlogn)
稳定性:不稳定
七、归并排序
array_test = [8, 3, 5, 1, 10, 4, 2, 6, 7, 9]
# 归并排序# 合并两个有序数组的操作 Merge
def Merge(array,low,mid,high):# 必须要分配空间 若直接temp = [] 则temp[k]会报错temp = [0] * (high+1)# 将原数组复制到temp中for k in range(low, high+1):temp[k] = array[k]i = lowj = mid+1k = i# 合并过程while i <= mid and j <= high:if temp[i] <= temp[j]:array[k] = temp[i]i = i + 1else:array[k] = temp[j]j = j + 1k = k + 1# 处理没有合并完的子序列while i <= mid:array[k] = temp[i]k = k + 1i = i + 1while j <= high:array[k] = temp[j]k = k + 1j = j + 1def MergeSort(array,low,high):if low < high:mid = (low+high)//2# 归并排序左半边MergeSort(array, low, mid)# 归并排序右半边MergeSort(array, mid+1, high)# 合并Merge(array, low, mid, high)return array
print(MergeSort(array_test, 0, len(array_test)-1))
空间复杂度:O(n) 辅助数组(递归工作栈复杂度O(logn))
时间复杂度:O(nlogn)
稳定性:稳定
八、基数排序
把关键词拆分为 d 位,按照关键字权重递增的顺序进行d躺分配、收集。
需要建立r个辅助队列
空间复杂度:O(r)
分配时,对于某一位,只需要从头到尾把元素扫一遍,n位的时间为 d*n
收集时,由于只需要改变一次链表的指针,对每个队列的操作时间为O(1),时间为为d*r
时间复杂度: O(d(n+r))
稳定性:稳定
总结:
1、(图片来自于python菜鸟教程 侵删)
2、
元素的移动次数与关键字的初始排列次序无关的是:基数排序
元素的比较次数与初始序列无关是:选择排序、折半插入排序
算法的排序趟数与初始序列无关的是:插入排序、选择排序、基数排序
算法的时间复杂度与初始序列无关的是:选择排序、堆排序、归并排序、基数排序
记忆方法:一堆(堆排序)乌龟(归并)选(选择)基(基数)佬
这个记忆方法来自于CSDN博主 @寒泉Hq
python 实现数据结构八种内部排序算法相关推荐
- 数据结构实验:内部排序算法的性能分析
文章目录 前言 一.问题描述 二.问题分析 三.实验结果及分析 (1)实验数据描述 (2)实验结果 (3)性能分析 四.源代码 前言 记录下本学期的数据结构实验 本实验主要集中于比较几种内部排序算法 ...
- 五种内部排序算法性能比较——C++
**五种内部排序算法性能比较 ** 1.直接插入排序算法 将一个待排序的记录插入到若干个已排好序的有序记录中的适当位置,从而得到一个新的.记录数增加1的有序数据序列,直到插入完成.在最开始,整个有序数 ...
- C语言——十四种内部排序算法【直接插入排序-冒泡排序-选择排序-插入排序-希尔排序-归并排序-快速排序-堆排序-折半插入排序-二分查找-路插入排序-表插入排序-简单选择排序-直接选择排序-树形选择】
目录: 一:插入排序 A:直接插入排序 1.定义: 2.算法演示 实例1: 3.基本思想 4.排序流程图 实例1: B:希尔排序 1.定义: 2.算法演示 实例2: C:其他插入排序 a:折半插入排序 ...
- 《数据结构》之内部排序算法比较
前言 各种内部排序算法的时间复杂度分析结果只给出了算法执行时间的阶,或大概执行时间.试通过随机的数据比较各算法的关键字比较次数和关键字移动次数,以取得直观感受. 基本要求: (1) 从以下常用的内部排 ...
- 排序 八种经典排序算法
排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列. 我整理了以前自己所写的一些排序算法结合网上的一些资料,共介绍8 ...
- 剖析八种经典排序算法
排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列. 我整理了以前自己所写的一些排序算法结合网上的一些资料,共介绍8 ...
- 八种经典排序算法总结
前言 算法和数据结构是一个程序员的内功,所以经常在一些笔试中都会要求手写一些简单的排序算法,以此考验面试者的编程水平.下面我就简单介绍八种常见的排序算法,一起学习一下. 一.冒泡排序 思路: 比较相邻 ...
- 八种常见排序算法细讲
目录 常见的八种排序 直接插入排序 希尔排序 直接选择排序 堆排序 冒泡排序 快速排序 hoare版本 挖坑法 前后指针版 快速排序代码 归并排序 计数排序 常见的八种排序 直接插入排序 ⾸先,我们将 ...
- 八种常用排序算法参考
写在前面: 因为网络上有很多篇讲排序算法的,所以这里就不详细讲了,只作为参考和自己查阅 当然了,虽然篇幅也会短很多,但部分重点和要点还在 八种排序算法分别是: ①选择排序: ②冒泡排序: ③插入排序: ...
最新文章
- 最全正則表達式汇总—想要的都有了
- 如何将一键还原精灵备份文件复制出来?
- UVA1103分区涂色+vc使用注意事项
- 了解员工工作的四种方法
- php支付宝h5 app,H5网站接入支付宝的支付接口
- 计算机术语 gc 是什么意思,gc是什么意思(女生网络用语gc的含义)
- 20+免费精美响应式Html5 网站模板01(含源码)
- struct用法(C语言)
- c 语言识别图片中的文字,Tesseract OCR图片识别为文字
- 【Unity实战100例】Unity幸运大转盘之概率可控
- 全世界最亏本的事(转)
- 声音四要素:音强、音调、音色和波形包络
- FT、DFT、FFT
- 群晖nas使用的端口
- (项目)在线教育平台(十三)
- Unity Shader Graph 制作Emission发光效果
- 【98期】面试官:给我说说你对Java GC机制的理解?
- 进击吧!Pythonista(6/100)
- 抓包:Charles抓包配置分析笔记
- 仿一号店APP商品分类效果开发Android版本