文章目录

  • 1. 排序算法总结
  • 2. 高精度计时器配合随机数进行性能测试
  • 3. 性能测试

1. 排序算法总结




这些高度总结的图也是将排序算法进行了一个深刻的总结,在此不必过分多说。

基于学习角度,肯定是首先考虑学习一些简单的排序算法,如直接插入排序、二分插入排序,再者就希尔排序、堆排序等中级排序算法,然后就是排序算法的精华所在:快速排序、归并排序等高级排序算法。这也是一个循序渐进的过程,理解每一个排序算法的细节,能否进行手撕代码、复杂度分析算是对基本的排序算法有所掌握。但是,我们学习算法的目的是为了应用到实际问题中,帮助我们快速解决问题,这也是前半段学习排序算法的不足之处。

所以这篇博文是作为一个承前启后的作用,总结前半段最为基础的排序算法的基本知识,并为后面的 OJ 习题做铺垫,力求熟练掌握排序算法。

2. 高精度计时器配合随机数进行性能测试

高精度计时.h 你没看错,就是中文的变量、类命名~~~

#include <windows.h>class 高精度计时
{public:高精度计时(void){QueryPerformanceFrequency(&CPU频率);}~高精度计时(void) {}void 开始(){QueryPerformanceCounter(&开始时间);}void 结束(){QueryPerformanceCounter(&结束时间);间隔 = ((double)结束时间.QuadPart - (double)开始时间.QuadPart) / (double)CPU频率.QuadPart;}double 间隔毫秒() const{return 间隔 * 1000;}private:double 间隔;LARGE_INTEGER 开始时间;LARGE_INTEGER 结束时间;LARGE_INTEGER CPU频率;
};

随机数测试函数:

#define  SIZE (5 * 1000)
void TestSpeed() {int array[SIZE];int size = SIZE;srand(20190118);for (int i = 0; i < size; i++) {array[i] = rand() % size;}QuickSort(array,0, size);高精度计时  计时器;计时器.开始();HeapSort(array, size);计时器.结束();printf("耗时: %f 毫秒\n", 计时器.间隔毫秒());
}

sort.h 这些天来的所有排序算法源代码:

