利用随机函数产生30000个随机整数,利用插入排序、起泡排序、选择排序、快速排序、堆排序、归并排序等排序方法进行排序,并统计每一种排序上机所花费的时间。

1、折半插入排序:插入排序的基本插入是在一个有序表中进行查找和插入,这个查找可利用折半查找来实现,即为折半插入排序

2、起泡排序:首先将第一个记录的关键字和第二个记录的关键字进行比较,若为逆序,则将两个记录交换,然后比较第二个记录和第三个记录的关键字。依此类推,直到第N-1和第N个记录的关键字进行过比较为止。上述为第一趟排序,其结果使得关键字的最大纪录被安排到最后一个记录的位置上。然后进行第二趟起泡排序,对前N-1个记录进行同样操作。一共要进行N-1趟起泡排序。

3、快速排序:通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。

4、选择排序:通过N-1次关键字间的比较,i趟排序是后面N-i+1(i=1,2,3,4,........n-1)个元素中选择一个值最小的元素与该 N-i+1个元素的最前门的那个元素交换位置,即与整个序列的第 个元素交换位置。如此下去,直到 i = n - 1,排序结束。简单说就是N-I+1个记录中选出关键字最小的记录,并和第I1<=I<=N)个记录交换。

5、堆排序:在堆排序的算法中先建一个大顶堆,既先选得一个关键字作为最大的记录并与序列中最后一个记录交换,然后对序列中前N-1记录进行选择,重新将它调整成一个大顶堆,如此反复直到排序结束。

6、归并排序:归并排序算法采用的是分治算法,即把两个(或两个以上)有序表合并成一个新的有序表,即把待排序的序列分成若干个子序列,每个子序列都是有序的,然后把有序子序列合并成整体有序序列,这个过程也称为2-路归并。

代码如下所示

头文件为:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include<assert.h>
#include<malloc.h>
#include <time.h>//计时
//#ifndef _CLOCK_T_DEFINED  
//typedef long clock_t;
//#define _CLOCK_T_DEFINED  
//#endif  

#define MAX_SIZE 100000

typedef struct SeqList
{
	int *r;//r[0]闲置
	int length;//顺序表总长度
}SeqList;

enum OP
{
	EXIT,
	INSERT,
	BININSERT,
	BUBBLE,
	QUICK,
	SELECT,
	STACK,
	MERGE,
};

主函数文件为:

#include "SeqList.h"

