【数据结构(C语言)】内排序算法(简单选择排序、直接插入排序、冒泡排序、快速排序、两路合并排序、堆排序)概述与C语言实现

内排序算法(简单选择排序、直接插入排序、冒泡排序、快速排序、两路合并排序、堆排序)

先列出本篇博客代码实现要用到的数据结构。

typedef int KeyType;
typedef int DataType;
typedef int Status;
typedef int ElemType;
typedef struct entry    //数据元素
{
	KeyType key;        //排序关键字,KeyType是可比较类型
	DataType data;      //data包含数据元素中的其他可数据项
}Entry;
typedef struct list     //顺序表
{
	int n;              //待排序数据元素数目
	Entry D[MaxSize];   //静态数组存储数据元素
}List;

一、简单选择排序

(1)算法内容

  • 每一趟排序将待排序列中最小的元素找出,并与第一个数据元素交换位置,将其从下一趟排序序列中移出。
  • 重复上述过程直到某趟排序时待排序列只剩下2个数据元素。在这里插入图片描述

(2)程序实现:

/*在startindex到表尾的范围内寻找最小关键字元素下标*/
int FindMin(List *list, int start_index)
{
	int min_index = start_index;
	for (int i = start_index + 1; i < list->n; i++)
		if (list->D[i].key < list->D[min_index].key)
			min_index = i;
	return min_index;
}
/*交换*/
void Swap(Entry *D, int i, int j)
{
	Entry temp;
	if (i == j) return;
	temp = D[i];
	D[i] = D[j];
	D[j] = temp;
}
/*简单选择排序*/
void SelectSort(List *list)
{
	int min_index, start_index = 0;
	while (start_index < list->n - 1)
	{
		min_index = FindMin(list, start_index);
		Swap(list->D, start_index, min_index);
		start_index++;
	}
}

(3)复杂度和稳定性

  • 比较次数:第i趟要比较 n − i n-i ni次,一共 n − 1 n-1 n1趟, ∑ i = 1 n − 1 ( n − i ) = n ( n − 1 ) 2 \displaystyle\sum_{i=1}^{n-1}(n-i)=\dfrac{n(n-1)}{2} i=1n1(ni)=2n(n1)

  • 最好、最坏、平均时间复杂度: O ( n 2 ) O(n^2) O(n2)

  • 空间复杂度: O ( 1 ) O(1) O(1)

  • 稳定性:不稳定

    对于待排序列中出现两个相同元素,对该元素排序前后出现相对位置改变的情况。(本来在前的现在变成在后的)

二、直接插入排序

(1)算法内容

  • 从只包含一个元素大的有序序列开始,不断将待排序数据元素有序插入这个有序序列中,直到有序序列包含了所有待排序数据元素为止

    i趟排序:前1~i个元素作为有序序列,后面的元素是无序区,将第i+1个元素按序插入有序序列中

在这里插入图片描述

(2)代码实现

void InsertSort(List *list)
{
	int j;
	Entry insert_item;  //每一次待插入元素
	for (int i = 1; i < list->n; i++) 
	{
		insert_item = list->D[i];//insert_item存储当前待插入值,避免后面的后移操作覆盖掉
		for (j = i - 1; j>=0; j--)
		{
			if (insert_item.key < list->D[j].key) list->D[j + 1] = list->D[j];//有序序列后移,为当前待插入元素空出位置
			else break;
		}
		list->D[j + 1] = insert_item;
	}
}

(3)复杂度和稳定性

  • 最好情况:待排序列本就有序,所以该算法适用于待排序列有序递增的情况

    最好情况下共需要比较 1 + 1 + 1 + ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ + 1 = n − 1 1+1+1+······+1=n-1 1+1+1++1=n1次,此时不需要移动元素。

    最好时间复杂度: O ( n ) O(n) O(n)

  • 最坏情况:待排序列是逆序。

    最坏情况下共需要比较 1 + 2 + 3 + ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ + ( n − 1 ) = n ( n − 1 ) 2 1+2+3+······+(n-1)=\dfrac{n(n-1)}{2} 1+2+3++(n1)=2n(n1)次。

    最坏时间复杂度: O ( n 2 ) O(n^2) O(n2)

  • 平均情况:第i趟插入各个位置的概率相同,均为 1 i + 1 \dfrac{1}{i+1} i+11,元素平均比较 1 + i 2 1+\dfrac{i}{2} 1+2i次。

    平均情况下共需要比较 ∑ i = 1 n − 1 ( 1 + i 2 ) = ( n + 4 ) ( n − 1 ) 2 \displaystyle\sum_{i=1}^{n-1}(1+\dfrac{i}{2})=\dfrac{(n+4)(n-1)}2 i=1n1(1+2i)=2(n+4)(n1)

    平均时间复杂度: O ( n 2 ) O(n^2) O(n2)

  • 算法稳定

