基本概念:
1、 排序:按照一定的关键字,将一个序列排列成想要得到的一个新的序列。
2、 内部排序和外部排序:整个排序过程完全在内存中进行,叫做内部排序。数据量较大需要借助外部存储设备才能完成,叫做外部排序。
3、 主关键字和此关键字:
4、 排序的稳定性:对于相同的元素来说,在排序之前和之后的书讯是一样的,那么这种排序就是稳定的排序,如果顺序发生了变化,那么就是不稳定排序。
1、 思想:反复扫描待排序序列,在扫描的过程中顺次比较相邻的两个元素的大小,若逆序就交换位置。第一趟,从第一个数据开始,比较相邻的两个数据,(以升序为例)如果大就交换,得到一个最大数据在末尾;然后进行第二趟,只扫描前 n-1 个元素,得到次大的放在倒数第二位。以此类推,最后得到升序序列。如果在扫描过程中,发现没有交换,说明已经排好序列,直接终止扫描。所以最多进行 n-1 趟扫描。
2、 时间复杂度:T(n) = O(n²)。
3、 空间复杂度:S(n) = O(1)。
4、 稳定性:稳定排序
static void bubbleSort(int array[], int length) {
for (int i = 0; i < length - 1; i++) {
for (int j = 0; j < length - i - 1; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
print(array, length);
}
}
(2)快速排序
1、 思想:冒泡排序一次只能消除一个逆序,为了能一次消除多个逆序,采用快速排序。以一个关键字为轴,从左从右依次与其进行对比,然后交换,第一趟结束后,可以把序列分为两个子序列,然后再分段进行快速排序,达到高效。
2、 时间复杂度:平均T(n) = O(n㏒n),最坏O(n²)。
3、 空间复杂度:S(n) = O(㏒n)。
4、 稳定性:不稳定排序。{3, 2, 2}
static void quickSort(int array[], int left, int right) {
if (left >= right)
return;
int pivot = array[left];
int i = left;
int j = right;
while (i != j) {
while (array[j] >= pivot && j > i)
j--;
while (array[i] <= pivot && i < j)
i++;
if (i < j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
array[left] = array[i];
array[i] = pivot;
quickSort(array, left, i - 1);
quickSort(array, i + 1, right);
}
(3)堆排序
1、 思想:把待排序记录的关键字存放在数组r[1…n]中,将r看成是一刻完全二叉树的顺序表示,每个节点表示一个记录,第一个记录r[1]作为二叉树的根,一下个记录r[2…n]依次逐层从左到右顺序排列,任意节点r[i]的左孩子是r[2i],右孩子是r[2i+1],双亲是r[i/2向下取整]。然后对这棵完全二叉树进行调整建堆。
2、 时间复杂度:T(n) = O(n㏒n)。
3、 空间复杂度:S(n) = O(1)。
4、 稳定性:不稳定排序。{5, 5, 3}
static void adjustHeap(int array[], int parent, int length, bool large) {
int pivot = array[parent]; //保存当前父节点
int child = 2 * parent + 1; //获取左孩子
while (child < length) {
if (large) {
//大顶堆
//如果有右孩子,且右孩子大于左孩子,选取有孩子节点
if (child + 1 < length && array[child] < array[child + 1])
child++;
// 如果父节点的值已经大于孩子节点的值,则直接结束
if (array[parent] >= array[child])
break;
} else {
//如果有右孩子,且右孩子小于左孩子,选取右孩子节点
if (child + 1 < length && array[child] > array[child + 1])
child++;
//如果父节点的值已经小于孩子节点的值,则直接结束
if (array[parent] < array[child])
break;
}
//把孩子节点的值赋给父节点
array[parent] = array[child];
//选取孩子节点的左孩子节点,继续向下筛选
parent = child;
child = child * 2 + 1;
array[parent] = pivot;
}
}
/*
* 初始化堆
* 调整之后,第一个元素为序列的极值
*/
static void buildHeap(int array[], int length, bool large) {
for (int i = (length - 1) / 2; i >= 0; --i)
adjustHeap(array, i, length, large);
}
(4)直接插入排序
1、 思想:最基本的插入排序,将第i个插入到前i-1个中的适当位置。
2、 时间复杂度:T(n) = O(n²)。
3、 空间复杂度:S(n) = O(1)。
4、 稳定性:稳定排序。循环条件while(r[0].key< r[j].key)保证的。
static void directInsertSort(int array[], int length) {
//升序版本
for (int i = 1; i < length; i++) {
if (array[i] < array[i - 1]) { //找到小数
int j = i - 1;
int pivot = array[i]; //复制小数为哨兵元素
array[i] = array[i - 1]; //先进行一次后移
while (pivot < array[j] && j >= 0) { //寻找小数插入位置
array[j + 1] = array[j];
j--;
}
array[j + 1] = pivot;
}
}
}
(5)希尔排序
1、 思想:又称缩小增量排序法。把待排序序列分成若干较小的子序列,然后逐个使用直接插入排序法排序,最后再对一个较为有序的序列进行一次排序,主要是为了减少移动的次数,提高效率。原理应该就是从无序到渐渐有序,要比直接从无序到有序移动的次数会少一些。
2、 时间复杂度:O(n的1.5次方)
3、 空间复杂度:O(1)
4、 稳定性:不稳定排序。{2,4,1,2},2和1一组4和2一组,进行希尔排序,第一个2和最后一个2会发生位置上的变化。
static void shellSort(int array[], int length) {
int gap = length / 2;
while (gap >= 1) {
//距离间隔gap为一组,遍历所有组
for (int i = gap; i < length; i++) {
if (array[i] < array[i - gap]) {
int j = i - gap;
int x = array[i];
array[i] = array[j];
//寻找x在当前序列上的插入点
while (x < array[j] && j >= 0) {
array[j + gap] = array[j];
j -= gap;
}
array[j + gap] = x;
}
}
print(array, length);
gap /= 2;
}
}
(6) 归并排序:
1、 思想:假设初始序列右n个记录,首先将这n个记录看成n个有序的子序列,每个子序列的长度为1,然后两两归并,得到n/2向上取整 个长度为2(n为奇数时,最后一个序列的长度为1)的有序子序列。在此基础上,在对长度为2的有序子序列进行两两归并,得到若干个长度为4的有序子序列。如此重复,直至得到一个长度为n的有序序列为止。
2、 时间复杂度:T(n) = O(n㏒n)。
3、 空间复杂度:S(n) = O(n)。
4、 稳定性:稳定排序。
static void mergeSort(int array[], int helper[], int left, int right) {
if (left >= right)
return;
int mid = (left + right) / 2;
mergeSort(array, helper, left, mid);
mergeSort(array, helper, mid + 1, right);
int helperLeft = left;
int helperRight = mid + 1;
int cur = left;
for (int i = left; i <= right; i++) {
helper[i] = array[i];
}
while (helperLeft <= mid && helperRight <= right) {
if (helper[helperLeft] <= helper[helperRight])
array[cur++] = helper[helperLeft++];
else
array[cur++] = helper[helperRight++];
}
while (helperLeft <= mid)
array[cur++] = helper[helperLeft++];
}