555数据结构考试
总结
列表比较
时间复杂度 | 额外空间复杂度 | |
---|---|---|
插入排序 | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) |
希尔排序 | O ( n 1.5 ) O(n^{1.5}) O(n1.5) | O ( 1 ) O(1) O(1) |
冒泡排序 | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) |
快速排序 | O ( n log n ) O(n\log n) O(nlogn) | O ( n log n ) O(n\log n) O(nlogn) |
简单选择排序 | O ( n 2 ) O(n^2) O(n2) | O ( 1 ) O(1) O(1) |
堆排序 | O ( n log n ) O(n\log n) O(nlogn) | O ( 1 ) O(1) O(1) |
归并排序 | O ( n log n ) O(n\log n) O(nlogn) | O ( n ) O(n) O(n) |
桶排序 | O ( n ) O(n) O(n) | O ( k ) O(k) O(k) |
计数排序 | O ( n + k ) O(n+k) O(n+k) | O ( n + k ) O(n+k) O(n+k) |
基数排序 | O ( d n ) O(dn) O(dn) |
稳定性
不稳定的:希尔排序、选择排序、快速排序、堆排序
最坏情况
希尔排序
快速排序在元素有序时退化到 O ( n 2 ) O(n^2) O(n2)
最好情况
插入排序、希尔排序、冒泡排序最好 O ( n ) O(n) O(n)
排序算法
插入排序
- 时间复杂度 O ( n 2 ) O(n^2) O(n2)
- 流程:依次选择未排序元素,在已排好序的数组中从左到右找到应放置的位置,整体移动在它后面的元素。
希尔排序
- 增量 d d d ,每次排序 a [ i ] , a [ i + d ] , a [ i + 2 d ] , . . . a[i],a[i+d],a[i+2d],... a[i],a[i+d],a[i+2d],... ,每轮结束后缩小增量,常采取 d / = 2 d/=2 d/=2
- 增量序列决定了复杂度
- 时间复杂度平均 O ( n 1.5 ) O(n^{1.5}) O(n1.5)
冒泡排序
- 以小到大排序为例,第 n − j + 1 n-j+1 n−j+1 轮会将序列 a [ 1... j ] a[1...j] a[1...j] 中最大的元素移动到 a [ j ] a[j] a[j] 的位置上, n n n 轮后完成排序。
- 优化:设置一个flag,如果一轮中没有进行元素交换,说明已经有序,退出
- 时间复杂度 O ( n 2 ) O(n^2) O(n2)
// a[1...n]
for(int j = n; j > 0; j--)
for(int i = 1; i < j; i++)
if(a[i] > a[i + 1])
swap(a[i], a[i + 1]);
// 优化:设置一个flag,如果一轮中没有进行元素交换,说明已经有序,退出
for(int j = n, flag = true; j > 0 && flag; j--)
{
flag = false;
for(int i = 1; i < j; i++)
if(a[i] > a[i + 1])
{
swap(a[i], a[i + 1]);
flag=true;
}
}
快速排序
- 待排序序列中选取一个枢轴元素 p i v o t pivot pivot ,将数组中 < p i v o t <pivot <pivot 的元素放在左边,大于的放在右边, p i v o t pivot pivot 放在数组中间
- 常选用第一个元素作为 p i v o t pivot pivot
- 递归排序 p i v o t pivot pivot 左边部分和 p i v o t pivot pivot 右边部分
- 平均 O ( n log n ) O(n\log n) O(nlogn) ,最坏是数组有序的情况,退化到 O ( n 2 ) O(n^2) O(n2)
简单选择排序
- 选择未排序区间最大的元素,放到已排序区间的开头
- 时间复杂度 O ( n 2 ) O(n^2) O(n2)
堆排序
- 小根堆&大根堆的概念
- 建堆: a [ 1... i ] , i + + a[1...i],i++ a[1...i],i++ 建堆 or a [ i . . . n ] , i − − a[i...n],i-- a[i...n],i−− 建堆
- 每次取出堆顶元素,将堆顶和堆底元素调换,删去堆底(堆的大小–),调整堆
- O ( n log n ) O(n\log n) O(nlogn)
- 不稳定
- 应用:优先队列、找最小/最大的m个元素
归并排序
- 递归排序数组的一个个部分,再将排序好的部分合起来,需要 O ( n ) O(n) O(n) 的额外空间
- O ( n log n ) O(n\log n) O(nlogn)
void merge_sort(int *x, int *y, int l, int r)
{
if (l + 1 >= r)
return;
int m = l + ((r - l) >> 1), p = l, q = m, i = l;
merge_sort(x, y, l, m);
merge_sort(x, y, m, r);
while (p < m || q < r)
{
if (q >= r || (p < m && x[p] <= x[q]))
t[i++] = a[p++];
else
t[i++] = a[q++];
}
for (i = l; i < r; i++)
a[i] = t[i];
}
桶排序
- 有序的桶,将数据放入这些桶,然后桶内部排序
计数排序
- 将元素看成桶, O ( n ) O(n) O(n) 扫描数组,每扫描一个元素,就向桶里丢一个+1
- 元素若不是int或太大需要一个映射
- 只能用于元素种类少的情况
基数排序
- 按关键字排序,每个关键字排序一次,所得的序列就是按第一关键字->第二关键字…排好序的序列。
- 时间复杂度 O ( d n ) O(dn) O(dn) , d d d 是关键字个数,一般这些关键字都能近线性排序