数据结构课设——排序综合(C语言)
题目
利用随机函数产生N个随机整数(20000以上),对这些数进行多种方法进行排序。
要求:
- 至少采用四种方法实现上述问题求解(提示,可采用的方法有插入排序、希尔排序、冒泡排序、快速排序、选择排序、堆排序、归并排序)。并把排序后的结果保存在不同的文件中。
- 统计每一种排序方法的性能(以上机运行程序所花费的时间为准进行对比,),找出其中两种较快的方法。
本程序中用到了6种排序方法。
随机数的生成
srand((unsigned)time(NULL));
srand
用来初始化随机种子,会提供一个种子,这个种子会对应一个随机数。
为了防止随机数每次重复,这里使用系统时间来作为随机种子。
1.插入排序
步骤
- 从第一个元素开始,该元素可以认为已经被排序
- 取下一个元素
temp
,从已排序的元素序列从后往前遍历 - 如果该元素大于
temp
,则将该元素移到下一位 - 重复步骤3,直到找到已排序元素中小于等于
temp
的元素 temp
插入到元素的后面,如果已排序的元素都大于temp
,则将temp
插入到下标为0的位置- 重复步骤2~5
动图演示如下:
void insertSort()
{
for (int i = 1; i < CAPACITY; i++)
{
int temp = array[i];
int j = i - 1;
while (j >= 0)
{
//说明前面已经有序了
if (array[j] <= temp)
{
break;
}
//移动j的值到j+1
array[j + 1] = array[j];
j--;
}
array[j + 1] = temp;
}
}
- 时间复杂度:最坏情况:O( N 2 N^2 N2),最好情况 O(N)
- 空间复杂度:O(1)
- 稳定性:稳定
2.希尔排序
希尔排序又称缩小增量法
步骤
- 先定义一下分组个数gap
- 把整个数组分成gap个组,每个组里有
CAPACITY/gap
个元素 - 把每个小组分别用插入方式排序
- 逐渐缩小这个gap,直到gap=1时,全部排序完成
void shellSort()
{
int gap = CAPACITY / 2;
while (gap > 0)
{
shell( gap);
gap /= 2;
}
}
//核心代码
void shell( int gap)
{
for (int i = gap; i < CAPACITY; i++)
{
int temp = array[i];
int j = i - gap;
while (j >= 0)
{
if (array[j] <= temp)
{
break;
}
array[j + gap] = array[j];
j -= gap;
}
array[j + gap] = temp;
}
}
- 时间复杂度:O( N 1.25 N^{1.25} N1.25) ~ O( N 1.5 N^{1.5} N1.5)
- 空间复杂度:O(1)
- 稳定性:不稳定
3.冒泡排序
左边大于右边交换一趟排下来最大的在右边
void bubbleSort()
{
for (int i = 0; i < CAPACITY - 1; i++) {
int set = 0;
for (int j = 0; j < CAPACITY - 1 - i; j++)
{
if (array[j] > array[j + 1])
{
swap(j, j + 1);
set = 1;
}
}
if (set==0)
{
break;
}
}
}
void swap(int left, int right)
{
int temp = array[left];
array[left] = array[right];
array[right] = temp;
}
- 时间复杂度:O( N 2 N^2 N2)
- 空间复杂度:O(1)
- 稳定性:稳定
4.快速排序
挖坑法找基准
left
下标的值当做默认的基准值,这时left
的位置就空出来了right
向左移动,找到比基准值小的值,放到left
的位置left
向右移动,找到比基准值大的值,放到right
的位置- 当
left
与right
相遇时,把之前记录的基准值放在相遇的下标- 返回相遇点下标,这就是基准的下标
//快速排序
void quickSort()
{
const int N = 1e2;
start = clock();
quickSortProcess(0, CAPACITY - 1);
end = clock();
printf("time: %f s\n", ((double)(end - start)) / CLOCKS_PER_SEC / N);
}
//核心代码
void quickSortProcess(int left, int right)
{
if (left>=right)
{
return;
}
//找基准
int pivot= partitionHole(left, right);
quickSortProcess(left, pivot);
quickSortProcess( pivot+1,right);
}
int partitionHole(int left, int right)
{
int pivotValue = array[left];
while (left < right)
{
while (right > left && array[right] >= pivotValue)
{
right--;
}
array[left] = array[right];
while (left < right && array[left] <= pivotValue)
{
left++;
}
array[right] = array[left];
}
array[left] = pivotValue;
return left;
}
时间复杂度:O(N* l o g N logN logN)
空间复杂度:O( l o g N logN logN)
稳定性:不稳定
5.选择排序
步骤
- 定义数组边界,
left=0,right=CAPACITY-1
- 定义
i
用来遍历- 定义最小值下标
minIndex=left,maxIndex=left
- 在
i
遍历的过程中,找到比最小值小的元素更新minIndex
,找到比最大值大的元素更新maxIndex
- 一轮遍历完成后,
left
与minIndex
交换,right与maxIndex
交换- 循环终止条件是
left<rigth
//选择排序
void selectSort()
{
int left = 0;
int right = CAPACITY - 1;
while (left < right)
{
int minIndex = left;
int maxIndex = left;
//找最大值和最小值
for (int i = left + 1; i <= right; i++)
{
if (array[i] < array[minIndex])
{
minIndex = i;
}
if (array[i] > array[maxIndex])
{
maxIndex = i;
}
}
if (left != minIndex)
{
swap(left, minIndex);
}
if (left == maxIndex)
{
minIndex = maxIndex;
}
if (right != maxIndex)
{
swap(right, maxIndex);
}
left++;
right--;
}
}
- 时间复杂度:O( N 2 N^2 N2)
- 空间复杂度:O(1)
- 稳定性:不稳定
6.归并排序
步骤
把大数组分解成若干个小数组
把小数组做归并操作,并在归并的过程中完成排序
- 在归并的过程中,需要用到一个临时数组来存储排序好的数据,那么这个数组的容量为
right-left+1
- 确定每个小数组的开始与结束下标
- 合并两个数组,合并的方法可以参考合并有序数组的过程
- 两个数组都不为空的情况下,比当前位置元素的大小,小的那一个直接加入到临时数组里
- 如果两个数组的元素个数不一样多,那么就要处理有剩余元素的数组,直接把剩余元素追加到临时数组里
把临时数组中排序好的元素,覆盖到原数组对应的下标
//归并排序
void mergeSort()
{
mergeSortProcessor( 0, CAPACITY - 1);
}
void mergeSortProcessor(int left, int right)
{
//1、终止条件
if (left >= right) {
return;
}
//2、找中间下标
int mid = (left + right) / 2;
//3、分解左右区段
mergeSortProcessor( left, mid);
mergeSortProcessor( mid + 1, right);
//4、合并
marge( left, mid, right);
}
void marge(int left, int mid, int right)
{
//1、创建临时数组
//int n = (right - left + 1);
int *temp=(int*)malloc((right - left + 1)*sizeof(int));
int index = 0;
//2、确定每个小数组的下标
int start1 = left;
int end1 = mid;
int start2 = mid + 1;
int end2 = right;
//3、合并
while (start1 <= end1 && start2 <= end2) {
if (array[start1] < array[start2]) {
temp[index++] = array[start1++];
}
else {
temp[index++] = array[start2++];
}
}
//剩余元素添加到temp中
while (start1 <= end1) {
temp[index++] = array[start1++];
}
while (start2 <= end2) {
temp[index++] = array[start2++];
}
//4、temp写到原数组中
for (int i = 0; i < index; i++) {
array[i + left] = temp[i];
}
free(temp);
temp = NULL;
}
- 时间复杂度:O(N* l o g N logN logN)
- 空间复杂度:O(N)
- 稳定性:稳定
完整代码
sort.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#define CAPACITY 20000
int array[CAPACITY];
clock_t start, end;
void initArray();
void save(char* name1);
void dispaly();
void swap(int i, int minIndex);
//插入排序
void insertSort();
//希尔排序
void shellSort();
void shell(int gap);
//冒泡排序
void bubbleSort();
//快速排序
void quickSort();
void quickSortProcess(int left, int right);
int partitionHole(int left, int right);
//选择排序
void selectSort();
//归并排序
void mergeSort();
void mergeSortProcessor(int left, int right);
void marge(int left, int mid, int right);
sort.c
#include"sort.h"
void initArray()
{
srand((unsigned)time(NULL));
for (int i = 0; i < CAPACITY; i++)
{
array[i] = rand();
}
}
void save(char* name1)
{
FILE* fp;
char* name2 = ".txt";
char* name = (char*)malloc(strlen(name1) + strlen(name2));
strcpy(name, name1);
strcat(name, name2);
fp = fopen(name, "w");
int count = 0;
for (int i = 0; i < CAPACITY; i++)
{
fprintf(fp, "%6d", array[i]);
count++;
if (count%100==0)
{
fprintf(fp, "\n");
}
}
fclose(fp);
}
void dispaly()
{
int count = 0;
for (int i = 0; i < CAPACITY; i++)
{
printf("%6d", array[i]);
count++;
if (count % 20 == 0)
{
printf("\n");
}
}
printf("\n");
}
//插入排序
void insertSort()
{
const int N = 1e2;
start = clock();
for (int i = 1; i < CAPACITY; i++)
{
int temp = array[i];
int j = i - 1;
while (j >= 0)
{
//说明前面已经有序了
if (array[j] <= temp)
{
break;
}
//移动j的值到j+1
array[j + 1] = array[j];
j--;
}
array[j + 1] = temp;
}
end = clock();
printf("time: %f s\n", ((double)(end - start)) / CLOCKS_PER_SEC / N);
}
//希尔排序
void shellSort()
{
const int N = 1e2;
start = clock();
int gap = CAPACITY / 2;
while (gap > 0)
{
shell( gap);
gap /= 2;
}
end = clock();
printf("time: %f s\n", ((double)(end - start)) / CLOCKS_PER_SEC / N);
}
void shell( int gap)
{
for (int i = gap; i < CAPACITY; i++)
{
int temp = array[i];
int j = i - gap;
while (j >= 0)
{
if (array[j] <= temp)
{
break;
}
array[j + gap] = array[j];
j -= gap;
}
array[j + gap] = temp;
}
}
void swap(int left, int right)
{
int temp = array[left];
array[left] = array[right];
array[right] = temp;
}
//冒泡排序
void bubbleSort()
{
const int N = 1e2;
start = clock();
for (int i = 0; i < CAPACITY - 1; i++) {
int set = 0;
for (int j = 0; j < CAPACITY - 1 - i; j++)
{
if (array[j] > array[j + 1])
{
swap(j, j + 1);
set = 1;
}
}
if (set==0)
{
break;
}
}
end = clock();
printf("time: %f s\n", ((double)(end - start)) / CLOCKS_PER_SEC / N);
}
//快速排序
void quickSort()
{
const int N = 1e2;
start = clock();
quickSortProcess(0, CAPACITY - 1);
end = clock();
printf("time: %f s\n", ((double)(end - start)) / CLOCKS_PER_SEC / N);
}
//核心代码
void quickSortProcess(int left, int right)
{
if (left>=right)
{
return;
}
//找基准
int pivot= partitionHole(left, right);
quickSortProcess(left, pivot);
quickSortProcess( pivot+1,right);
}
int partitionHole(int left, int right)
{
int pivotValue = array[left];
while (left < right)
{
while (right > left && array[right] >= pivotValue)
{
right--;
}
array[left] = array[right];
while (left < right && array[left] <= pivotValue)
{
left++;
}
array[right] = array[left];
}
array[left] = pivotValue;
return left;
}
//选择排序
void selectSort()
{
const int N = 1e2;
start = clock();
int left = 0;
int right = CAPACITY - 1;
while (left < right)
{
int minIndex = left;
int maxIndex = left;
//找最大值和最小值
for (int i = left + 1; i <= right; i++)
{
if (array[i] < array[minIndex])
{
minIndex = i;
}
if (array[i] > array[maxIndex])
{
maxIndex = i;
}
}
if (left != minIndex)
{
swap(left, minIndex);
}
if (left == maxIndex)
{
minIndex = maxIndex;
}
if (right != maxIndex)
{
swap(right, maxIndex);
}
left++;
right--;
}
end = clock();
printf("time: %f s\n", ((double)(end - start)) / CLOCKS_PER_SEC / N);
}
//归并排序
void mergeSort()
{
const int N = 1e2;
start = clock();
mergeSortProcessor( 0, CAPACITY - 1);
end = clock();
printf("time: %f s\n", ((double)(end - start)) / CLOCKS_PER_SEC / N);
}
void mergeSortProcessor(int left, int right)
{
//1、终止条件
if (left >= right) {
return;
}
//2、找中间下标
int mid = (left + right) / 2;
//3、分解左右区段
mergeSortProcessor( left, mid);
mergeSortProcessor( mid + 1, right);
//4、合并
marge( left, mid, right);
}
void marge(int left, int mid, int right)
{
//1、创建临时数组
//int n = (right - left + 1);
int *temp=(int*)malloc((right - left + 1)*sizeof(int));
int index = 0;
//2、确定每个小数组的下标
int start1 = left;
int end1 = mid;
int start2 = mid + 1;
int end2 = right;
//3、合并
while (start1 <= end1 && start2 <= end2) {
if (array[start1] < array[start2]) {
temp[index++] = array[start1++];
}
else {
temp[index++] = array[start2++];
}
}
//剩余元素添加到temp中
while (start1 <= end1) {
temp[index++] = array[start1++];
}
while (start2 <= end2) {
temp[index++] = array[start2++];
}
//4、temp写到原数组中
for (int i = 0; i < index; i++) {
array[i + left] = temp[i];
}
free(temp);
temp = NULL;
}
main.c
#include"sort.h"
void menu()
{
printf("+===================================+\n");
printf("+ 欢迎使用综合排序系统 +\n");
printf("+ 1.插入排序 +\n");
printf("+ 2.希尔排序 +\n");
printf("+ 3.冒泡排序 +\n");
printf("+ 4.快速排序 +\n");
printf("+ 5.选择排序 +\n");
printf("+ 6.归并排序 +\n");
printf("+ 0.退出程序 +\n");
printf("+===================================+\n");
}
void setting()
{
system("color 0b");
}
int main()
{
setting();
while (1)
{
int select;
//生成随机数组
initArray();
//dispaly();
menu();
printf("请选择需要进行的操作:");
scanf("%d", &select);
switch (select)
{
case 1:
insertSort();
save("插入排序");
system("pause");
system("cls");
break;
case 2:
shellSort();
save("希尔排序");
system("pause");
system("cls");
break;
case 3:
bubbleSort();
save("冒泡排序");
system("pause");
system("cls");
break;
case 4:
quickSort();
save("快速排序");
//dispaly();
system("pause");
system("cls");
break;
case 5:
selectSort();
save("选择排序");
system("pause");
system("cls");
break;
case 6:
mergeSort();
save("归并排序");
system("pause");
system("cls");
break;
case 0:
printf("拜拜,欢迎下次使用.....\n");
return 0;
break;
default:
printf("选择无效,请重新选择!!!\n");
system("pause");
system("cls");
break;
}
}
}