数据结构6.2内部排序

本文详细介绍了内部排序的各种方法,包括直接插入排序、折半插入排序、2路插入排序、表插入排序、希尔排序、交换排序(起泡排序、快速排序)、选择排序(简单选择排序、树形选择排序、堆排序)、归并排序(递归和非递归实现)、计数排序和基数排序。重点讨论了排序方法的稳定性、分类以及各自的优势。

排序

假设含n个记录的序列为
{R1,R2,…,Rn}
其对应的关键字序列为
{K1,K2,…,Kn}
这些关键字的排列方式有多种,其中至少有一种排列方式能使得关键字之间存在着这样一个关系:
Kp1 <= Kp2 <= … <= Kpn
按此关系将记录序列重新排列为
{Rp1,Rp2,…,Rpn}
即为有序记录,将这一过程称为排序

排序方法的稳定性

若在一个记录序列中Ki == Kj,且在排序前的序列中Ri领先于Rj。若在排序后的序列中Ri仍领先于Rj,则称使用的排序方法是稳定的;若排序后的序列中可能使Rj领先于Ri,则称所用的排序方法是不稳定的。

排序方法分类

若整个排序过程不需要访问外存便能完成,则称此类排序为内部排序;反之,待排序的记录数量很大,整个排序过程不能在内存中一次完成,需要借助外存才能实现,则称此类排序为外部排序

内部排序方法

1.插入排序:将无序序列区中的记录向有序序列区中插入,使有序序列长度增加
2.交换排序:通过比较记录的关键字大小来决定是否交换记录,从而排定记录所在位置
3.归并排序:将两个小的有序记录序列合并成一个大的有序记录序列,逐步增加有序序列长度
4.选择排序:从无序序列区中选出关键字最小(升序排列)或最大(降序排列)的记录,并将它交换到有序序列区中指定位置的方法
5.计数排序:通过统计小于(升序排列)或大于(降序排列)待排序记录关键字的记录个数,从而决定待排序记录所在位置

插入排序

直接插入排序

基本操作是将一个记录插入到已排好的有序表中,从而得到一个新的、记录数增加1的有序表。

折半插入排序

在直接插入排序的基础上,用折半查找定位记录待排序记录在已排序记录表中的位置。

2路插入排序

是对折半插入排序算法的一种改进,目的是减少排序过程中记录的移动次数。以第一个记录为界,将整个记录序列分成两部分进行处理。将不小于第一个记录的记录用折半插入的方法插入到左路的有序序列中;将小于第一个记录的记录用折半插入的方法插入到右路的有序序列中。可设两个指针final和first分别指示左路序列的最后一条记录位置和右路序列中第一条记录的位置。

表插入排序

改变查找过程中采用的存储结构。采用静态链表进行排序,并在排序完成之后一次性的调整各个记录相互之间的位置。

希尔排序

又称缩小增量排序。利用直接插入排序的优点对待排序的记录序列先做宏观调整,再做微观调整。将整个记录序列按下标的一定增量分成若干个子序列,对每个子序列分别进行直接插入排序。然后再将增量缩小,划分子序列,重复进行,最后再对整个序列进行一次直接插入排序。

交换排序

起泡排序

快速排序

又称霍尔排序,将序列中的每条记录当成一个标尺,凡是比该记录关键字小的记录移到该记录的前面,不小于的移到后面,这样就确定了该记录的位置,也称该记录为枢轴记录

选择排序

简单选择排序

一趟简单选择排序的操作为:从无序的记录序列中选出一个关键字值最小的记录存入到指定的位置

树形选择排序

一种借助于锦标赛方式的选择排序算法。使用近似于完全二叉树的树形,所有记录均为叶子结点,从叶子结点开始,通过两两比较,填到树顶的结点是对应关键字最小的记录,然后将该叶子结点关键字置为最大关键字(或无穷大),继续选出第二个最小值,重复进行至排序结束。

堆排序

堆或者是空二叉树,或者是一颗满足如下特性的完全二叉树:其左右子树均是堆,并且当左子树或右子树不空时,根结点的值小于(或大于)左右子树根结点的值。