三、冒泡排序

(1)算法内容

  • 第i趟排序对前n-i+1个元素执行相邻两个元素逆序则交换的操作,第i趟排序结束后会检测本趟排序是否发生了数据交换,未发生则代表已经完成排序,无需继续下面几趟

    较大的元素被移到最后,较小的元素往前移动

在这里插入图片描述

(2)代码实现

/*交换*/
void Swap(Entry *D, int i, int j)
{
	Entry temp;
	if (i == j) return;
	temp = D[i];
	D[i] = D[j];
	D[j] = temp;
}
/*冒泡排序*/
void BubbleSort(List *list)
{
	Status isSwap = FALSE;                  //记录交换状态
	for (int i = list->n - 1; i > 0; i--)
	{
		isSwap = FALSE;                     //标记是否发生了数据交换
		for (int j = 0; j < i; j++)
		{
			if (list->D[j].key > list->D[j + 1].key)
			{
				Swap(list->D, j, j + 1);
				isSwap = TRUE;
			}
		}
		if (!isSwap) break;                 //没有发生数据交换就代表刚好排序成功,避免不必要的判断。      
	}
}

(3)复杂度和稳定性

  • 最好情况:待排序列本就有序,适用于有序且简单快速实现的情况

    最好情况下共需要比较 n − 1 n-1 n1次(第i趟排序结束后会检测本趟排序是否发生了数据交换)

    最好时间复杂度: O ( n ) O(n) O(n)

  • 最坏情况:每一趟都有数据交换,第i趟比较n-i次

    最坏情况下共需要比较 ∑ i = 1 n − 1 n − i = n ( n − 1 ) 2 \displaystyle\sum_{i=1}^{n-1}n-i=\dfrac {n(n-1)}2 i=1n1ni=2n(n1)

    最坏时间复杂度: O ( n 2 ) O(n^{2}) O(n2)

  • 平均情况:每趟停止的概率相同,为 1 n − 1 \dfrac {1}{n-1} n11

    平均情况下比较次数是 1 n − 1 × ∑ j = 1 n − 1 ∑ i = 1 j ( n − i ) = n ( 2 n − 1 ) 6 \dfrac 1{n-1}\times \displaystyle\sum_{j=1}^{n-1}\displaystyle\sum_{i=1}^{j}(n-i)=\dfrac {n(2n-1)}6 n11×j=1n1i=1j(ni)=6n(2n1)

    平均时间复杂度: O ( n 2 ) O(n^{2}) O(n2)

  • 稳定性:遇到关键字相同的元素不发生交换,是稳定的。

四、快速排序

(1)算法内容

  • 待排序序列中元素数目小于等于1的时候,无需排序,直接退出

  • 对当前待排序序列进行如下划分变成左右两个子序列。

    每一趟排序结束交换了low和j后,分割元素左边的序列必然比分割元素小,右边的必然比分割元素大。

  • 在这里插入图片描述
    在这里插入图片描述

(2)代码实现

/*快速排序法*/
int Partition(List *list, int low, int high)
{
	int i = low, j = high + 1;
	Entry pivot = list->D[low];//pivot是分割元素
	do {
		do i++; while (i < high&&list->D[i].key < pivot.key);//直到i指向关键字小于分割元素的元素就停止
		do j--; while (list->D[j].key > pivot.key);//直到j指向关键字大于分割元素的元素就停止
		if (i < j) Swap(list->D, i, j);
	} while (i < j);
	Swap(list->D, low, j);
	return j;//此时j是分割元素下标
}
void QuickSort(List *list, int low, int high)
{
	if (low < high)//从这里可以看出当前待排序序列至少包含2个元素
	{
		int k = Partition(list, low, high);
		QuickSort(list, low, k - 1);
		QuickSort(list, k + 1, high);
	}
}

