注意:允许转载,但转载请注明作者和出处
最重要:复习插入排序和堆排序
插入排序
1. 通过交换的方式进行插入排序
// 方法1:通过交换的方式进行插入排序
#include <iostream>
using namespace std;
const int N = 1010;
int a[N];
int n;
void insert_sort(int a[]) // 更简单
{
// 栗子:5 2 4 1 3
// 手动模拟如下:
// 2 5 4 1 3
// 2 4 5 1 3
// 1 2 4 5 3
// 1 2 3 4 5
// 从头到尾遍历一遍元素(a[1]~a[n-1]),
// 表示这些元素需要一遍遍重新排列,且是通过交换的方式去实现
// 怎么通过交换的方式?
// 从当前待排列元素的前一个元素开始,每次比较一下这俩元素
// 若前面一个元素大于后面元素,就交换一下
for (int i = 1; i < n; i ++)
{
int p = i - 1;
// 不设置哨兵,而采用交换的方式来进行插入排序
while (p >= 0 && a[p] > a[p + 1])
{
swap(a[p], a[p + 1]);
p --;
}
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++) cin >> a[i];
insert_sort(a);
for (int i = 0; i < n; i ++) cout << a[i] << ' ';
puts("");
return 0;
}
2. 通过设置哨兵进行插入排序
// 方法2:通过设置哨兵进行插入排序
// 版本1:数组下标从0开始
#include <iostream>
using namespace std;
const int N = 1010;
int a[N];
int n;
void insert_sort(int a[]) // 复杂,不推荐
{
// 栗子:5 2 4 1 3
// 2 5 4 1 3
// 2 4 5 1 3
// 1 2 4 5 3
// 1 2 3 4 5
for (int i = 1; i < n; i ++)
{
int x = a[i];
//cout << x << endl;
int j = i - 1;
for (; j >= 0; j --)
{
if (a[j] > x) a[j + 1] = a[j];
else break;
}
a[j + 1] = x;
// for (int j = 0; j < n; j ++) cout << a[j] << ' ';
// puts("");
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++) cin >> a[i];
insert_sort(a);
for (int i = 0; i < n; i ++) cout << a[i] << ' ';
puts("");
return 0;
}
// 版本2:数组下标从1开始
#include <iostream>
using namespace std;
const int N = 1010;
int a[N];
int n;
void insert_sort(int a[])
{
for (int i = 2; i <= n; i ++)
{
int x = a[i];
int j;
for (j = i - 1; j; j --)
{
if (a[j] > x) a[j + 1] = a[j];
else break;
}
a[j + 1] = x;
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
insert_sort(a);
for (int i = 1; i <= n; i ++) cout << a[i] << ' ';
return 0;
}
堆排序
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int n, m;
void down(int u, int cnt) // 结点不断下坠
{
int t = u;
if (2 * u <= cnt && a[2 * u] > a[t]) t = 2 * u;
if (2 * u + 1 <= cnt && a[2 * u + 1] > a[t]) t = 2 * u + 1;
if (t != u)
{
swap(a[t], a[u]);
down(t, cnt);
}
}
void heap_sort(int a[], int n)
{
// 建立大根堆的过程
// 大根堆:从小到大;小根堆:小大到小
for (int i = n / 2; i >= 1; i --) down(i, n);
// 堆排序的过程
int cnt = n;
for (int i = n; i > 1; i --)
{
swap(a[i], a[1]);
cnt --;
down(1, cnt);
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> a[i];
heap_sort(a, n);
for (int i = 1; i <= m; i ++) cout << a[i] << ' ';
return 0;
}
AcWing 1588. 插入还是堆排序
题目
解析
注意:插入排序在排序过程中,前面k个元素保持有序,但是后面元素与初始序列完全一致
而堆排序,若根据大根堆进行排序,则最后面几个元素是有序的,前面元素是混乱的、与初始序列不一定相同
答案
#include <iostream>
using namespace std;
const int N = 110;
int a[N], b[N];
int n;
void down(int u, int cnt)
{
int t = u;
if (2 * u <= cnt && b[2 * u] > b[t]) t = 2 * u;
if (2 * u + 1 <= cnt && b[2 * u + 1] > b[t]) t = 2 * u + 1;
if (t != u)
{
swap(b[t], b[u]);
down(t, cnt);
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= n; i ++) cin >> b[i];
int p = 2;
while (p <= n && b[p] >= b[p - 1]) p ++;
int t = p;
while (t <= n && a[t] == b[t]) t ++;
// cout << p << ' ' << t << endl;
if (t == n + 1)
{
puts("Insertion Sort");
int k = p;
while (k >= 2 && b[k] < b[k - 1])
{
swap(b[k], b[k - 1]);
k --;
}
for (int i = 1; i <= n; i ++) cout << b[i] << ' ';
}
else
{
// 大根堆:升序
puts("Heap Sort");
int cnt = n;
while (b[1] <= b[cnt]) cnt --;
swap(b[1], b[cnt]);
// 注意相当于是又有一个元素排好了顺序,
// 所以当前未排序的元素个数再-1
down(1, cnt - 1);
for (int i = 1; i <= n; i ++) cout << b[i] << ' ';
}
return 0;
}