给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。
本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下:
输入第一行给出正整数N(≤105),随后一行给出N个(长整型范围内的)整数,其间以空格分隔。
在一行中输出从小到大排序后的结果,数字间以1个空格分隔,行末不得有多余空格。
11
4 981 10 -17 0 -20 29 50 8 43 -5
-20 -17 -5 0 4 8 10 29 43 50 981
把所有提到的排序都尝试复现一遍(才发现自己啥也不会)
在未排序序列中选出最小元素和序列首位元素交换,剩下来的序列以此类推
#include
#include
#define MAX_NUM 100005
int Data[MAX_NUM];
void Swap(int* data1, int* data2) {
int temp = *data1;
*data1 = *data2;
*data2 = temp;
return;
}
void SimpleSelectionSort(int num, int data[]) {
int minIndex;
for(int i = 0; i < num - 1; i++) {
minIndex = i;
for(int j = i + 1; j < num; j++) {
if(data[j] < data[minIndex]) {
minIndex = j;
}
}
Swap(&data[i], &data[minIndex]);
}
return;
}
int main() {
int num;
scanf("%d", &num);
for(int i = 0; i < num; i++) {
scanf("%d", &Data[i]);
}
SimpleSelectionSort(num, Data);
for(int i = 0; i < num; i++) {
printf("%d", Data[i]);
if(i != num - 1) printf(" ");
}
return 0;
}
首先将一个无序的序列生成最大堆,从树的倒数第二排最右边开始,下标是节点总数/2-1,然后依次递减1,不断将以当前下标为根节点的子树调整为最大堆
调整过程为下滤
接着不需要将堆顶元素输出,而是将堆顶元素与当前堆的最后一个元素交换位置,交换完位置后再将大小减1的堆重新调整成最大堆,重复上述过程,原来保存最大堆的数组就转换为一个从小到大的序列
/*堆排序建立堆的时候,
相对于之前建立堆是插入,
这个是在一堆无序的数字上建立
*/
#include
#include
#define MAX_NUM 100005
int Data[MAX_NUM];
void Swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
return;
}
void PercDown(int data[], int root, int num) { //建立最大堆和从最大堆中弹出最大值,核心部分都是下滤
//相对与之前的最大堆算法,本题特殊之处在于用于存储最大堆的数组不是从下标1开始,0做哨兵,而就是从0开始
int parent, child;
int tmp = data[root];
//从root开始,遍历数组,比较当前值和左右子节点,若当前值大于左右子节点,则交换当前值和左右子节点的值,并重新调整最大堆
for(parent = root; parent * 2 + 1 < num; parent = child) {
child = parent * 2 + 1;
if((child!= num - 1) && (data[child] < data[child + 1])) {
child++;
}
if(tmp >= data[child]) {
break;
}
else {
data[parent] = data[child];
}
}
data[parent] = tmp;
return;
}
void HeapSort(int data[], int num) {
//建立最大堆
for(int i = num / 2 - 1; i >= 0; i--) {
PercDown(data, i, num);
}
//删除最大堆顶
for(int i = num - 1; i > 0; i--) {
Swap(&data[0], &data[i]);
PercDown(data, 0, i);
}
}
int main() {
int num;
scanf("%d", &num);
for(int i = 0; i < num; i++) {
scanf("%d", &Data[i]);
}
HeapSort(Data, num);
for(int i = 0; i < num; i++) {
printf("%d", Data[i]);
if(i != num - 1) {
printf(" ");
}
}
return 0;
}
将序列分为已排和未排,每次从未排中取一个与已排比较直到合适位置后插入,重复上述过程,直到没有未排序列
#include
#include
#define MAX_NUM 100005
int Data[MAX_NUM];
void SimpleInsertSort(int data[], int num) {
for(int i = 1; i < num; i++) {
int tmp = data[i]; //取出未排序列中第一个元素
int j = i;
for(; j > 0 && data[j - 1] > tmp; j--) { //依次与已排序列从末尾往前比
data[j] = data[j - 1];
}
data[j] = tmp; //将未排序列第一个元素插入到已排序列合适位置
}
return;
}
int main() {
int num;
scanf("%d", &num);
for(int i = 0; i < num; i++) {
scanf("%d", &Data[i]);
}
SimpleInsertSort(Data, num);
for(int i = 0; i < num; i++) {
printf("%d", Data[i]);
if(i != num - 1) {
printf(" ");
}
}
return 0;
}
通过将待排序的一组元素按一定间隔分为若干个序列,分别进行插入排序;最终间隔是1
往往用Sedgewick作为增量序列
void ShellSort(int data[], int num) {
//定义一个增量数组
int i;
int sedgewick[] = {929, 505, 209, 109, 41, 19, 5, 1, 0};
//在sedgewick序列中找到比num小的增量,因为初始的增量sedgewick[i]不能超过待排序列长度
for(i = 0; sedgewick[i] >= num; i++) //在sedgewick序列中找到比num小的增量,因为初始的增量sedgewick[i]不能超过待排序列长度
;
for(int interval = sedgewick[i]; interval > 0; interval = sedgewick[++i]) {
//插入排序
//比较难以理解,首先从一个intervel以后开始选择,因为下标0~intervel-1是分别intervel的第一个(第一个又是已排序列)
for(int j = interval; j < num; j++) {
int tmp = data[j]; //取出未排序列中第一个元素
int k = j;
//依次将其已排序元素进行比较
for(; k >= interval && data[k - interval] > tmp; k -= interval) { //依次与已排序列从末尾往前比
data[k] = data[k - interval];
}
data[k] = tmp; //将未排序列的第一个元素插入到已排序列中合适位置
}
}
}
外层循环从待排序列最后一位往前依次确定,内层循环从前往后扫描两两比较取最大
减少循环的一个方法是每层循环设置一个flag,如果从头至尾扫描循环都没有交换,说明当前序列已经有序,可以break了
#include
#define MAX_NUM 100005
#define bool int
#define TRUE 1
#define FALSE 0
int Data[MAX_NUM];
void Swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
return;
}
void BubbleSort(int data[], int num) {
for(int i = num - 1; i >= 0; i--) { //依次从下标num - 1开始往前定位
bool flag = FALSE; //标记该次循环中是否发生交换,若无,说明该序列已经有序
for(int j = 0; j < i; j++) {
if(data[j] > data[j + 1]) {
Swap(&data[j], &data[j + 1]);
flag = TRUE;
}
}
if(flag == FALSE) {
break;
}
}
return;
}
int main() {
int num;
scanf("%d", &num);
for(int i = 0; i < num; i++) {
scanf("%d", &Data[i]);
}
BubbleSort(Data, num);
for(int i = 0; i < num; i++) {
printf("%d", Data[i]);
if(i != num - 1) {
printf(" ");
}
}
return 0;
}
快速排序的思路是通过分治法,首先取一个pivot基准值,将大于pivot的都移到右边,小于它的都移到左边,将一个序列分成两个序列,然后将这两个序列分别重复上述操作
具体实现:
首先为了减少时间复杂度,要考究选择的pivot,方法是将最左边,最右边和中间(left + right)/2按最左边<=中间<=最右边,因为这样排序后最左边必定比中间小,最右边必定比中间大,将中间的值移动到最右边倒数第二个后,比较范围只用从最左边下标+1到最右边下标-2
另一个优化是因为递归针对较大数据还好,但对于较小数据就很慢,所以临设一个cutoff变量,当前序列大小比这个大就用快排,如果小就直接用简单插入排序
但发现这个cutoff最小必须设为2,再小就报错了,目前还没想出来是为什么
#include
#define TRUE 1
#define FALSE 0
#define MAX_NUM 100005
typedef int bool;
int Data[MAX_NUM];
int Cutoff = 3;
void Swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
return;
}
/*实现简单插入排序*/
void SimpleInsertSort(int data[], int left, int right) {
for(int i = left + 1; i <= right; i++) {
int tmp = data[i];
int j = i;
for(; j > left && data[j - 1] > tmp; j--) {
data[j] = data[j - 1];
}
data[j] = tmp;
}
return;
}
/*下面函数作用是确定快排中主元,将最左边、最右边、中间元素调整为
最左边 <= 中间 <= 最右边,此时最左边一定小于中间,最右边一定大于等于中间,这两个所以就不用考虑了
将中间的主元放到右边倒数第二个位置,下面就只用比较左边第二个到右边倒数第三个位置的范围就行*/
int CompareThreeNums(int data[], int left, int right) {
int mid = (left + right) / 2;
int max = data[left];
if(data[left] > data[mid]) {
Swap(&data[left], &data[mid]);
}
if(data[left] > data[right]) {
Swap(&data[left], &data[right]);
}
if(data[mid] > data[right]) {
Swap(&data[mid], &data[right]);
}
Swap(&data[mid], &data[right - 1]);
return data[right - 1];
}
void QuickSortCore(int data[], int left, int right) {
if(Cutoff <= right - left) {
int pivot = CompareThreeNums(data, left, right);
int low = left;
int high = right - 1;
while(TRUE) {
while(data[++low] < pivot) ;
while(data[--high] > pivot) ;
if(low < high) {
Swap(&data[low], &data[high]);
}
else {
break;
}
}
Swap(&data[low], &data[right - 1]); //将基准换到正确位置
QuickSortCore(data, left, low - 1); //对基准左边序列递归
QuickSortCore(data, low + 1, right); //对基准右边序列递归
}
else {
SimpleInsertSort(data, left, right); //对序列进行简单插入排序
}
return;
}
void QuickSort(int data[], int num) {
QuickSortCore(data, 0, num - 1);
return;
}
int main() {
int num;
scanf("%d", &num);
for(int i = 0; i < num; i++) {
scanf("%d", &Data[i]);
}
QuickSort(Data, num);
for(int i = 0; i < num; i++) {
printf("%d", Data[i]);
if(i != num - 1) {
printf(" ");
}
}
return 0;
}