(3)复杂度和稳定性

  • 最好情况:每一趟排序后左右子序列长度相近。

    时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

  • 最坏情况:每次分割的两个子序列中有一个为空,此时需要n-1趟排序,例如:待排序列本就顺序或者本就逆序。所以适用于无序状态

    时间复杂度: O ( n 2 ) O(n^{2}) O(n2)

  • 平均情况:略

    时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

  • 稳定性:不稳定

五、两路合并排序

(1)算法内容

  • 基本概述:将n个元素分成n组有序序列,两两合并成一个有序序列,对于最后两个序列,如果n是偶数就合并最后两个序列,否则排除最后一个序列两两合并。以此类推直到最后只有1个有序序列。在这里插入图片描述
  • 合并算法:在这里插入图片描述

(2)代码实现

void Merge(List *list, Entry *temp, int low, int n1, int n2)
{
	int i = low, j = low + n1;
	while (i <= low + n1 - 1 && j <= low + n1 + n2 - 1)
	{
		if (list->D[i].key <= list->D[j].key) *temp++ = list->D[i++];//if条件中的小于等于可以看出该排序算法的稳定性
		else *temp++ = list->D[j++];
	}
	while (i <= low + n1 - 1) *temp++ = list->D[i++];
	while (j <= low + n1 + n2 - 1) *temp++ = list->D[j++];
}
void MergeSort(List *list)
{
	Entry *temp=(Entry*)malloc(sizeof(Entry)*MaxSize);//建立一个与原数组等大小的辅助数组用于存储每一次从头到尾两两合并后的新数组
	int low, n1, n2, size = 1;//用size存储每一次两两排序的序列中元素的数目(除了最后一个序列),一开始是把每个元素看作一个序列
	while (size < list->n)//size每更新一次就需要进入下一步两两合并
	{
		low = 0;//low是一对待合并序列中第一个序列的第一个元素下标
		while (low + size < list->n)//内循环控制序列从头到尾的两两合并操作
		{
			n1 = size;//每次两两排序第一个序列必定是size个元素
			if (low + size * 2 < list->n) n2 = size;
			else n2 = list->n - low - size;//计算第二个序列的长度,主要是针对最后一个序列与其他序列数目不一致的情况。
			Merge(list, temp + low, low, n1, n2);
			low += n1 + n2;//指向下一组要两两合并的序列的第一个序列第一个元素下标
		}
		for (int i = 0; i < low; i++) list->D[i] = temp[i];//用两两合并得到的数组更新原数组。
		size *= 2;//同时每做完一次合并,size就翻倍
	}
}

(3)复杂度和稳定性

  • 执行趟数: ┌ l o g 2 n ┐ \ulcorner log_2n\urcorner log2n

  • 时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)【无最好最坏情况】

  • 稳定性:稳定

    如果2个相同关键字元素在同一个有序序列中,必然稳定,如果在不同的有序序列中,同样是稳定的

六、堆排序

(1)知识储备

在这里插入图片描述

(2)算法内容

在这里插入图片描述

调整成最大堆用AdjustDown向下调整,每次交换之后都要进行一次向下调整。

  • 排序前需要向下调整建堆
  • 每一趟排序包括交换首尾元素、现根节点向下调整建堆,也就是说,第一趟堆排序包括两个调整建堆操作。

在这里插入图片描述
在这里插入图片描述

(3)代码实现

/*堆排序*/
void AdjustDown(Entry *heap, int current, int border)
{
	int p = current;
	int minChild;
	Entry temp;
	while (2 * p + 1 <= border)//若p不是叶结点,则执行调整
	{
		if ((2 * p + 2 <= border) && (heap[2 * p + 1].key > heap[2 * p + 2].key))  minChild = 2 * p + 2;
		else minChild = 2 * p + 1;
		if (heap[p].key <= heap[minChild].key)  break;
		else
		{
			temp = heap[p];
			heap[p] = heap[minChild];
			heap[minChild] = temp;
			p = minChild;
		}
	}
}
void HeapSort(List *hp)
{
	Entry temp;
	for (int i = (hp->n - 2) / 2; i >= 0; i--)  AdjustDown(hp->D, i, hp->n - 1);
	for (int i = hp->n - 1; i > 0; i--)
	{
		Swap(hp->D, 0, i);
		AdjustDown(hp->D, 0, i - 1);
	}
}

(4)复杂度和稳定性

  • 最好、最坏、平均时间复杂度: O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
  • 不稳定

七、总结与对比