//建立并初始化线性表
void InitSeqList(SeqList* L)
{
	assert(L);//检验指针有效性
	L->r = (int *)malloc(MAX_SIZE*sizeof(int));//动态分配空间
	if (!L->r)
	{
		printf("开辟空间失败!");
		return;
	}
	L->length = 0;
}
//产生随机数并显示在界面上
void CreateShow(SeqList* L)
{
	assert(L);
	int i = 0, n;
	printf("请输入要排序的元素个数>");
	scanf("%d", &n);
	for (; i <= n; i++)
	{
		L->r[i] = rand();//产生随机数
	}
	printf("\n");
	printf("随机产生了%d个随机数,它们分别是>\n", n);
	for (i = 1; i <= n; i++)
	{
		printf("%8d  ", L->r[i]);
	}
	printf("\n");
	L->length = n;
}
//打印出排序后的数据
void PrintSeqList(SeqList* L)
{
	assert(L);
	printf("数据个数为>%d\n", L->length);
	printf("排序后的数据为(从小到大进行了排序)>\n");
	for (int i = 1; i <= L->length; i++)
	{
		printf("%8d  ", L->r[i]);
	}
	printf("\n");
}
//交换两个数
void swap(int* num1, int* num2)
{
	int temp = *num1;
	*num1 = *num2;
	*num2 = temp;
}
//直接插入排序
void InsertSort(SeqList* L)
{
	assert(L);
	int i, j;
	if (L->length == 0)
	{
		printf("需要排序的数据为空!");
		return;
	}
	for (i = 2; i <= L->length; i++)
	{
		if (L->r[i] < L->r[i - 1])//将L->r[i]插入有序表
		{
			//分析
			//  2 3 8 7 9 5 10(选择r[i]=5,i=6)
			//5 2 3 8 7   9 10
			//5 2 3 8   7 9 10
			//5 2 3   8 7 9 10(大于5的数都后移)
			//  2 3 5 8 7 9 10
			L->r[0] = L->r[i];//设置监视哨
			L->r[i] = L->r[i - 1];
			for (j = i - 2; L->r[0] < L->r[j]; j--)
			{
				L->r[j + 1] = L->r[j];//大于将要插入数的数后移
			}
			L->r[j + 1] = L->r[0];//插入到正确位置
		}
	}
}
//折半插入排序
void BinInsert(SeqList* L)
{
	assert(L);
	int i, j, mid, low, high;
	if (L->length == 0)
	{
		printf("需要排序的数据为空!");
		return;
	}
	for (i = 2; i <= L->length; i++)
	{//折半查找
		//分析
		//  2 3 8 7 9 5 10(选择r[i]=5,i=6)
		//5 2 3 8 7 9   10
		//5 2 3 8 7 9   10(折半查找结束后,low为2,high为3)
		//5 2 3   8 7 9 10(大于5的数8、7、9都后移)
		//  2 3 5 8 7 9 10
		L->r[0] = L->r[i];//将L->r[0]暂存在L->r[0]
		low = 1;
		high = i - 1;
		while (low <= high)
		{
			mid = low - (low - high) / 2;
			if (L->r[0] < L->r[mid])
			{
				high = mid - 1;//插入到低半部分
			}
			else
			{
				low = mid + 1;//插入到高半部分
			}
		}
		for (j = i - 1; j >= high + 1; j--)
		{
			L->r[j + 1] = L->r[j];
		}
		L->r[high + 1] = L->r[0];//将要插入的数据插入
	}
}
//冒泡排序
void BubbleSort(SeqList* L)
{
	assert(L);
	int i, j, flag;//冒泡排序的优化就是定义一个标志位flag,接近有序时停止冒泡
	if (L->length == 0)
	{
		printf("需要排序的数据为空!");
		return;
	}
	for (j = 1; j <= L->length - 1; j++)//总共比较L->length-1趟
	{
		for (i = 1; i <= L->length - j; i++)//每一趟冒泡出一个最大数
		{
			flag = 0;
			if (L->r[i] > L->r[i + 1])
			{//交换两个数
				swap(&L->r[i], &L->r[i + 1]);
				flag = 1;
			}
		}
		if (flag == 0)
			break;
	}
}
//快速排序(分治递归)
void QuickSort(SeqList* L, int low, int high)
{
	assert(L);
	int mid;
	int left = low;
	int right = high;
	if (L->length == 0)
	{
		printf("要排序的数据为空!");
		return;
	}
	mid = L->r[low - (low - high) / 2];//选取的参照中间值
	do
	{
		while (L->r[left] < mid && left < high)//从左到右找比mid大的元素
			left++;
		while (L->r[right] > mid && right > low)//从右到左找比mid小的元素
			right--;
		if (left <= right)//若找到且满足条件,则交换
		{
			swap(&L->r[left++], &L->r[right--]);
		}
	} while (left <= right);
	if (left < high)
		QuickSort(L, left, high);//运用递归
	if (low < right)
		QuickSort(L, low, right);
}
//选择排序
void SelectSort(SeqList* L)
{
	assert(L);
	int i, j, min, max;
	if (L->length == 0)
	{
		printf("需要排序的数据为空!");
		return;
	}
	for (i = 1; i <= L->length - 1; i++)//排序的趟数L->length-1
	{
		min = i;
		max = L->length - 1;
		for (j = i; j <= max; j++)
		{//比较第i个元素和其后的元素找到最小的和最大的
			if (L->r[j] < L->r[min])
			{
				swap(&L->r[min], &L->r[j]);//交换两个数,每一趟将最小数放在前面
			}
			if (L->r[j] > L->r[max])
			{
				swap(&L->r[max], &L->r[j]);//交换两个数,每一趟将最大数放在后面
			}
		}
	}
}
//堆排序
void HeapAdjust(SeqList* L, int s, int m)//调整L->r[s]的关键字,使L->r[s-m]成大顶堆
{
	assert(L);
	int i;
	L->r[0] = L->r[s];
	for (i = 2 * s; i <= m; i *= 2)//沿数据较大的孩子结点向下筛选
	{
		if (i < m && (L->r[i] < L->r[i + 1]))//i为数据较大的记录下标
			i++;
		if (L->r[0] >= L->r[i]) //L->r[0]插入在s位置上
			break;
		L->r[s] = L->r[i];
		s = i;
	}
	L->r[s] = L->r[0]; 	//插入新数据 	
}

