目录
在数据结构的学习中,排序是一个非常重要的章节。第八章主要围绕排序展开,包括排序的基本概念、内部排序和外部排序。下面我们将详细介绍各种排序算法。
一、排序的基本概念
排序指的是重新排列序列中的元素,使得按照某个关键字递增或递减。例如对于学生信息表按照成绩排序。
稳定性
稳定性是排序算法的一个重要特性。它指的是在排序过程中,关键字相等的元素的相对次序是否保持不变。如果保持不变,则该排序算法是稳定的,否则是不稳定的。
二、内部排序
内部排序是在内存中进行的排序,数据量一般较小,可以一次性读入内存进行排序后再输出到外存。内部排序又可细分为插入排序、交换排序、选择排序以及归并排序等。
插入排序
- 直接插入排序
直接插入排序的思想很简单,每一回合基于已排序序列,挑选当前未排序序列中的第一个元素,从最后一个元素开始依次往前比较,直到找到合适位置插入。
以下是简单的 C 语言代码实现:
void insertionSort(int arr[], int n) {
int i, key, j;
for (i = 1; i < n; i++) {
key = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
- 折半插入排序
折半插入排序是对直接插入排序的查找过程进行改进,改成折半查找。但它的时间复杂度和空间复杂度并没有有效提升。其空间复杂度和直接插入排序相同,是常量阶,平均时间复杂度依然是。折半插入排序也是稳定的。 - 希尔排序
希尔排序基于如果序列基本有序则不需要多次直接插入的思想。它通过多趟的直接插入排序来实现,首先形成一个增量序列,按照增量的值进行小组划分,然后在各个小组内进行直接插入排序,不断减小增量值,直到增量值为 1。希尔排序的时间复杂度不确定,且是不稳定的。
交换排序
- 冒泡排序
冒泡排序的思想是从后往前或从前往后两两比较相邻元素,如果为逆序则发生交换。经过一趟排序后,会有一个当前最小或最大的元素移动到最后的位置。其空间复杂度是常量阶,最好情况下时间复杂度为线性阶,一般情况和最坏情况是,是一种稳定的算法。
以下是 C 语言代码实现:
void bubbleSort(int arr[], int n) {
int i, j;
for (i = 0; i < n - 1; i++) {
for (j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
- 快速排序
快速排序的核心思想是每一次选择一个枢轴元素,通过划分的方式把比枢轴元素小的放在左边,比枢轴元素大的放在右边。它需要借助栈来实现,空间复杂度取决于递归树的深度,最好情况时间复杂度是,最坏情况是(当序列基本有序时),平均时间复杂度是,是所有排序算法中平均性能最好的,但它是不稳定的。
选择排序
- 简单选择排序
简单选择排序每一轮在未排序元素中选出一个当前最小或最大的元素,然后存放在已排序序列的末尾。它的时间复杂度始终是,空间复杂度是常量阶,是不稳定的。 - 堆排序
堆排序采用顺序存储方式,其核心思想是学会插入和删除的调整。在堆排序中,任何一个父亲节点(大根堆时父亲节点值大于两孩子节点,小根堆时父亲节点值小于等于两孩子节点)。首先要先把初始的堆建出来,从最后一个父节点开始不断向下调整。输出堆顶元素后,将其与最后一个元素交换,然后从根节点开始进行向下调整。堆排序的空间复杂度是常量阶,时间复杂度在构建堆过程是线性阶,每次调整时间与堆的高度有关,总的时间复杂度是,也是不稳定的。
归并排序
归并排序基于归并操作和分治法(主要研究二路归并排序)。首先把原始数组拆分成多个长度为一的有序表,然后按照相邻的两个有序表进行两两合并,不断重复这个过程直到得到一个完整的有序表。归并操作需要额外开辟一个数组,空间复杂度达到线性阶,时间复杂度不管是最好、最坏还是平均复杂度,都要进行趟的归并操作,每趟对个元素进行处理,总的时间复杂度是。
三、外部排序
外部排序用于处理数据量很大无法一次性读入内存的情况。首先在外存中形成多个小的有序表,然后利用外部排序算法将这些有序表合并成一个大的有序表。主要使用二路归并排序的思想,涉及内存里的输入缓冲区和输出缓冲区。通过不断比较两个输入缓冲区中的最小或最大元素,将其选出来放到输出缓冲区中,输出缓冲区装满后写到外存中。在外部排序中重点研究的是 I/O 次数,为了减少 I/O 次数,提出了多路平衡树,但它增加了每次选出关键字的比较次数,于是又引入了败者树。此外还有置换选择排序算法用于减少归并段的个数。同时还介绍了如何求最佳归并数,可类似于哈夫曼树的方法。
希望通过对这些排序算法的学习,大家能对数据结构中的排序有更深入的理解和掌握。不同的排序算法在不同的场景下有各自的优势,我们需要根据实际情况选择合适的排序算法。