排序

参考:十大经典排序算法(动图演示)

对同一个顺序表使用不同的排序方法进行排序,得到的排序结果可能不同(稳定和不稳定)

对于 $n$ 个元素使用 $m$ 路做归并排序,所需趟数为 $\lceil log_mn \rceil$

将两个各有$n$个元素的有序表归并成一个有序表,最少比较$n$次,最多比较$2n-1$次。

1 2 3 4 5 和 6 7 8 9 10 需要比较5次
1 3 5 7 9 和 2 4 6 8 10 需要比较9次

游戏规则和遍历代码

const int N = 10;
int VALS[N] = { 34,1,4,0,73,34,87,45,111,14 };
int vals[N];


int turnNum;
template<class T>
void PrintArray(T Data[], int n) {
	cout << "第" << ++turnNum << "趟" << " : ";
	for (int i = 0; i != n; i++) cout << Data[i] << " ";
	cout << endl;
}

//void xxSort(...){}

int main() {
	for (int i = 0; i != N; i++) cout << VALS[i] << " ";
	cout << endl << endl;

	memcpy(vals, VALS, sizeof(VALS));
	turnNum = 0;
	cout << "xx排序:" << endl;
	xxSort(...);
	cout << endl << endl;
    
    return 0;
}

直接插入排序

保持前面的序列有序,每次把当前元素插入前面的有序序列中。

折半插入排序

保持前面的序列有序,每次把当前元素插入前面的有序序列中。

因为前面的序列有序,所以可以用二分。但是空位仍然需要一个一个移动,时间复杂度在数量级上没有改变。

希尔排序

希尔排序保持每隔$d$个元素有序,$d$由大到小变化,当$d$为1并且排完时就排好了。

以上三种排序都属于插入排序,特点是需要把位置一个一个挪出来。

冒泡排序

对于当前元素对,前后顺序反了就调换,再进行下一对,做$n$轮。(如果某一轮没调换可以提前结束)

快速排序

快速排序使用递归分割序列,对每一个序列,使用 Partition 操作,即把比轴小的元素分到轴左边,大的分右边。再递归。最坏情况下,是整个序列都已经有序且完全倒序 ,此时,快速排序退化为冒泡排序,要比较n*(n-1)/2次才能完成

以上两种排序都属于交换排序,特点是需要元素交换 Swap 操作

直接选择排序

每次选择最小的放前面。

堆排序

归并排序

将两个有序子数组归并为有序的完整数组

基数排序

杂题思路

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

  • 思路1:桶排序(如果nums范围较小)

  • 思路2:用一个小顶堆,只有k个节点,比堆顶大的数据就入这个堆,把堆顶淘汰,比堆顶小的数据直接扔掉,这样走一遍,只剩下前k个最大的数据,堆顶就是 第k大的数据。

最后更新于