简单选择排序直接插入排序冒泡排序快速排序两路合并排序堆排序
最好时间复杂度 O ( n 2 ) O(n^2) O(n2) O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)(无最好最坏情况) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
最坏时间复杂度 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^{2}) O(n2) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)(无最好最坏情况) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
平均时间复杂度 O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n 2 ) O(n^2) O(n2) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)(无最好最坏情况) O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)
空间复杂度 O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1) O ( 1 ) O(1) O(1)最好/平均: O ( l o g 2 n ) O(log_2n) O(log2n)最坏: O ( n ) O(n) O(n) O ( n ) O(n) O(n) O ( 1 ) O(1) O(1)
稳定性不稳定稳定稳定不稳定稳定不稳定

八、排序算法实现

为了更直观看出各个算法的排序时间,选择在C语言中调用python脚本,其中C语言用来实现各排序算法,python用来实现excel图表的绘制。关于如何在C语言中调用python脚本可以参考另一篇博客【C语言】如何在C程序中调用Python脚本

#define _CRT_SECURE_NO_WARNINGS
#include<Python.h>
#include<stdio.h>
#include<stdlib.h> 
#include<time.h>  
#include<windows.h>
#define MaxSize 100000
#define ERROR 0
#define FALSE 0
#define OK 1
#define TRUE 1
#define IsFull 2
#define IsEmpty 3
typedef int KeyType;
typedef int DataType;
typedef int Status;
typedef int ElemType;
typedef struct entry    //数据元素
{
	KeyType key;        //排序关键字,KeyType是可比较类型
	DataType data;      //data包含数据元素中的其他可数据项
}Entry;
typedef struct list     //顺序表
{
	int n;              //待排序数据元素数目
	Entry D[MaxSize];   //静态数组存储数据元素
}List;