#include <iostream>
#include <assert.h>
#include "高精度计时.h"using namespace std;void PrintArray(int array[], int size) {for (int i = 0; i < size; ++i) {printf("%d ", array[i]);}printf("\n");
}void Swap(int *x, int *y) {int tmp = *x;*x = *y;*y = tmp;//*x = ((*x) ^ (*y));//*y = ((*x) ^ (*y));//*x = ((*x) ^ (*y));
}// 直接插入排序(递增)
void InsertSort(int array[], int size) {for (int i = 1; i < size; ++i) {  // 遍历arrayint k = array[i];int j = i - 1;for (j; j >= 0; --j) {       // 与array[i]前面各个元素比较if (array[j] <= k) {    // 如果比前一个元素大,说明前半段已经有序,返回break;}array[j + 1] = array[j];    // 将大于array[i]的元素向后移动,注意从后向前赋值}array[j + 1] = k;   // 在前半段有序处插入array[i]}
}// 二分插入排序(递增)
void BinInsertSort(int array[], int size) {for (int i = 1; i < size; ++i) {   // 遍历arrayif (array[i] < array[i - 1]) {int k = array[i];int j = i - 1;int left = 0, right = i - 1, mid = 0;    // 直接对前段数据进行二分查找,找到array[i]应有的位置while (left <= right) {mid = (left + right) / 2;   // 取中间位置if (k < array[mid]) {right = mid - 1;   // 插入点在左半区}else {left = mid + 1;      // 插入点在右半区}}                            // 找到位置 rightfor (j; j >= right + 1; --j) {array[j + 1] = array[j];  // 将大于array[i]的元素向后移动,注意从后向前赋值}array[right + 1] = k;   // 在前半段有序处插入array[i]}}
}// 希尔排序(递增)
void ShellSort(int array[], int size) {int gap = size;while (1) {gap = (gap / 3) + 1;for (int i = gap; i < size; i++) {int k = array[i];int j;for (j = i - gap; j >= 0; j -= gap) {if (array[j] <= k) {break;}array[j + gap] = array[j];}array[j + gap] = k;}if (gap == 1) {break;}}
}// 冒泡排序(递增)
void BubbleSort(int array[], int size) {for (int i = 1; i < size; ++i) {int sorted = 1;for (int j = 0; j < size - i; ++j) {    // 将剩余数据的最大值归位if (array[j] > array[j + 1]) {int tmp = array[j];array[j] = array[j + 1];array[j + 1] = tmp;sorted = 0;}}if (sorted == 1) {       // 在一趟中没有排序,则算法结束break;}}
}// 快速排序(递增)
// 三数取中法
int BaseNumber(int array[], int begin, int end) {int mid = begin + ((end - begin) >> 1);        // 采用位运算效率高if (array[begin] > array[mid]) {      // 逻辑判断取出中位数的下标,当然排序及其它方法均可if (array[begin] > array[end]) {if (array[mid] > array[end]) {return mid;}else {return end;}}else {return begin;}}else {if (array[mid] > array[end]) {if (array[begin] > array[end]) {return begin;}else {return end;}}else {return mid;}}
}// 快速排序(递增)
// hoare版本
int QuickSort1(int array[], int begin, int end) {// 找基准// 由于每次规划取到最大值或最小值的概率都非常高,// 这样容易使树变成单支树,所以采用三数取中法来降低取到最值的概率//int index = BaseNumber(array, begin, end);  // 基准值在数组中的下标//if (index != end) {//   Swap(&array[index], &array[end]);   // 将基准值与最后一个数字进行值交换//}// 基准值int key = array[end];// 基准值的下标int k = end;// 两个指针、begin从0开始,end从size-1开始while (begin != end) {// begin向后移动,找比基准值大的元素,且begin不能大于end// 如果array[begin]比key小,则++beginwhile (array[begin] <= key && (begin < end)) {++begin;}// end向前移动,找比基准值key小的元素,且end不能小于begin// 如果array[end]比key大,则--endwhile (array[end] >= key && (begin < end)) {--end;}// 如果下标begin和下标end不相等,则交换所对应的数组元素值if (begin != end) {Swap(&array[begin], &array[end]);}}// 如果begin的最终位置就是基准的位置则不用交换if (begin != k) {// 将基准值挪到相应位置上Swap(&array[begin], &array[k]);}return begin;
}// 快速排序(递增)
// 挖坑法
int QuickSort2(int array[], int begin, int end) {// 依旧三数取中法确定基准int index = BaseNumber(array, begin, end);if (index != end) {Swap(&array[index], &array[end]);}// 第一个坑int key = array[end];int k = end;while (begin != end) {// begin从左边开始找比关键字大的元素将其入坑// begin所在位置变为坑while (array[begin] <= key && begin < end) {++begin;}if (begin != end) {array[end] = array[begin];--end;}// end从右开始找比关键字小的元素将其入begin坑while (array[end] >= key && begin < end) {--end;}if (begin != end) {array[begin] = array[end];++begin;}}if (begin != k) {array[begin] = key;}return begin;
}// 快速排序(递增)
// 双指针方法
int QuickSort3(int array[], int begin, int end) {int index = BaseNumber(array, begin, end);int cur = begin, prev = begin - 1;if (index != end) {Swap(&array[index], &array[end]);}int key = array[end];// cur不能超过序列长度while (cur <= end) {if (array[cur] <= key && ++prev != cur) {Swap(&array[cur], &array[prev]);}++cur;}return prev;
}// 快排递归实现(递增)
void QuickSort(int array[], int left, int right) {/*// 由于快速排序是递归调用,容易产生栈溢出// 但是快速排序排到最后元素也接近有序,则采用插入排序if (right - left < 2) {InsertSort(array + left, right - left);}*/// 数据较小时,直接判断即可if (left == right) {return;        // 区间内只有一个数}if (left > right) {return;       // 区间内没有数}// 基准值是array[right]int pos;pos = QuickSort1(array, left, right - 1); // 仅修改QuickSort1,1,2,3即可完成测试QuickSort(array, 0, pos);    // 快速排序基准值左侧QuickSort(array, pos + 1, right);  //快速排序基准值右侧}// 快排非递归实现(递增)
// 模拟实现栈
typedef struct Stack {int *data;int size;
}stack;void InitStack(stack *s) {int *data = (int*)malloc(20 * sizeof(int));if (data == NULL) {assert(0);return;}s->data = data;s->size = 0;
}void PushStack(stack *s, int d) {assert(s);if (s->size > 20) {return;}else {s->data[s->size++] = d;}
}void PopStack(stack *s) {assert(s);if (s->size == 0) {return;}else {s->size--;}
}int TopStack(stack *s) {assert(s);return s->data[s->size - 1];
}int EmptyStack(stack *s) {assert(s);return s->size == 0;
}// 快排非递归实现(递增)
void QuickSortStack(int array[], int size) {stack s;int pos, left = 0, right = 0;InitStack(&s);PushStack(&s, 0);PushStack(&s, size - 1);while (!EmptyStack(&s)) {right = TopStack(&s);PopStack(&s);left = TopStack(&s);PopStack(&s);if (left >= right) {continue;}else {pos = QuickSort1(array, left, right);//先快排基准左侧,则先将后侧的下标入栈if ((right - left) > pos + 1) {PushStack(&s, pos + 1);PushStack(&s, right - left);}if (pos > 0) {PushStack(&s, 0);PushStack(&s, pos - 1);}}}
}// 直接选择排序(递增)
void SelectSort(int array[], int size) {for (int i = 0; i < size; ++i) {// [0, size - i)int m = 0;for (int j = 0; j < size - i; ++j) {if (array[j] > array[m]) {m = j;}}// m 就是最大数的下标了//if (array + m == array + size - i - 1)//   continue;Swap(array + m, array + size - i - 1);}
}// 升级版直接选择排序,一次即找最大的,也找最小的
void SelectSortOP(int array[], int size) {int minSpace = 0;            // 用来放找到的最小数的下标int maxSpace = size - 1;    // 用来放找到的最大数的下标// 因为是闭区间,minSpace == maxSpace 时// [minSpace, maxSpace] 区间内只剩一个数了// 所有可以停止了while (minSpace < maxSpace) {int min = minSpace; // 假设最小的是 minSpace 位置int max = minSpace; // 假设最大的是 minSpace 位置// 在 [minSpace + 1, maxSpace] 区间里找真正的最小和最大for (int j = minSpace + 1; j <= maxSpace; j++) {if (array[j] < array[min]) {min = j;}if (array[j] > array[max]) {max = j;}}// min 和 max 分别时最小和最大的数的下标// 先交换小的{int t = array[min];array[min] = array[minSpace];array[minSpace] = t;}// 再交换大的if (max == minSpace) {max = min;}{int t = array[max];array[max] = array[maxSpace];array[maxSpace] = t;}minSpace++;maxSpace--;}
}// 堆排序(递增)
// 大顶堆的向下调整
void AdjustDown(int array[], int size, int r) {int left = 2 * r + 1;int right = 2 * r + 2;if (left >= size) {       // 是否为叶子节点return;           // 叶子节点直接结束}int m = left;      // 有左孩子// 是不是有右孩子,并找最大的孩子if (right < size && array[right] > array[left]) {m = right;}// 如果根的值大于最大孩子,直接返回if (array[r] >= array[m]) {return;}Swap(array + r, array + m);    // 将最大值最为新的根AdjustDown(array, size, m);     // 递归向下调整
}// 建堆
void CreateHeap(int array[], int size) {// i=最后一个非叶子节点// 已知parent,则 left=2* parent+1,right=2*parent+2// 已知child,则parent=(child-1)/2,在此均为数组的下标// 故最后一个非叶子节点,就是数组最后一个下标size-1,再-1,结果除2即可for (int i = (size - 1 - 1) / 2; i >= 0; --i) {AdjustDown(array, size, i);}
}// 堆排序(递增)
void HeapSort(int array[], int size) {CreateHeap(array, size);for (int i = 0; i < size; ++i) {Swap(array, array + size - i - 1);AdjustDown(array, size - i - 1, 0);}
}// 归并排序(递增)
// 合并两个有序序列
void Merge(int array[], int left, int mid, int right, int extra[]) {int size = right - left;int left_index = left;int right_index = mid;int extra_index = 0;while (left_index < mid && right_index < right) {if (array[left_index] <= array[right_index]) {extra[extra_index] = array[left_index];++left_index;}else {extra[extra_index] = array[right_index];++right_index;}extra_index++;}while (left_index < mid) {extra[extra_index++] = array[left_index++];}while (right_index < right) {extra[extra_index++] = array[right_index++];}for (int i = 0; i < size; i++) {array[left + i] = extra[i];}
}void __MergeSort(int array[], int left, int right, int extra[]) {// 终止条件if (right == left + 1) {// 只剩一个数return;}if (right <= left) {// 区间内没有数了return;}int mid = left + (right - left) / 2;// [left, mid)  [mid, right)__MergeSort(array, left, mid, extra);__MergeSort(array, mid, right, extra);// 左右区间都有序Merge(array, left, mid, right, extra);
}void MergeSortNor(int array[], int size) {int *extra = (int *)malloc(sizeof(int)* size);for (int i = 1; i < size; i = i * 2) {for (int j = 0; j < size; j = j + 2 * i) {int left, mid, right;left = j;mid = j + i;right = mid + i;if (mid >= size) {// 没有右边的区间 [mid, right)continue;}if (right > size) {right = size;}Merge(array, left, mid, right, extra);}}free(extra);
}// 归并排序(递增)
void MergeSort(int array[], int size) {int *extra = (int *)malloc(sizeof(int)* size);__MergeSort(array, 0, size, extra);free(extra);
}// 桶排序(递增)
#define BUCKSIZE    100
typedef struct {int data[BUCKSIZE];int count;       // 桶中元素的个数
} BuckType;         // 桶类型void BucketSort(int array[], int size) {int max, min, num, pos;BuckType *pB;max = min = array[0];for (int i = 1; i < size; ++i) {if (array[i] > max) {max = array[i];}else if (array[i] < min) {min = array[i];}}num = (max - min + 1) / 10 + 1;       // 求出桶的个数pB = (BuckType*)malloc(sizeof(BuckType) * num);memset(pB, 0, sizeof(BuckType) * num);for (int i = 0; i < size; ++i) {           // 将数组元素分配进桶int k = (array[i] - min + 1) / BUCKSIZE;  // 求出array[i]对应的桶号,在此为10个桶(pB + k)->data[(pB + k)->count] = array[i];(pB + k)->count++;}pos = 0;for (int i = 0; i < num; ++i) {QuickSort((pB + i)->data, 0, (pB + i)->count);  // 单个桶快速排序for (int j = 0; j < (pB + i)->count; ++j) {array[pos++] = (pB + i)->data[j];}}
}// 基数排序(递增)
// 动态二维数组实现
int Maxbit(int array[], int size) {     // 求待排序序列最大元素位数int maxvalue = array[0], digits = 0;   // 初始化最大元素为array[0],最大位数为0for (int i = 1; i < size; i++) {    // 找到序列中最大元素if (array[i] > maxvalue)maxvalue = array[i];}while (maxvalue != 0) {       // 分解得到最大元素的位数digits++;maxvalue /= 10;}return digits;
}int Bitnumber(int x, int bit) {        // 求x第bit位上的数字,例如238第2位上的数字为3int temp = 1;for (int i = 1; i < bit; ++i) {temp *= 10;}return (x / temp) % 10;
}// 基数排序(递增)
// 动态二维数组实现
void RadixSort(int array[], int size) {int i, j, k, bit, maxbit;maxbit = Maxbit(array, size);  //求最大元素位数cout << "最大元素位数为:" << maxbit << "位 " << endl;int **B = new int *[10];  // 分配二维动态数组for (i = 0; i < 10; ++i)B[i] = new int[size + 1];    // 每个桶都是size+1个空间,其中每个桶的第一个位置即B[0]第0位存放元素个数for (i = 0; i < 10; i++)B[i][0] = 0;  // 统计第i个桶的元素个数// 从个位到高位,对不同的位数进行桶排序for (bit = 1; bit <= maxbit; ++bit) {for (j = 0; j < size; j++) {    // 分配 int num = Bitnumber(array[j], bit);  // 取array[j]第bit位上的数字int index = ++B[num][0];B[num][index] = array[j];}for (i = 0, j = 0; i < 10; ++i) { // 收集for (k = 1; k <= B[i][0]; ++k)array[j++] = B[i][k];B[i][0] = 0; // 收集后元素个数置零}}for (int i = 0; i < 10; i++)delete[]B[i];delete B;
}// 基数排序(递增)
// 一维数组实现
const int maxn = 1000;
int a[maxn], size;
int maxbit(int array[], int size) { //辅助函数,求数据的最大位数int d = 1;//统计最大的位数int p = 10;for (int i = 0; i < size; ++i) {while (array[i] >= p) {p *= 10;++d;}}return d;
}// 基数排序(递增)
// 一维数组实现
void radixsort(int array[], int size) {int d = maxbit(array, size); // 求最大位数 int *tmp = new int[size]; // 辅助数组 int *count = new int[10]; // 计数器int i, j, k;int radix = 1;for (i = 1; i <= d; i++) { // 进行d次排序for (j = 0; j < 10; ++j) {count[j] = 0; // 每次分配前清空计数器}for (j = 0; j < size; ++j) {k = (array[j] / radix) % 10; // 取出个位数,然后是十位数,... count[k]++;  // 统计每个桶中的记录数}for (j = 1; j < 10; ++j) {count[j] += count[j - 1]; // 将tmp中的位置依次分配给每个桶}for (j = size - 1; j >= 0; --j) { //将所有桶中记录依次收集到tmp中k = (array[j] / radix) % 10;tmp[--count[k]] = array[j];}for (j = 0; j < size; j++) {   // 将临时数组的内容复制到array中array[j] = tmp[j];}cout << "第" << i << "次排序结果:" << endl;for (int i = 0; i < size; ++i)cout << array[i] << "   ";cout << endl;radix = radix * 10;}delete[]tmp;delete[]count;
}// 测试函数
void TestRight() {int array[] = { 3, 9, 1, 4, 2, 8, 2, 7, 5, 3, 6, 11, 9, 4, 2, 5, 0, 6 };int size = sizeof(array) / sizeof(int);SelectSortOP(array, size);PrintArray(array, size);
}#define    SIZE (5 * 1000)
void TestSpeed() {int array[SIZE];int size = SIZE;srand(20190118);for (int i = 0; i < size; i++) {array[i] = rand() % size;}// 需要有序序列时可调用// QuickSort(array,0, size);高精度计时  计时器;计时器.开始();HeapSort(array, size);计时器.结束();printf("耗时: %f 毫秒\n", 计时器.间隔毫秒());
}

main.cpp主函数:

#include "sort.h"int main() {TestRight();TestSpeed();system("pause");return 0;
}

3. 性能测试

有序 乱序 逆序
冒泡 0.2ms 7.9s
插排 0.2ms 1.7s
希尔 2.3ms 10ms
选择 3.4s 3.3s
选择OP 4.7s 2s
堆排序 9ms 15ms

测了测库的 sort() 函数,真——被吊打…感兴趣者自行测试…

[排序算法] 13. 常见排序算法总结及运用高精度计时模板测试性能(复杂度分析、高精度计时、总结)相关推荐

  1. java常见的排序算法_常见排序算法及Java实现

    先上个总图↓: ①.直接插入排序 插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并 ...

  2. 排序上---(排序概念,常见排序算法,直接插入,希尔排序,直接选择排序,堆排序)

    排序的概念 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作. 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对 ...

  3. 【排序算法】常见排序算法总结

    一.排序算法概述 排序,即将一组数据按照递增或递减的规则进行排列.根据不同的规则,排序算法的分类也不尽相同,常见分类标准有:内部排序和外部排序.内部排序是数据记录在内存中进行排序,而外部排序是因排序的 ...

  4. php 版本排序,四种常见排序算法--PHP版本

    1.冒泡排序法 /** * 冒泡排序 * des 对一组数据,比较相邻数据的大小,将值小数据在前面,值大的数据放在后面. */ $array = [2,5,1,3,7,4]; $result = bu ...

  5. python常见的排序算法_常见排序算法之python实现

    1. 冒泡排序 时间复杂度为O(n^2), 稳定的排序算法 思路:一开始比较的区间是[0,n-1],依次比较相邻两数,哪个数大哪个数就放在后面,这样一次遍历数组后,最大的数会在数组的最后一个位置,然后 ...

  6. java的一段排序代码_Java常见排序算法——快速排序

    概念: 通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分小,则可分别对这两部分记录继续进行排序,直到整个序列有序. 原理: 在数据集之中,选择一个元素作为"基准 ...

  7. 算法 | Java 常见排序算法(纯代码)

    目录 汇总 1. 冒泡排序 1. 冒泡排序 每轮循环确定最值: public void bubbleSort(int[] nums) { int temp; boolean isSort = fals ...

  8. 【聚类算法】常见聚类算法总结

    转自:https://blog.csdn.net/u010062386/article/details/82499777 感谢博主 1.常见算法 1.原型聚类 "原型"是指样本空间 ...

  9. 【推荐算法】常见优化算法总结(BGD、SGD、Momentum、Nesterov、Adagrad、AdaDelta、Adam)

    文章目录 前言 BGD SGD Momentum Nesterov Adagrad AdaDelta Adam 前言 对深度学习中常见优化器进行总结,包括BGD.SGD.Momentum.Nester ...

  10. 十种常见排序算法欢聚一堂

    文章目录 1.常见排序算法分类 2.非线性时间比较类排序 2.1 交换类排序 2.1.1 冒泡排序 2.1.2 快速排序 2.2 插入类排序 2.2.1 直接插入排序 2.2.2 Shell 排序 2 ...

最新文章

  1. 多个前端项目放在一个git好还是_前端工作流
  2. 使用 jQuery 简化 Ajax 开发.
  3. C++函数模板(一)
  4. Python基础教程:set集合的教程
  5. 中国互联网保险代理人生存状况调查报告
  6. transact-sql_如何使用Transact-SQL创建,配置和删除SQL Server链接服务器
  7. java数组_Java数组
  8. 3.2配置自定义的路径映射
  9. 全网最好用的VS Code插件推荐
  10. http三次握手_图文深入http三次握手核心问题【思维导图】
  11. 使用OTL连接数据库有感篇(一)
  12. 你是否了解新媒体,新媒体简介
  13. chromium 安装flash player
  14. 学编程必看:10道逻辑思维测试题(附答案)
  15. Word2013中如何去掉页眉横线
  16. 我的硬件工程师成长之路
  17. 如何确立人生目标?100个人生目标清单总汇
  18. D3D11_Chili_Tutorial(2):画一个三角形
  19. 美国男人欢迎中国的丑女人?------------说说洁
  20. 算法笔记(六):差分法

热门文章

  1. DDD领域驱动设计笔记
  2. WinRAR破解注册方法
  3. Python计算时间差天数
  4. grafana mysql 变量_grafana之Variables变量的使用
  5. 小女子12行代码实现Javascript双向数据绑定两个input框
  6. 重磅!罗振宇跨年演讲:扎心5问
  7. 各种手段终于将土豆视频url请求找到了
  8. oracle超级管理员忘记_Oracle 管理员账号密码忘记的快速解决方法
  9. android N编译
  10. led大屏按实际尺寸设计画面_led显示屏尺寸大小要怎么算