Problem A 快速排序
7-1 快速排序
全屏浏览题目切换布局
作者 朱允刚
单位 吉林大学
给定包含n个元素的整型数组a[1],a[2],…,a[n],利用快速排序算法对其进行递增排序,请输出排序过程,即每次Partition之后的数组。每次选择所处理的子数组的第一个元素作为基准元素。
输入格式:
输入为两行,第一行为一个整数n(1<n≤1000),表示数组长度。第二行为n个空格间隔的整数,表示待排序的数组。
输出格式:
输出为若干行,每行依次输出Partition后的数组,每个元素后一个空格。
输入样例:
5
4 5 3 2 1
输出样例:
2 1 3 4 5
1 2 3 4 5
1 2 3 4 5
思路
快速排序算法通过定义基准Pivot,实现了小元素左移、大元素右移,保证了一定程度的递增有序,同时又对左边和右边的子表分别进行一次快速排序,最终实现全局的递增有序。
快速排序的时间复杂度为O(nlogn),不稳定。
根据教材的代码,本题输出样例的第一行结果我是怎么推也推不出来呀。后来去参考借鉴了一下别人的代码,发现原来在Partition划分部分需要直接用Swap函数来交换元素,最后才模拟出了2 1 3 4 5
的结果…总的来说这题的测试样例和对应算法还有待商榷,下面附教材的Partition代码。
int Partition(SqList &S, int low, int high) {
int pivot = low;
while (low < high) {
while (low < high && S.elem[high] > S.elem[pivot])
--high;
S.elem[low] = S.elem[high];
while (low < high && S.elem[low] <= S.elem[pivot])
++low;
S.elem[high] = S.elem[low];
}
S.elem[low] = S.elem[pivot];
return low;
}
代码
#include <bits/stdc++.h>
using namespace std;
typedef struct SqList {
int *elem;
int length;
} SqList;
/// @brief 交换a和b的值
/// @param a
/// @param b
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
} // swap
/// @brief 打印顺序表
/// @param S
void PrintSqList(SqList S) {
for (int i = 1; i <= S.length; i++) {
cout << S.elem[i] << " ";
}
cout << endl;
} // PrintSqList
/// @brief 构建顺序表,根据需要的大小来分配空间
/// @param S
void CreateSqList(SqList &S) {
cin >> S.length;
S.elem = (int *)malloc((S.length + 1) * sizeof(int));
for (int i = 1; i <= S.length; i++) {
cin >> S.elem[i];
}
} // CreateSqList
/// @brief 划分操作,以low所指元素为基准pivot,大于pivot的元素都在右边,否则都在左边
/// @param S
/// @param low
/// @param high
/// @return
int Partition(SqList &S, int low, int high) {
int pivot = low;
// S.elem[0]=S.elem[low];
while (low < high) {
while (low < high && S.elem[high] > S.elem[pivot])
--high;
while (low < high && S.elem[low] <= S.elem[pivot])
++low;
swap(S.elem[low], S.elem[high]);
}
swap(S.elem[low], S.elem[pivot]);
return low;
} // Partition
/// @brief 快速排序
/// @param S
/// @param low
/// @param high
void QSort(SqList &S, int low, int high) {
if (low < high) {
int pivot = Partition(S, low, high);
PrintSqList(S);
QSort(S, low, pivot - 1);
QSort(S, pivot + 1, high);
}
} // QSort
/// @brief 快速排序
/// @param S
void QuickSort(SqList &S) {
QSort(S, 1, S.length);
PrintSqList(S);
} // QuickSort
int main() {
SqList S;
CreateSqList(S);
QuickSort(S);
return 0;
}
Problem B 堆排序
7-2 堆排序
全屏浏览题目切换布局
作者 严华云
单位 湖州师范学院
对n个数,要求用堆排序(最大堆)对其进行排序。
输入格式:
第一行一个n(n<1000)。第二行给出n个数。
输出格式:
输出n行,每行n个数。第一行表示将n个数(将n个数看成一棵树)变成最大堆后的结果,第二行表示将上次结果的根节点交换到现有节点的最后一个节点(然后将除最后一个节点的数看成一颗树),然后将该剩余节点树从新变成最大堆后的结果输出(包括交换到最后的节点),依次类推。
输入样例:
6
7 1 6 4 3 5
输出样例:
7 4 6 1 3 5
6 4 5 1 3 7
5 4 3 1 6 7
4 1 3 5 6 7
3 1 4 5 6 7
1 3 4 5 6 7
思路
要使用堆排序,首先要了解堆的定义。堆分为大根堆和小根堆。在教材里,大根堆的定义就是a[k]>a[2k]&&a[k]>a[2k+1],即双亲大于左右孩子。大根堆排序中每次会将堆中最小的元素上移至根节点,再将其与堆的最后一个元素进行交换,从而得到递增的有序序列。
堆排序的时间复杂度为O(nlogn),不稳定。
代码
#include <bits/stdc++.h>
using namespace std;
typedef struct SqList {
int *elem;
int length;
} SqList;
typedef SqList HeapType;
/// @brief 创建堆
/// @param H
void CreateHeap(HeapType &H) {
cin >> H.length;
H.elem = (int *)malloc((H.length + 1) * sizeof(int));
for (int i = 1; i <= H.length; i++) {
cin >> H.elem[i];
}
} // CreateHeap
/// @brief 打印堆,实际上是打印顺序表的元素
/// @param H
void PrintHeap(HeapType H){
for (int i = 1; i <= H.length; ++i){
cout << H.elem[i] << " ";
}
cout << endl;
} // PrintHeap
/// @brief 调整堆,使其符合堆的定义要求。堆的定义:a[k]>a[2*k] && a[k]>a[2*k+1]
/// @param H
/// @param k
/// @param len
void HeapAdjust(HeapType &H, int k, int len){
H.elem[0] = H.elem[k];
for (int i = 2 * k; i <= len; i *= 2) {
if (i < len && H.elem[i] < H.elem[i + 1]) {
i++;
}
if (H.elem[0] > H.elem[i]) {
break;
} else {
H.elem[k] = H.elem[i];
k=i;
}
}
H.elem[k] = H.elem[0];
} // HeapAdjust
/// @brief 堆排序
/// @param H
void HeapSort(HeapType &H){
for (int i = H.length / 2;i > 0; --i) {
HeapAdjust(H, i, H.length);
}
PrintHeap(H);
for (int i = H.length; i > 1; --i) {
swap(H.elem[1], H.elem[i]);
HeapAdjust(H, 1, i-1);
PrintHeap(H);
}
} // HeapSort
int main() {
HeapType H;
CreateHeap(H);
HeapSort(H);
}