1、九大常用排序算法介绍
在程序设计中,经常需要用到排序,可能大家都对排序算法有过一定的了解,不过,如果能系统地掌握它们,绝对是一件非常好的事情。
可能我们很熟悉冒泡排序、选择排序、快速排序、插入排序等等之类的排序算法,当被问到堆排序、归并排序等等就不知道怎么回事了。那么我们怎么去系统地记忆这些常用的排序算法呢?
我们可以根据排序的方式不同将排序算法分成插入排序、交换排序、选择排序、归并排序和基数排序,插入排序包含了直接插入排序、折半插入排序、希尔排序;交换排序包含了冒泡排序、快速排序;选择排序包含了直接选择排序、堆排序;可以用结构图来记忆常用的这些排序算法,结构图如下:
2、算法的性能对比
3、算法的执行步骤与代码实现
(1)直接插入排序
/*
直接插入排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)选取无序区中第一个元素i
(2)将i与有序区中元素j(0 <= j <= i-1)比较,寻找插入位置,同时移动元素
(3)将该元素插入合适位置
(4)重复(1)(2)(3)直至无序区长度为0
*/
template<typename T>
void InsertSort(T a[], int n)
{
for (int i = 1; i < n; i++) //每次选取无序区间的第一个元素插入
{
T t = a[i];
int j = i - 1; //i - 1即为有序区最后一个元素
while (j >= 0 && t < a[j]) //边比较寻找插入位置边移动元素
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = t; //插入元素到有序区
}
}
(2)折半插入排序
/*
折半插入排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)选取无序区中第一个元素i
(2)在有序区间折半搜索该元素应该插入的位置
(3)将该元素插入合适位置
(4)重复(1)(2)(3)直至无序区长度为0
*/
template<typename T>
void BinaryInsertSort(T a[], int n)
{
for (int i = 1; i < n; i++) //每次选取无序区间的第一个元素插入
{
T t = a[i];
int left = 0, right = i - 1; //折半寻找插入位置
while (left <= right)
{
int mid = (left + right) / 2; //取区间中间位置
if (t < a[mid]) right = mid - 1; //插入点在左半区
else left = mid + 1; //插入点在右半区(为保证排序稳定性,如果有元素相等,则在该元素后插入)
}
int j = i - 1;
while (j >= right + 1) //移动元素
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = t; //插入元素到有序区
}
}
(3)希尔排序
详细排序思路参考:https://www.cnblogs.com/chengxiao/p/6104371.html
/*
希尔排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)将待排序集合分成k个组,且每个组元素下标的差值为k
(2)对每个组的元素进行直接插入排序
(3)减少组的规模(这里采用折半减少的方式),重复(1)(2)直至规模为最小值1
*/
template<typename T>
void ShellSort(T a[], int n)
{
int k = n / 2; //排序划分组数
while (k > 0)
{
for (int g = 0; g < k; g++) //对每组的元素分别进行插入排序
{
for (int i = g + k; i < n; i += k) //插入排序
{
T t = a[i];
int j = i - k; //将直接插入排序中的1换成k
while (j >= 0 && t < a[j])
{
a[j + k] = a[j];
j -= k;
}
a[j + k] = t;
}
}
k = k / 2; //减少分组数,直至分组为0
}
}
(4)冒泡排序
/*
冒泡排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)从无序区间的最后一个元素开始,如果该元素小于它相邻的前一个元素,则两者交换,重复比较直至无序区所有元素都比较完成
(2)将无序区间的第一个元素置入有序区间
(3)重复(1)(2)直至无序区间长度为0
*/
template <typename T>
void BubbleSort(T a[], int n)
{
for (int i = 0; i < n; i++) //区间[0, i]为有序区
{
for (int j = n - 1; j > i; j--) //从无序区间的最后一个元素开始
{
if (a[j] < a[j - 1]) //如果该元素小于它相邻的前一个元素,则两者交换
{
T t = a[j];
a[j] = a[j - 1];
a[j - 1] = t;
}
}
}
}
(5)快速排序
/*
快速排序
a:待排序元素集合
left:集合中第一个元素下标
right:集合中最后一个元素下标
步骤:
(1)以集合第一个元素为基准,进行划分,将小与它的元素放在它左边,将大于它的元素放在它右边
(2)将左边元素的区间、右边元素的区间递归进行划分
(3)重复(1)(2),直至子区间不能再划分为止
*/
template <typename T>
void QuickSort(T a[], int left, int right)
{
if (left >= right) return;
//以第一个元素为基准,执行一趟划分
int i = left, j = right;
T t = a[left];
while (i < j)
{
while (i < j && a[j] >= t) //从右向左扫描,选取第一个小于t的元素交换
j--;
a[i] = a[j];
while (i < j && a[i] <= t) //再从左往右扫描,选取第一个大于t的元素交换
i++;
a[j] = a[i];
}
a[i] = t;
//递归执行划分
QuickSort(a, left, i - 1);
QuickSort(a, i + 1, right);
}
(6)直接选择排序
/*
直接选择排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)从无序区间选择最小的元素置入有序区间
(2)重复(1)直至无序区间长度为0
*/
template<typename T>
void SelectSort(T a[], int n)
{
for (int i = 0; i < n; i++)
{
int imin = i; //标记无序区间最小元素下标
for (int j = i + 1; j < n; j++) //选出无序区间的最小元素
if (a[j] < a[imin]) imin = j;
if (imin != i) //将选出的最小元素和无序区第一个元素交换
{
T t = a[i];
a[i] = a[imin];
a[imin] = t;
}
}
}
(7)堆排序
详细排序思路参考:https://www.cnblogs.com/chengxiao/p/6129630.html
/*
调整堆:给定一个非叶子节点,递归向下调整,使其满足堆的结构(根节点大于它的左右孩子节点)
a:待排序元素集合
n:非叶子节点的下标
n:集合中元素的个数
步骤:
(1)若左右孩子节点的最大值大于当前节点,将其和最大值的节点交换
(2)交换后可能会导致子树不满足堆的定义,所以要递归进行调整
*/
template<typename T>
void AdjustHeap(T a[], int i, int n)
{
T t = a[i];
int j = i * 2 + 1; //j指向i的左孩子节点
while (j < n)
{
if (j + 1 < n && a[j] < a[j + 1]) j++; //如果右子树大于它的左子树,则j改为指向右子树
if (t < a[j]) a[(j - 1) / 2] = a[j]; //如果孩子节点较大,则将孩子节点与父节点交换(因为是递归调整,所以不用修改孩子节点的值)
else break;
j = j * 2 + 1; //递归遍历孩子节点
}
j < n ? a[j] = t : a[(j - 1) / 2] = t; //递归出口,被break掉的情况和j越界的情况
}
/*
堆排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)建立堆
(2)每次取无序区堆顶元素,置入有序区
(3)调整堆
(4)重复(2)(3)直至无序区长度为0
*/
template<typename T>
void HeapSort(T a[], int n)
{
//构建堆
for (int i = n / 2 - 1; i >= 0; i--) //从第一个非叶子节点开始,向上调整堆直至调整至堆顶
AdjustHeap(a, i, n);
//堆排序
for (int i = n - 1; i >= 0; i--) //每次选取堆顶元素置入有序区
{
T t = a[0];
a[0] = a[i];
a[i] = t;
AdjustHeap(a, 0, i); //调整堆
}
}
(8)归并排序
详细排序思路参考:https://www.cnblogs.com/chengxiao/p/6194356.html
/*
归并排序
a:待排序元素集合
left:集合中第一个元素下标
right:集合中最后一个元素下标
步骤:
(1)将排序集合递归划分成两个集合,直到划分集合的长度为1
(2)以有序的方式合并两个有序集合
(3)重复(2)直到所有集合都合并完
*/
template<typename T>
void MergeSort(T a[], int left, int right)
{
if (left < right)
{
//分
int mid = (left + right) / 2; //二分法将集合划分成两个部分
MergeSort(a, left, mid); //递归划分左边集合
MergeSort(a, mid + 1, right); //递归划分右边集合
//合
T *tmp = new T[right - left + 1]; //建立一个临时数组,存放合并的有序序列
int i = left, j = mid + 1, k = 0; //i为左边集合下标,j为右边集合下标,k为合并集合下标
while (i <= mid && j <= right)
{
if (a[i] < a[j]) tmp[k++] = a[i++]; //左边集合值更小
else tmp[k++] = a[j++]; //右边集合值更小
}
while (i <= mid) tmp[k++] = a[i++]; //如果左边集合未遍历完
while (j <= right) tmp[k++] = a[j++]; //如果右边集合未遍历完
while (--k >= 0) a[left + k] = tmp[k]; //将临时数组拷贝回原数组
delete[] tmp; //释放空间
}
}
(9)基数排序
/*
基数节点
val:元素的值,采用字符串表示
next:该元素的下一个节点地址
*/
#include <string>
typedef struct _RadixNode
{
string val;
struct _RadixNode *next;
}RadixNode;
/*
基数排序
p:待排序元素集合,用单链表表示
r:元素的基数(对于二进制r为2,对于10进制r为10)
d:元素的位数
步骤:
(1)将集合分成r个组,r的值为集合每一位的所有可能取值的个数
(2)从集合的第d位开始,重复(3)(4)直至d的值为0,d的值为集合中元素的最大位数
(3)将集合中所有元素分配到相应的组
(4)从所有组中收集元素
*/
void RadixSort(RadixNode *&p, int r, int d)
{
RadixNode **head = new RadixNode*[r]; //存储基数的每一个字符的头节点
RadixNode **tail = new RadixNode*[r]; //存储基数的每一个字符的尾节点
while (--d >= 0) //对集合中所有数字的每一位进行分配和收集
{
//分配
for (int i = 0; i < r; i++) //初始化头结点和尾节点
head[i] = tail[i] = NULL;
while (p != NULL) //分配集合中的每一个元素
{
int i = p->val[d] - '0'; //获取元素第d位对应的字符下标
if (head[i] == NULL) //分配到对应的字符组,组中没有元素的情况
head[i] = tail[i] = p;
else //分配到对应的字符组,组中已经有元素的情况
tail[i] = tail[i]->next = p;
p = p->next;
}
//收集
p = NULL;
auto q = p;
for (int i = 0; i < r; i++) //收集每一个组的所有元素
{
if (head[i] != NULL) //组不为空收集
{
if (p == NULL) //还未收集到元素的情况
{
p = head[i];
q = tail[i];
}
else //已经收集到元素的情况
{
q->next = head[i];
q = tail[i];
}
}
}
if(q) q->next = NULL; //添加链表结束标志
}
delete[] head, tail; //释放空间
}
3、测试
这里作者随机生成了20万个数据,数据的范围是0~10000,对上面提到的所有算法进行了时间复杂度的测试,测试代码和测试结果如下:
测试代码:
#include <Windows.h>
#include <iostream>
using namespace std;
void InitRandSet(int a[], int n, int minVal, int maxVal)
{
int k = maxVal - minVal + 1;
for (int i = 0; i < n; i++)
a[i] = minVal + rand() % k;
}
void InitRadixData(RadixNode *&p, int a[], int n, int d)
{
auto *q = p;
for (int i = 0; i < n; i++)
{
if (q == NULL) p = q = new RadixNode;
else q = q->next = new RadixNode;
q->val = to_string(a[i]);
q->val = string(d - q->val.length(), '0') + q->val;
}
q->next = NULL;
}
int main()
{
const int n = 200000; //待排序集合长度
const int minVal = 0; //数据最小值,用于生成随机数据
const int maxVal = 10000; //数据最大值,用于生成随机数据
const int r = 10, d = 5; //基数排序参数d,r
int *a = new int[n]; //待排序集合数组
int *aCopy = new int[n]; //集合数组备份,因为排序后数组会变为有序,所以需要备份无序数组
InitRandSet(aCopy, n, minVal, maxVal); //生成随机数组
RadixNode *p = NULL; //基数排序数据格式
InitRadixData(p, aCopy, n, d); //基数排序数据初始化
DWORD pre_time = GetTickCount(); //保存上一个时间
auto difTime = [&pre_time]()->long { //获取时间差
DWORD dif = GetTickCount() - pre_time;
pre_time = GetTickCount();
return dif;
};
auto copySet = [&a, aCopy, n]()->void { //拷贝数组
for (int i = 0; i < n; i++)
a[i] = aCopy[i];
};
cout << "待排序集合长度:" << n << endl;
//插入排序
copySet(); InsertSort(a, n); cout << "1.插入排序:" << difTime() << "ms" << endl;
copySet(); BinaryInsertSort(a, n); cout << "2.折半插入排序:" << difTime() << "ms" << endl;
copySet(); ShellSort(a, n); cout << "3.希尔排序:" << difTime() << "ms" << endl;
//交换排序
copySet(); BubbleSort(a, n); cout << "4.冒泡排序:" << difTime() << "ms" << endl;
copySet(); QuickSort(a, 0, n - 1); cout << "5.快速排序:" << difTime() << "ms" << endl;
//选择排序
copySet(); SelectSort(a, n); cout << "6.选择排序:" << difTime() << "ms" << endl;
copySet(); HeapSort(a, n); cout << "7.堆排序:" << difTime() << "ms" << endl;
//归并排序
copySet(); MergeSort(a, 0, n - 1); cout << "8.归并排序:" << difTime() << "ms" << endl;
//基数排序
RadixSort(p, r, d); cout << "9.基数排序:" << difTime() << "ms" << endl;
delete[] a, aCopy; //释放资源
while (p != NULL) { auto q = p; p = p->next; delete q; } //释放链表申请的空间
while (1) cin.get();
return 0;
}
测试结果:
完整代码:
#include <iostream>
using namespace std;
/*
直接插入排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)选取无序区中第一个元素i
(2)将i与有序区中元素j(0 <= j <= i-1)比较,寻找插入位置,同时移动元素
(3)将该元素插入合适位置
(4)重复(1)(2)(3)直至无序区长度为0
*/
template<typename T>
void InsertSort(T a[], int n)
{
for (int i = 1; i < n; i++) //每次选取无序区间的第一个元素插入
{
T t = a[i];
int j = i - 1; //i - 1即为有序区最后一个元素
while (j >= 0 && t < a[j]) //边比较寻找插入位置边移动元素
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = t; //插入元素到有序区
}
}
/*
折半插入排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)选取无序区中第一个元素i
(2)在有序区间折半搜索该元素应该插入的位置
(3)将该元素插入合适位置
(4)重复(1)(2)(3)直至无序区长度为0
*/
template<typename T>
void BinaryInsertSort(T a[], int n)
{
for (int i = 1; i < n; i++) //每次选取无序区间的第一个元素插入
{
T t = a[i];
int left = 0, right = i - 1; //折半寻找插入位置
while (left <= right)
{
int mid = (left + right) / 2; //取区间中间位置
if (t < a[mid]) right = mid - 1; //插入点在左半区
else left = mid + 1; //插入点在右半区(为保证排序稳定性,如果有元素相等,则在该元素后插入)
}
int j = i - 1;
while (j >= right + 1) //移动元素
{
a[j + 1] = a[j];
j--;
}
a[j + 1] = t; //插入元素到有序区
}
}
/*
希尔排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)将待排序集合分成k个组,且每个组元素下标的差值为k
(2)对每个组的元素进行直接插入排序
(3)减少组的规模(这里采用折半减少的方式),重复(1)(2)直至规模为最小值1
*/
template<typename T>
void ShellSort(T a[], int n)
{
int k = n / 2; //排序划分组数
while (k > 0)
{
for (int g = 0; g < k; g++) //对每组的元素分别进行插入排序
{
for (int i = g + k; i < n; i += k) //插入排序
{
T t = a[i];
int j = i - k; //将直接插入排序中的1换成k
while (j >= 0 && t < a[j])
{
a[j + k] = a[j];
j -= k;
}
a[j + k] = t;
}
}
k = k / 2; //减少分组数,直至分组为0
}
}
/*
冒泡排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)从无序区间的最后一个元素开始,如果该元素小于它相邻的前一个元素,则两者交换,重复比较直至无序区所有元素都比较完成
(2)将无序区间的第一个元素置入有序区间
(3)重复(1)(2)直至无序区间长度为0
*/
template <typename T>
void BubbleSort(T a[], int n)
{
for (int i = 0; i < n; i++) //区间[0, i]为有序区
{
for (int j = n - 1; j > i; j--) //从无序区间的最后一个元素开始
{
if (a[j] < a[j - 1]) //如果该元素小于它相邻的前一个元素,则两者交换
{
T t = a[j];
a[j] = a[j - 1];
a[j - 1] = t;
}
}
}
}
/*
快速排序
a:待排序元素集合
left:集合中第一个元素下标
right:集合中最后一个元素下标
步骤:
(1)以集合第一个元素为基准,进行划分,将小与它的元素放在它左边,将大于它的元素放在它右边
(2)将左边元素的区间、右边元素的区间递归进行划分
(3)重复(1)(2),直至子区间不能再划分为止
*/
template <typename T>
void QuickSort(T a[], int left, int right)
{
if (left >= right) return;
//以第一个元素为基准,执行一趟划分
int i = left, j = right;
T t = a[left];
while (i < j)
{
while (i < j && a[j] >= t) //从右向左扫描,选取第一个小于t的元素交换
j--;
a[i] = a[j];
while (i < j && a[i] <= t) //再从左往右扫描,选取第一个大于t的元素交换
i++;
a[j] = a[i];
}
a[i] = t;
//递归执行划分
QuickSort(a, left, i - 1);
QuickSort(a, i + 1, right);
}
/*
直接选择排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)从无序区间选择最小的元素置入有序区间
(2)重复(1)直至无序区间长度为0
*/
template<typename T>
void SelectSort(T a[], int n)
{
for (int i = 0; i < n; i++)
{
int imin = i; //标记无序区间最小元素下标
for (int j = i + 1; j < n; j++) //选出无序区间的最小元素
if (a[j] < a[imin]) imin = j;
if (imin != i) //将选出的最小元素和无序区第一个元素交换
{
T t = a[i];
a[i] = a[imin];
a[imin] = t;
}
}
}
/*
调整堆:给定一个非叶子节点,递归向下调整,使其满足堆的结构(根节点大于它的左右孩子节点)
a:待排序元素集合
n:非叶子节点的下标
n:集合中元素的个数
步骤:
(1)若左右孩子节点的最大值大于当前节点,将其和最大值的节点交换
(2)交换后可能会导致子树不满足堆的定义,所以要递归进行调整
*/
template<typename T>
void AdjustHeap(T a[], int i, int n)
{
T t = a[i];
int j = i * 2 + 1; //j指向i的左孩子节点
while (j < n)
{
if (j + 1 < n && a[j] < a[j + 1]) j++; //如果右子树大于它的左子树,则j改为指向右子树
if (t < a[j]) a[(j - 1) / 2] = a[j]; //如果孩子节点较大,则将孩子节点与父节点交换(因为是递归调整,所以不用修改孩子节点的值)
else break;
j = j * 2 + 1; //递归遍历孩子节点
}
j < n ? a[j] = t : a[(j - 1) / 2] = t; //递归出口,被break掉的情况和j越界的情况
}
/*
堆排序
a:待排序元素集合
n:集合中元素的个数
步骤:
(1)建立堆
(2)每次取无序区堆顶元素,置入有序区
(3)调整堆
(4)重复(2)(3)直至无序区长度为0
*/
template<typename T>
void HeapSort(T a[], int n)
{
//构建堆
for (int i = n / 2 - 1; i >= 0; i--) //从第一个非叶子节点开始,向上调整堆直至调整至堆顶
AdjustHeap(a, i, n);
//堆排序
for (int i = n - 1; i >= 0; i--) //每次选取堆顶元素置入有序区
{
T t = a[0];
a[0] = a[i];
a[i] = t;
AdjustHeap(a, 0, i); //调整堆
}
}
/*
归并排序
a:待排序元素集合
left:集合中第一个元素下标
right:集合中最后一个元素下标
步骤:
(1)将排序集合递归划分成两个集合,直到划分集合的长度为1
(2)以有序的方式合并两个有序集合
(3)重复(2)直到所有集合都合并完
*/
template<typename T>
void MergeSort(T a[], int left, int right)
{
if (left < right)
{
//分
int mid = (left + right) / 2; //二分法将集合划分成两个部分
MergeSort(a, left, mid); //递归划分左边集合
MergeSort(a, mid + 1, right); //递归划分右边集合
//合
T *tmp = new T[right - left + 1]; //建立一个临时数组,存放合并的有序序列
int i = left, j = mid + 1, k = 0; //i为左边集合下标,j为右边集合下标,k为合并集合下标
while (i <= mid && j <= right)
{
if (a[i] < a[j]) tmp[k++] = a[i++]; //左边集合值更小
else tmp[k++] = a[j++]; //右边集合值更小
}
while (i <= mid) tmp[k++] = a[i++]; //如果左边集合未遍历完
while (j <= right) tmp[k++] = a[j++]; //如果右边集合未遍历完
while (--k >= 0) a[left + k] = tmp[k]; //将临时数组拷贝回原数组
delete[] tmp; //释放空间
}
}
/*
基数节点
val:元素的值,采用字符串表示
next:该元素的下一个节点地址
*/
#include <string>
typedef struct _RadixNode
{
string val;
struct _RadixNode *next;
}RadixNode;
/*
基数排序
p:待排序元素集合,用单链表表示
r:元素的基数(对于二进制r为2,对于10进制r为10)
d:元素的位数
步骤:
(1)将集合分成r个组,r的值为集合每一位的所有可能取值的个数
(2)从集合的第d位开始,重复(3)(4)直至d的值为0,d的值为集合中元素的最大位数
(3)将集合中所有元素分配到相应的组
(4)从所有组中收集元素
*/
void RadixSort(RadixNode *&p, int r, int d)
{
RadixNode **head = new RadixNode*[r]; //存储基数的每一个字符的头节点
RadixNode **tail = new RadixNode*[r]; //存储基数的每一个字符的尾节点
while (--d >= 0) //对集合中所有数字的每一位进行分配和收集
{
//分配
for (int i = 0; i < r; i++) //初始化头结点和尾节点
head[i] = tail[i] = NULL;
while (p != NULL) //分配集合中的每一个元素
{
int i = p->val[d] - '0'; //获取元素第d位对应的字符下标
if (head[i] == NULL) //分配到对应的字符组,组中没有元素的情况
head[i] = tail[i] = p;
else //分配到对应的字符组,组中已经有元素的情况
tail[i] = tail[i]->next = p;
p = p->next;
}
//收集
p = NULL;
auto q = p;
for (int i = 0; i < r; i++) //收集每一个组的所有元素
{
if (head[i] != NULL) //组不为空收集
{
if (p == NULL) //还未收集到元素的情况
{
p = head[i];
q = tail[i];
}
else //已经收集到元素的情况
{
q->next = head[i];
q = tail[i];
}
}
}
if(q) q->next = NULL; //添加链表结束标志
}
delete[] head, tail; //释放空间
}
#include <Windows.h>
void InitRandSet(int a[], int n, int minVal, int maxVal)
{
int k = maxVal - minVal + 1;
for (int i = 0; i < n; i++)
a[i] = minVal + rand() % k;
}
void InitRadixData(RadixNode *&p, int a[], int n, int d)
{
auto *q = p;
for (int i = 0; i < n; i++)
{
if (q == NULL) p = q = new RadixNode;
else q = q->next = new RadixNode;
q->val = to_string(a[i]);
q->val = string(d - q->val.length(), '0') + q->val;
}
q->next = NULL;
}
int main()
{
const int n = 200000; //待排序集合长度
const int minVal = 0; //数据最小值,用于生成随机数据
const int maxVal = 10000; //数据最大值,用于生成随机数据
const int r = 10, d = 5; //基数排序参数d,r
int *a = new int[n]; //待排序集合数组
int *aCopy = new int[n]; //集合数组备份,因为排序后数组会变为有序,所以需要备份无序数组
InitRandSet(aCopy, n, minVal, maxVal); //生成随机数组
RadixNode *p = NULL; //基数排序数据格式
InitRadixData(p, aCopy, n, d); //基数排序数据初始化
DWORD pre_time = GetTickCount(); //保存上一个时间
auto difTime = [&pre_time]()->long { //获取时间差
DWORD dif = GetTickCount() - pre_time;
pre_time = GetTickCount();
return dif;
};
auto copySet = [&a, aCopy, n]()->void { //拷贝数组
for (int i = 0; i < n; i++)
a[i] = aCopy[i];
};
cout << "待排序集合长度:" << n << endl;
//插入排序
copySet(); InsertSort(a, n); cout << "1.插入排序:" << difTime() << "ms" << endl;
copySet(); BinaryInsertSort(a, n); cout << "2.折半插入排序:" << difTime() << "ms" << endl;
copySet(); ShellSort(a, n); cout << "3.希尔排序:" << difTime() << "ms" << endl;
//交换排序
copySet(); BubbleSort(a, n); cout << "4.冒泡排序:" << difTime() << "ms" << endl;
copySet(); QuickSort(a, 0, n - 1); cout << "5.快速排序:" << difTime() << "ms" << endl;
//选择排序
copySet(); SelectSort(a, n); cout << "6.选择排序:" << difTime() << "ms" << endl;
copySet(); HeapSort(a, n); cout << "7.堆排序:" << difTime() << "ms" << endl;
//归并排序
copySet(); MergeSort(a, 0, n - 1); cout << "8.归并排序:" << difTime() << "ms" << endl;
//基数排序
RadixSort(p, r, d); cout << "9.基数排序:" << difTime() << "ms" << endl;
delete[] a, aCopy; //释放资源
while (p != NULL) { auto q = p; p = p->next; delete q; } //释放链表申请的空间
while (1) cin.get();
return 0;
}
参考资料:
[1] 李春葆.数据结构教程.清华大学出版社,2013.