void HeapSort(SeqList* L)
{
	assert(L);
	int i;
	if (L->length == 0)
	{
		printf("没有数据!");
		return;
	}
	for (i = L->length / 2; i > 0; i--)
		HeapAdjust(L, i, L->length);
	for (i = L->length; i > 1; i--)
	{//将堆顶记录和当前未经排序的子序列L->r[1..i]中最后一个记录互换
		swap(&L->r[1], &L->r[i]);
		HeapAdjust(L, 1, i - 1); //将L->r[1..i-1]重新调整为大顶堆
	}
}
//归并排序函数的具体实现
void MergeArray(SeqList* L, int low, int mid, int high)
{
	assert(L);
	int i, j, k, len1, len2;
	int *front, *back;
	len1 = mid - low + 1;//前一部分的长度
	len2 = high - mid;//后一部分的长度
	front = (int*)malloc(len1*sizeof(int));//申请两个空间存放排好的数组
	back = (int*)malloc(len2*sizeof(int));
	//将数组转入两个新空间中
	for (i = 0; i < len1; i++)
		front[i] = L->r[low + i];
	for (j = 0; j < len2; j++)
		back[j] = L->r[mid + j + 1];
	//合并元素
	i = 0; 
	j = 0;
	k = low; 
	while (i < len1&&j < len2)
	{//L->r[]中依次放入两个数组中较小数
		if (front[i] < back[j])
			L->r[k++] = front[i++];
		else
			L->r[k++] = back[j++];
	}
	//将剩余元素合并
	while (i < len1)
		L->r[k++] = front[i++];
	while (j < len2)
		L->r[k++] = back[j++];
}
//归并排序函数的具体实现
void MergeSort(SeqList* L, int low, int high)
{
	assert(L);
	int middle;
	if (L->length == 0)
	{
		printf("要排序的数据为空!");
		return;
	}
	if (low<high)
	{
		middle = low - (low - high) / 2;
		MergeSort(L, low, middle);//将前面一部分用递归的方法排序
		MergeSort(L, middle + 1, high); //将后面一部分用递归的方法排序
		MergeArray(L, low, middle, high);//再将二个有序数列合并
	}
}

void menu()
{
	printf("\n\t*****************算法排序比较系统****************");
	printf("\n\t-------------------------------------------------\n");
	printf("\t***********       1、直接插入排序     ***********\n");
	printf("\t***********       2、折半插入排序     ***********\n");
	printf("\t***********       3、起泡排序         ***********\n");
	printf("\t***********       4、快速排序         ***********\n");
	printf("\t***********       5、选择排序         ***********\n");
	printf("\t***********       6、堆排序           ***********\n");
	printf("\t***********       7、归并排序         ***********\n");
	printf("\t***********       0、退出系统         ***********\n");
}

int main()
{
	SeqList L;
	srand((unsigned int)time(NULL));
	InitSeqList(&L);//初始化L
	int n = 1;
	clock_t start, end; //clock_t用于计时开始时间和结束时间 
	while (n)
	{
		menu();
		printf("请选择你要排序的方式(数字1~7)或退出系统(数字0)>");
		scanf("%d", &n);
		switch (n)
		{
		case INSERT:
			start = clock();
			CreateShow(&L);
			InsertSort(&L);
			end = clock();
			PrintSeqList(&L);
			printf("插入排序时间是:%f毫秒\n", (float)(end - start));
			break;
		case BININSERT:
			start = clock();
			CreateShow(&L);
			BinInsert(&L);
			end = clock();
			PrintSeqList(&L);
			printf("插入排序时间是:%f毫秒\n", (float)(end - start));
			break;
		case BUBBLE:
			start = clock();
			CreateShow(&L);
			BubbleSort(&L);
			end = clock();
			PrintSeqList(&L);
			printf("插入排序时间是:%f毫秒\n", (float)(end - start));
			break;
		case QUICK:
			start = clock();
			CreateShow(&L);
			QuickSort(&L, 1, L.length);
			end = clock();
			PrintSeqList(&L);
			printf("插入排序时间是:%f毫秒\n", (float)(end - start));
			break;
		case SELECT:
			start = clock();
			CreateShow(&L);
			SelectSort(&L);
			end = clock();
			PrintSeqList(&L);
			printf("插入排序时间是:%f毫秒\n", (float)(end - start));
			break;
		case STACK:
			start = clock();
			CreateShow(&L);
			HeapSort(&L);
			end = clock();
			PrintSeqList(&L);
			printf("插入排序时间是:%f毫秒\n", (float)(end - start));
			break;
		case MERGE:
			start = clock();
			CreateShow(&L);
			MergeSort(&L, 1, L.length);
			end = clock();
			PrintSeqList(&L);
			printf("插入排序时间是:%f毫秒\n", (float)(end - start));
			break;
		case EXIT:printf("感谢使用本系统,欢迎下次使用!"); break;
		default:printf("您输入的序号错误!请重新选择>\n"); break;
		}
	}
	system("pause");
	return 0;
}

各种排序算法的最差时间,时间复杂度及稳定性比较

排序算法 

最差时间

时间复杂度 

是否稳定

插入排序 

O(n2)

O(n2) 

稳定 

冒泡排序

O(n2)

O(n2) 

稳定 

快速排序

O(n2)

O(n*log2n) 

不稳定 

选择排序

O(n2)

O(n2) 

稳定 

堆排序

 O(n*log2n) 

O(n*log2n) 

不稳定 

归并排序

O(n*log2n)

O(n*log2n) 

稳定