Status Init(List *list, int mSize)
{
	list->n = mSize;
	return OK;
}
Status Insert(List *list, int i, ElemType x)
{
	if (i<-1 || i>list->n - 1) return ERROR;
	if (list->n == MaxSize)  return IsFull;
	for (int j = list->n - 1; j > i; j--)  list->D[j + 1] = list->D[j];  //由于新元素放到第i号元素后面,放入前其余元素从后往前分别向后平移1单元
	list->D[i + 1].key = x;                                              //新元素放到第i号元素后面
	list->n = list->n + 1;                                               //更新待排序数据的数量
	return OK;
}
Status Output(List *list)
{
	if (list->n == 0) return IsEmpty;
	printf("排序后效果如下:\n");
	for (int i = 0; i < list->n; i++) printf("%d ", list->D[i].key);
	printf("\n");
	return OK;
}
Status OutputRe(List *list)
{
	if (list->n == 0) return IsEmpty;
	printf("排序后效果如下:\n");
	for (int i = list->n; i > 0; i--) printf("%d ", list->D[i-1].key);
	printf("\n");
	return OK;
}
Status Output1(List *list)
{
	if (list->n == 0) return IsEmpty;
	for (int i = 0; i < list->n; i++) printf("%d ", list->D[i].key);
	printf("\n");
	return OK;
}
/*在startindex致表尾范围内寻找最小关键字元素下标*/
int FindMin(List *list, int start_index)
{
	int min_index = start_index;
	for (int i = start_index + 1; i < list->n; i++)
		if (list->D[i].key < list->D[min_index].key)
			min_index = i;
	return min_index;
}
/*交换*/
void Swap(Entry *D, int i, int j)
{
	Entry temp;
	if (i == j) return;
	temp = D[i];
	D[i] = D[j];
	D[j] = temp;
}
/*简单选择排序*/
void SelectSort(List *list)
{
	int min_index, start_index = 0;
	while (start_index < list->n - 1)
	{
		min_index = FindMin(list, start_index);
		Swap(list->D, start_index, min_index);
		start_index++;
	}
}
/*直接插入排序*/
void InsertSort(List *list)
{
	int j;
	Entry insert_item;  //每一次待插入元素
	for (int i = 1; i < list->n; i++) 
	{
		insert_item = list->D[i];
		for (j = i - 1; j>=0; j--)
		{
			if (insert_item.key < list->D[j].key) list->D[j + 1] = list->D[j];//有序序列后移,为当前待插入元素空出位置
			else break;
		}
		list->D[j + 1] = insert_item;
	}
}
/*冒泡排序*/
void BubbleSort(List *list)
{
	Status isSwap = FALSE;                  //记录交换状态
	for (int i = list->n - 1; i > 0; i--)
	{
		isSwap = FALSE;                     //标记是否发生了数据交换
		for (int j = 0; j < i; j++)
		{
			if (list->D[j].key > list->D[j + 1].key)
			{
				Swap(list->D, j, j + 1);
				isSwap = TRUE;
			}
		}
		if (!isSwap) break;                 //没有发生数据交换就代表刚好排序成功,避免不必要的判断。      
	}
}
/*快速排序法*/
int Partition(List *list, int low, int high)
{
	int i = low, j = high + 1;
	Entry pivot = list->D[low];//pivot是分割元素
	do {
		do i++; while (i < high&&list->D[i].key < pivot.key);//i前进
		do j--; while (list->D[j].key > pivot.key);//j前进
		if (i < j) Swap(list->D, i, j);
	} while (i < j);
	Swap(list->D, low, j);
	return j;//此时j是分割元素下标
}
void QuickSort(List *list, int low, int high)
{
	if (low < high)//当前待排序序列至少包含2个元素
	{
		int k = Partition(list, low, high);
		QuickSort(list, low, k - 1);
		QuickSort(list, k + 1, high);
	}
}
/*两路合并排序*/
void Merge(List *list, Entry *temp, int low, int n1, int n2)
{
	int i = low, j = low + n1;
	while (i <= low + n1 - 1 && j <= low + n1 + n2 - 1)
	{
		if (list->D[i].key <= list->D[j].key) *temp++ = list->D[i++];
		else *temp++ = list->D[j++];
	}
	while (i <= low + n1 - 1) *temp++ = list->D[i++];
	while (j <= low + n1 + n2 - 1) *temp++ = list->D[j++];
}
void MergeSort(List *list)
{
	Entry *temp=(Entry*)malloc(sizeof(Entry)*MaxSize);
	int low, n1, n2, size = 1;
	while (size < list->n)
	{
		low = 0;
		while (low + size < list->n)
		{
			n1 = size;
			if (low + size * 2 < list->n) n2 = size;
			else n2 = list->n - low - size;
			Merge(list, temp + low, low, n1, n2);
			low += n1 + n2;
		}
		for (int i = 0; i < low; i++) list->D[i] = temp[i];
		size *= 2;
	}
}
/*堆排序*/
void AdjustDown(Entry *heap, int current, int border)
{
	int p = current;
	int minChild;
	Entry temp;
	while (2 * p + 1 <= border)//若p不是叶结点,则执行调整
	{
		if ((2 * p + 2 <= border) && (heap[2 * p + 1].key > heap[2 * p + 2].key))  minChild = 2 * p + 2;
		else minChild = 2 * p + 1;
		if (heap[p].key <= heap[minChild].key)  break;
		else
		{
			temp = heap[p];
			heap[p] = heap[minChild];
			heap[minChild] = temp;
			p = minChild;
		}
	}
}
void HeapSort(List *hp)
{
	Entry temp;
	for (int i = (hp->n - 2) / 2; i >= 0; i--)  AdjustDown(hp->D, i, hp->n - 1);
	for (int i = hp->n - 1; i > 0; i--)
	{
		Swap(hp->D, 0, i);
		AdjustDown(hp->D, 0, i - 1);
	}
}
/*生成excel表格*/
Status CreateExcel(int *time)
{
	PyObject *pName, *pModule, *pDict, *pFunc;
	PyObject *pArgs, *pValue;
	Py_Initialize();//初始化python
	// 检查初始化是否成功  
	if (!Py_IsInitialized())
	{
		printf("初始化失败\n");
		Py_Finalize();
	}
	//设置python模块,搜寻位置,文件放在.cpp文件一起
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");

	//Python文件名  
	pModule = PyImport_ImportModule("graph");
	if (!pModule) {
		printf("py文件导入失败\n");
		Py_Finalize();
	}
	else {
		//直接获取模块中的函数
		pFunc = PyObject_GetAttrString(pModule, "create_graph");
		if (!pFunc) {
			printf("函数导入失败\n");
			Py_Finalize();
		}

		//将c/c++类型数据转换为python类型,利用元组传递
		pArgs = PyTuple_New(6);
		pValue = PyLong_FromLong(time[0]);
		PyTuple_SetItem(pArgs, 0, pValue);

		pValue = PyLong_FromLong(time[1]);
		PyTuple_SetItem(pArgs, 1, pValue);

		pValue = PyLong_FromLong(time[2]);
		PyTuple_SetItem(pArgs, 2, pValue);

		pValue = PyLong_FromLong(time[3]);
		PyTuple_SetItem(pArgs, 3, pValue);

		pValue = PyLong_FromLong(time[4]);
		PyTuple_SetItem(pArgs, 4, pValue);

		pValue = PyLong_FromLong(time[5]);
		PyTuple_SetItem(pArgs, 5, pValue);
		//调用直接获得的函数,并传递参数
		pValue = PyObject_CallObject(pFunc, pArgs);

		//释放python
		Py_Finalize();
		return OK;
	}
}
int main()
{
	clock_t start, end;
	double diff_time[6] = {0};
	int operation, num, data[10] = { -1 }, difftime[6] = {0};
	char tmpbuf[] = { 0 };
	int data_t[MaxSize] = { 0 };
	_tzset();                             // 初始化时区
	_strdate(tmpbuf);
	while (1)
	{
		printf("(当前时间: %s)\n", tmpbuf);
		system("title MADE BY YQC");
		List *list  = (List*)malloc(sizeof(List));
		List *list1 = (List*)malloc(sizeof(List));
		List *list2 = (List*)malloc(sizeof(List));
		List *list3 = (List*)malloc(sizeof(List));
		List *list4 = (List*)malloc(sizeof(List));
		List *list5 = (List*)malloc(sizeof(List));
		Init(list, 0);   //先初始化
		Init(list1, 0);
		Init(list2, 0);
		Init(list3, 0);
		Init(list4, 0);
		Init(list5, 0);
		printf("1.自定义待排序数据\n2.随机生成待排序数据\n3.几种排序算法对比\n4.退出程序\n——请选择:");
		scanf("%d", &operation);
		system("CLS");
		switch (operation)
		{
		case 1:
			printf("请输入待排序数据的数目(小于等于200000):");
			scanf("%d", &num);
			printf("请输入数据:");
			for (int i = 0; i < num; i++)
			{
				scanf("%d", data + i);
				if (Insert(list, i - 1, data[i]) == IsFull)  printf("顺序表已满\n");
			}
			break;
		case 2:
			printf("请输入待排序数据的数目(小于等于200000):");
			scanf("%d", &num);
			printf("正在随机生成数据\n");
			srand((unsigned)time(NULL));                 //设定以当前时间为随机数种子
			for(int i = 0; i < num; i++)
				if (Insert(list, i - 1, rand()%num) == IsFull)  printf("顺序表已满\n");
			printf("当前生成的随机数据如下:\n");
			Output1(list);
			printf("生成成功\n");
			break;
		case 3:
			printf("请输入待排序数据的数目(小于等于200000):");
			scanf("%d", &num);
			srand((unsigned)time(NULL));                  //设定以当前时间为随机数种子

			printf("***正在构建数据……\n");
			for (int i = 0; i < num; i++)
			{
				data_t[i] = rand() % num;
				if (  Insert(list,  i - 1, data_t[i]) == IsFull
					& Insert(list1, i - 1, data_t[i]) == IsFull
					& Insert(list2, i - 1, data_t[i]) == IsFull
					& Insert(list3, i - 1, data_t[i]) == IsFull
					& Insert(list4, i - 1, data_t[i]) == IsFull
					& Insert(list5, i - 1, data_t[i]) == IsFull)  printf("顺序表已满\n");
			}
			printf("***构建完毕,开始测试……\n");

			start = clock();
			SelectSort(list);
			end = clock();
			diff_time[0] = (double)(end - start) / CLOCKS_PER_SEC;
			difftime[0] = diff_time[0] * 1000;
			printf("简单选择排序用时:%f \n", diff_time[0]);

			start = clock();
			InsertSort(list1);
			end = clock();
			diff_time[1] = (double)(end - start) / CLOCKS_PER_SEC;
			difftime[1] = diff_time[1] * 1000;
			printf("直接插入排序用时%fms \n", diff_time[1]);

			start = clock();
			BubbleSort(list2);
			end = clock();
			diff_time[2] = (double)(end - start) / CLOCKS_PER_SEC;
			difftime[2] = diff_time[2] * 1000;
			printf("冒泡排序用时%fms\n", diff_time[2]);

			start = clock();
			QuickSort(list3, 0, list->n - 1);
			end = clock();
			diff_time[3] = (double)(end - start) / CLOCKS_PER_SEC;
			difftime[3] = diff_time[3] * 1000;
			printf("快速排序用时:%fms\n", diff_time[3]);

			start = clock();
			MergeSort(list4);
			end = clock();
			diff_time[4] = (double)(end - start) / CLOCKS_PER_SEC;
			difftime[4] = diff_time[4] * 1000;
			printf("两路合并排序排序用时:%fms\n", diff_time[4]);

			start = clock();
			HeapSort(list5);
			end = clock();
			diff_time[5] = (double)(end - start) / CLOCKS_PER_SEC;
			difftime[5] = diff_time[5] * 1000;
			printf("堆排序排序用时:%fms\n", diff_time[5]);

			printf("***正在生成Excel表格……\n");
			CreateExcel(difftime);
			printf("***生成成功……\n");
			break;
		case 4:
			exit(0);
		default:
			printf("WARNING:异常输入");
			break;
		}
		if (operation == 1 || operation == 2)
		{
			printf("1.简单选择排序\n2.直接插入排序\n3.冒泡排序\n4.快速排序\n5.两路合并排序\n6.堆排序\n——请输入你要采用的排序方式:");
			scanf("%d", &operation);
			switch (operation)
			{
			case 1:
				SelectSort(list);
				if (Output(list) == IsEmpty) printf("顺序表为空,无法输出");
				break;
			case 2:
				InsertSort(list);
				if (Output(list) == IsEmpty) printf("顺序表为空,无法输出");
				break;
			case 3:
				BubbleSort(list);
				if (Output(list) == IsEmpty) printf("顺序表为空,无法输出");
				break;
			case 4:
				QuickSort(list, 0, list->n - 1);
				if (Output(list) == IsEmpty) printf("顺序表为空,无法输出");
				break;
			case 5:
				MergeSort(list);
				if (Output(list) == IsEmpty) printf("顺序表为空,无法输出");
				break;
			case 6:
				HeapSort(list);
				if (OutputRe(list) == IsEmpty) printf("顺序表为空,无法输出");
				break;
			default:
				printf("WARNING:异常输入");
				break;
			}
		}
		free(list);
		free(list1);
		free(list2);
		free(list3);
		free(list4);
		free(list5);
	}
	return 0;
}