归并排序

递归的归并排序算法

1. 有序表合并算法
2.2路归并排序算法

非递归的归并排序算法

1.有序表合并算法
2.归并排序算法

计数排序

通过记录关键字的比较,计算每个记录应该存放的位序,也就是对每个记录,统计记录序列中按关键字值排在它前面的记录个数,然后把每个记录调到相应位置。

基数排序

一种多关键字的排序方法。假设有n个记录构成的序列{R1,R1,…,Rn},其中每个记录Ri中含有d个关键字(K01 , K11 … Kd-1 1)若对于序列中任意两个记录Ri和Rj都满足Ri中所有关键字对应小于Rj中的关键字。则称上述记录序列对关键字(K01 , K11 … Kd-1 1)有序。其中K0被称为最主位关键字,Kd-1被称为最次位关键字。

最高位优先(MSD)法

先按最主位关键字K0进行排序,并按K0的不同值将记录序列分成若干子序列,在分别按K1进行排序…以此类推,直到最后按最次位关键字Kd-1排序完成为止

最低位优先(LSD)法

先按最次位关键字Kd-1进行排序,并按K0的不同值将记录序列分成若干子序列,在分别按Kd-2进行排序…以此类推,直到最后按最主位关键字K0排序完成为止

### 数据结构中的十大经典排序算法解释与实现 #### 1. 插入排序 (Insertion Sort) 插入排序是一种简单直观的排序方法,它构建有序序列的工作原理类似于人们整理手中的扑克牌。每次从未排序部分取出一个元素,在已排序部分找到合适的位置并插入。 ```python def insertion_sort(arr): for i in range(1, len(arr)): key = arr[i] j = i - 1 while j >=0 and key < arr[j]: arr[j + 1] = arr[j] j -= 1 arr[j + 1] = key ``` 该算法的时间复杂度为 O(n&sup2;),适用于小型数组或基本有序的数据集[^1]。 #### 2. 希尔排序 (Shell Sort) 希尔排序是对插入排序的一种改进版本,通过比较相隔一定间隔的元素来减少移动次数,从而提高效率。 ```python def shell_sort(arr): n = len(arr) gap = n // 2 while gap > 0: for i in range(gap, n): temp = arr[i] j = i while j >= gap and arr[j - gap] > temp: arr[j] = arr[j - gap] j -= gap arr[j] = temp gap //= 2 ``` 时间复杂度介于O(n log n)到O(n^(3/2))之间,取决于增量的选择. #### 3. 冒泡排序 (Bubble Sort) 冒泡排序重复遍历要排序列表,依次比较相邻两个元素大小,并交换位置直到整个列表变得有序为止。 ```python def bubble_sort(arr): n = len(arr) for i in range(n): swapped = False for j in range(0, n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] swapped = True if not swapped: break ``` 平均情况下性能较差,时间复杂度为O(n&sup2;). #### 4. 快速排序 (Quick Sort) 快速排序采用分治法策略,选取一个基准值将待排序列划分为两部分,分别对这两部分继续执行相同操作直至完成全部排序过程。 ```python def quick_sort(arr): if len(arr) <= 1: return arr else: pivot = arr[len(arr)//2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left)+middle+quick_sort(right) ``` 最佳情况下的时间复杂度可以达到O(nlogn),但在最坏的情况下会退化成O(n&sup2;). #### 5. 归并排序 (Merge Sort) 归并排序也是一种基于分治思想的经典排序方式,先递归地把原始数组分成若干子数组再逐一合并这些子数组形成最终的结果。 ```python def merge_sort(arr): if len(arr)>1: mid=len(arr)//2;left_half=arr[:mid];right_half=arr[mid:] merge_sort(left_half);merge_sort(right_half); i=j=k=0 while i<len(left_half)and j<len(right_half): if left_half[i]<right_half[j]: arr[k]=left_half[i];i+=1 else: arr[k]=right_half[j];j+=1 k+=1 while i<len(left_half):arr[k]=left_half[i];i+=1;k+=1 while j<len(right_half):arr[k]=right_half[j];j+=1;k+=1 ``` 无论输入如何其稳定性和渐近运行时间为O(nlogn)[^1]. #### 6. 计数排序 (Counting Sort) 计数排序不是基于比较而是利用键值范围有限这一特性来进行高效排序的方法之一。 ```python def counting_sort(arr,max_value): m=max_value+1;count=[0]*m; for a in arr: count[a]+=1 i=0 for a in range(m): for c in range(count[a]): arr[i]=a;i+=1 return arr ``` 当数值分布较为集中时表现良好,空间消耗较大且只适合整型数据处理场景下应用. #### 7.排序 (Bucket Sort) 桶排序是另一种非比较类线性排序算法,核心在于按照特定规则分配给不同区间内的“桶”,之后单独针对各个桶内元素实施更高效的内部排序手段最后汇总得到完全有序集合。 ```python from typing import List def bucket_sort(nums:List[float])->None: """Sorts nums using Bucket sort algorithm""" num_of_buckets=int(len(nums)/2)# Create buckets based on size of input list. buckets=[[]for _ in range(num_of_buckets)] # Distribute elements into corresponding buckets according to their value ranges. max_val,min_val=max(nums),min(nums) interval=(max_val-min_val)/(num_of_buckets-1) for val in nums:buckets[int((val-min_val)/interval)].append(val) # Perform Insertion Sort within each individual bucket then concatenate all results together at last step. sorted_nums=[] for bkt in buckets: insrt_srt(bkt) sorted_nums.extend(bkt) return sorted_nums ``` 对于浮点数或者具有明显规律性的离散型变量尤为适用,实际效果依赖于具体应用场景设计合理程度. #### 8. 基数排序 (Radix Sort) 基数排序属于多关键字排序范畴,通常用于解决多位数字组成的字符串类型的排列组合问题上。通过对每一位上的字符逐位进行独立排序进而获得整体顺序关系。 ```python def radix_sort(lst): RADIX = 10 placement = 1 max_digit = max(lst) while placement <= max_digit: # declare and initialize empty buckets buckets = [[] for _ in range(RADIX)] # distribute the elements across different buckets for i in lst: tmp = int((i / placement) % RADIX) buckets[tmp].append(i) # collect items from buckets back into original array index = 0 for bucket in buckets: for item in bucket: lst[index] = item index += 1 # move to next digit place placement *= RADIX ``` 特别擅长处理大规模同构对象之间的相对定位任务,比如电话号码簿等场合中发挥重要作用. #### 9.排序 (Heap Sort) 堆排序借助二叉树形结构维护最大(最小)堆性质以确保根节点始终保存当前最高优先级记录项,随后不断调整剩余结点保持原有形态不变的同时逐步缩小_list,n,i): smallest=i;l=2*i+1;r=2*(i+1) if l<n and custom_list[l]<custom_list[smallest]:smallest=l elif r<n and custom_list[r]<custom_list[smallest]:smallest=r if smallest!=i: custom_list[i],custom_list[smallest]=custom_list[smallest],custom_list[i] heapify(custom_list,n,smallest) def heapsort(custom_list): n=len(custom_list) for i in reversed(range(int(n//2))): heapify(custom_list,n,i) for i in reversed(range(n)): custom_list[i],custom_list[0]=custom_list[0],custom_list[i] heapify(custom_list,i,0) return custom_list[::-1] ``` 具备较好的稳定性以及较低的空间开销特点使其成为许多编程语言标准库内置函数默认选项之一. #### 10. 选择排序 (Selection Sort) 选择排序的核心思路是在未排序区域寻找极值并与起始位置互换以此逐渐扩大已知最优解规模边界直至覆盖全量样本空间。 ```python def selection_sort(arr): for i in range(len(arr)-1): min_index=i for j in range(i+1,len(arr)): if arr[min_index]>arr[j]:min_index=j arr[i],arr[min_index]=arr[min_index],arr[i] ``` 尽管易于理解和编码实践但因频繁读写内存地址造成缓存命中率低下而影响总体效能水平处于次优状态.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值