graph.py

# -*- coding:utf-8 -*-
import xlsxwriter

def create_graph(a,b,c,d,e,f):
	# 创建一个excel
	workbook = xlsxwriter.Workbook("排序算法比较结果.xlsx")
	# 创建一个sheet
	worksheet = workbook.add_worksheet()
	# worksheet = workbook.add_worksheet("bug_analysis")

	# 自定义样式,加粗
	bold = workbook.add_format({'bold': 1})

	# --------1、准备数据并写入excel---------------
	# 向excel中写入数据,建立图标时要用到
	headings = ["排序方法", "排序时间"]
	data = [["简单选择排序", "直接插入排序", "冒泡排序", "快速排序", "两路合并排序", "堆排序"],[a/1000,b/1000,c/1000,d/1000,e/1000,f/1000]]
	
	# 写入表头
	worksheet.write_row('A1', headings, bold)
 
	# 写入数据
	worksheet.write_column('A2', data[0])
	worksheet.write_column('B2', data[1])
 
	# --------2、生成图表并插入到excel---------------
	# 创建一个柱状图(column chart)
	chart_col = workbook.add_chart({'type': 'column'})
 
	# 配置第一个系列数据
	chart_col.add_series({'name': '=Sheet1!$B$1','categories': '=Sheet1!$A$2:$A$7','values':   '=Sheet1!$B$2:$B$7','line': {'color': 'red'},})
	# 这里的sheet1是默认的值,因为我们在新建sheet时没有指定sheet名
	# 如果我们新建sheet时设置了sheet名,这里就要设置成相应的值
 
	# 设置图表的title 和 x,y轴信息
	chart_col.set_title({'name': "排序算法结果"})
	chart_col.set_x_axis({'name': "排序方法"})
	chart_col.set_y_axis({'name':  "花费时间(ms)"})
 
	# 设置图表的风格
	chart_col.set_style(1)
 
	# 把图表插入到worksheet以及偏移
	worksheet.insert_chart('A10', chart_col, {'x_offset': 25, 'y_offset': 10})
	
	workbook.close()
	return 0

if __name__=="__main__":
	create_graph(10, 40, 50, 20, 10, 50)

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Em0s_Er1t

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值