目录
一、排序的概念
二、排序的分类
三、交换排序(省略冒泡)
1、概念
2、算法思想
3、实现原理
4、快速排序代码
四、归并排序
1、概念
2、代码实现
五、堆排序
1、堆排序基本思想
2、代码实现
六、插入排序
1、概念
2、代码实现
七、基数排序
1、概述
2、代码实现
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。(递增或递减)
一图以蔽之:
1、概念
快速排序:
又称划分交换排序(partition-exchange sort),简称快排,一种排序算法,最早由东尼·霍尔提出。在平均状况下,排序n个项目要 O(n log2 n)(大O符号)次比较。在最坏状况下则需要 O(n^2)次比较,但这种状况并不常见。事实上,快速排序 (n log n)通常明显比其他算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地达成。
——(维基百科)
快速排序:
分治排序的一种排序算法,它将一个数组分成两个子数组,将两个部分独立的排序。快速排序和归并排序是互补的,归并排序将数组分成两个子数组分别排序,并将有序的子数组归并以将整个数组排序,而快速排序则是就当两个子数组都有序时,整个数组就自然有序了。归并中,递归调用发生在处理整个数组之前,而在快速中,递归调用发生在处理整个数组之后
2、算法思想
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
3、实现原理
(1)设置两个变量 low、high,排序开始时:low=0,high=size-1。
(2)整个数组找基准正确位置,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面
(a)默认数组的第一个数为基准数据,赋值给key,即key=array[low]。
(b)因为默认数组的第一个数为基准,所以从后面开始向前搜索(high–),找到第一个小于key的array[high],就将 array[high] 赋给 array[low],即 array[low] = array[high]。(循环条件是 array[high] >= key;结束时 array[high] < key)
(c)此时从前面开始向后搜索(low++),找到第一个大于key的array[low],就将 array[low] 赋给 array[high],即 array[high] = array[low]。(循环条件是 array[low] <= key;结束时 array[low] > key)
(d)循环 2-3 步骤,直到 low=high,该位置就是基准位置。
(e)把基准数据赋给当前位置。
(3)第一趟找到的基准位置,作为下一趟的分界点。
(4)递归调用(recursive)分界点前和分界点后的子数组排序,重复2.2、2.3、2.4的步骤。
(5)最终就会得到排序好的数组。
4、快速排序代码
#include
using namespace std; void display(int* array, int size) { for (int i = 0; i < size; i++) { cout< = key) { j--; } /// 当找到比 array[i] 小的时,就把后面的值 array[j] 赋给 坑 if (i < j) { array[i] = array[j]; } /// 当队首元素小于等于基准数据时,就一直向后挪动 i 指针 while (i < j && array[i] <= key) { i++; } /// 当找到比 array[j] 大的时,就把前面的值 array[i] 赋给 新坑 if (i < j) { array[j] = array[i]; } } /// 跳出循环时 i 和 j 相等,此时的 i 或 j 就是 key 的正确索引位置 /// 把基准数据赋给正确位置(基准数据的坑) array[i] = key; return i; } void QuickSort(int array[], int low, int high) { /// 开始默认基准为 low if (low < high) { /// 分段位置下标 int standard = getStandard(array, low, high); /// 递归调用排序 /// 左边排序 QuickSort(array, low, standard - 1); /// 右边排序 QuickSort(array, standard + 1, high); } } /// 合并到一起的快速排序,与上面的是一样的 // void QuickSort(int array[], int low, int high) { // if (low < high) { // int i = low; // int j = high; // int key = array[i]; // while (i < j) { // while (i < j && array[j] >= key) { // j--; // } // if (i < j) { // array[i] = array[j]; // } // while (i < j && array[i] <= key) { // i++; // } // if (i < j) { // array[j] = array[i]; // } // } // array[i] = key; // QuickSort(array, low, i - 1); // QuickSort(array, i + 1, high); // } // } int main() { int array[] = {49, 38, 65, 97, 76, 13, 27, 49, 10}; int size = sizeof(array) / sizeof(int); /// 打印数据 cout<
1、概念
归并排序是一种效率较高的排序方法,它分为拆分和合并两大部分,先拆后合。
所谓拆分,就是将一堆无序的数拆成单个,方便合并。
所谓合并,就是将拆分好的数按照排序规则再拼凑起来。
详细解释请看下图:
看完这幅图你应该明白了,归并排序原来就是将一堆数字分开,再合成有序的数列。其实,这就是分治的思想,将大问题化小问题,将每个最小的问题处理好,合并起来大问题也就处理好了。
2、代码实现
#include
using namespace std; ///每一趟合并 void merge(int* data,int* tmp,int left,int mid,int right){ int i=left,j=mid+1; int k=left; while(i<=mid&&j<=right){ if(data[i]>n; int* data=new int[n]; for(int i=0;i >data[i]; for(int i=0;i
1、堆排序基本思想
(1)将待排序序列构造成一个大顶堆。
(2)此时,整个序列的最大值就是堆顶的根节点。
(3)将其与末尾元素进行交换, 此时末尾就为最大值。
(4)然后将剩余 n-1 个元素重新构造成一个堆, 这样会得到 n 个元素的次小值。 如此反复执行, 便能得到一个有序序列了。
最后可以看到在构建大顶堆的过程中, 元素的个数逐渐减少,最后就得到一个有序序列了。
注:一般升序采用大顶堆, 降序采用小顶堆。
2、代码实现
/**以大顶堆举例*/ #include
using namespace std; void Max_heap(int arr[], int first, int last){ int par = first; int son = par * 2 + 1; while(son <= last){ if(son < last && arr[son] < arr[son + 1]){ son++; } if(arr[par] > arr[son]){///如果满足,那么就直接返回 return; }else{ int temp = arr[par]; arr[par] = arr[son]; arr[son] = temp;///交换顺序 par = son; son = par * 2 + 1;///再次进入循环 } } } void heap_sort(int arr[], int len){ for(int i = len / 2 - 1;i >= 0;i--){ ///从最后一个非叶子节点开始往回走 Max_heap(arr, i, len-1); }///先排好形成大顶堆 ///下面代码:先将第一个元素和已经排好元素前一位作交换,再进行堆排序 for(int i = len - 1;i > 0;i--){ int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; Max_heap(arr, 0, i - 1); } } int main(){ int n;///一共有多少数据 cin>>n; int* arr=new int[n+1];///要排序的数据 for(int i = 0;i < n;i++){ cin>>arr[i]; } heap_sort(arr, n); for(int i = 0;i < n;i++){ cout<
1、概念
(1)直接插入排序
把待排序的数据插入到已经排好序的数据中,直到所有的数据插入完成,即就是直接插入排序。(如流行于陕西一带的纸牌游戏,挖坑)一般待排序的区间是第二个数到最后一个数。注意动态移动插入的过程,结合图与代码去理解。例如下面的例子就是待排序区间从 7 到 8,把第一个数当作已经排序的数据:
(2)希尔排序
希尔排序实在前面直接插入排序的基础上进行改进的一种排序。直接插入排序的变量 i 其实就是一个间隔,而希尔排序的间隔不是 1,它的间隔逐渐缩小直到为 1 的一种排序(当间隔gap到达1时停止),因此又叫缩小增量法。它是对直接插入排序算法的优化,当间隔不为 1 的时候,都是预排序。下图是举例,第一次的间隔是数据长度的三分之一再加一。即 gap = size / 3 + 1
2、代码实现
#include
using namespace std; ///初始化数组 void SetArray(int *data, int size) { //srand(time(0)); cout << "随机初始化" << size << "个数" << endl; for (int i = 0; i < size; i++) { data[i] = rand() % 100 + 1; } } ///打印函数 void Print(int *data, int size) { for (int i = 0; i < size; i++) { cout << data[i] << " "; } cout << endl; } ///交换函数 void Swap(int &a, int &b) { int tmp = a; a = b; b = tmp; } ///冒泡排序 void Bubble_Sort(int *data, int size) { for (int i = size - 1; i >= 0; i--) { bool flag = false; //、是否交换标志 for (int j = 0; j < i; j++) { if (data[j + 1] < data[j]) { Swap(data[j], data[j + 1]); flag = true;//发生了交换 } } if (flag == false) {//全程无交换 break; } } } ///直接插入排序 void Insertion_Sort(int *data, int size) { for (int i = 1; i < size; i++) { int tmp = data[i]; int j; for (j = i; j > 0 && data[j - 1] > tmp; j--) { ///前一个数大于后一个树,进行交换 data[j] = data[j - 1]; } ///找到合适位置,进行插入 data[j] = tmp; } } ///折半插入排序 void Binary_Insertion_Sort(int *data, int size) { for (int i = 1; i < size; i++) { int low = 0, high = i - 1;//在i之前找到最佳位置 int tmp = data[i], mid, j; while (low <= high) {//寻找最佳位置 mid = (low + high) / 2; if (data[mid] < tmp) { //大于中间值,到右半部分寻找 low = mid + 1; } else {//小于中间值,到左半部分寻找 high = mid - 1; } } for (j = i; j > low; j--) { data[j] = data[j - 1]; } data[j] = tmp; } } ///希尔排序(通俗易懂版) void ShellInsert(int *arr, int len, int gap) { int k, i, j, temp; ///k循环是处理每一组 for (k = 0; k < gap; k++) { ///i循环是调用了其中一组进行排序 for (i = k; i < len; i += gap) { ///temp是某组第i个数值(都是比较序列的最后一个) temp = arr[i]; ///k永远的每一组的第一个 for (j = i; j > k; j -= gap) { ///条件符合temp与arr[j]交换 if (temp > arr[j - gap]) arr[j] = arr[j - gap]; else break; } arr[j] = temp; } } } ///调用希尔排序,确定gap(gap大小是循环除以2) void ShellSort(int *arr, int len) { int gap = len / 2; while (true) { ShellInsert(arr, len, gap); Print(arr, len); if (gap == 1) break; gap /= 2; } } ///改进版希尔排序 void Shell_sort(int *arr, int len) { int i, j, gap, key; ///初始间隔:n/2,每一趟之后除以2 for (gap = len / 2; gap > 0; gap /= 2) { ///每一趟采用插入排序,为什么是i++而不是i+=gap呢,因为是每一组都处理一下 for (i = gap; i < len; i++) { key = arr[i]; for (j = i; j >= gap && key < arr[j - gap]; j -= gap) arr[j] = arr[j - gap]; ///找到合适位置,进行插入 arr[j] = key; } Print(arr, len); } } int main() { cout << "请输入数组长度:" << endl; int size, *data; cin >> size; data = new int[size]; SetArray(data, size); cout << "冒泡排序前:" << endl; Print(data, size); cout << "冒泡排序后:" << endl; Bubble_Sort(data, size); Print(data, size); SetArray(data, size); cout << "直接插入排序前:" << endl; Print(data, size); cout << "直接插入排序后:" << endl; Insertion_Sort(data, size); Print(data, size); SetArray(data, size); cout << "折半插入排序前:" << endl; Print(data, size); cout << "折半插入排序后:" << endl; Binary_Insertion_Sort(data, size); Print(data, size); SetArray(data, size); cout << "希尔排序前:" << endl; Print(data, size); cout << "希尔排序后:" << endl; ShellSort(data, size); //Shell_sort(data,size); Print(data, size); return 0; }
1、概述
基数排序的知识点我就不贴出来,相信都能搜到对应概念解释,下面就直接上代码,代码解释其实也很清晰了。
2、代码实现
#include
using namespace std; ///补充:(arr[i] / exp) % 10 这个表达式很重要哦,作用是截取到某个数的某一位 /// 获取数组arr中最大值,arr——待排序的数组,len——数组arr的长度。 int arrmax(int *arr, int len) { int i, imax; imax = arr[0]; for (i = 1; i < len; i++) if (arr[i] > imax) imax = arr[i]; return imax; } /// 对数组arr按指数位进行排序。 /// arr——待排序的数组,len——数组arr的长度。 /// exp——排序指数,exp=1:按个位排序;exp=10:按十位排序;...... void _radixsort(int *arr, int len, int exp) { int i; int result[len]; /// 存放从桶中排序好收集到的数据的临时数组。 int buckets[10] = {0}; /// 初始化10个桶。 ///遍历arr,将数据出现的次数存储在buckets中。 for (i = 0; i < len; i++) buckets[(arr[i] / exp) % 10]++; ///调整buckets各元素的值,调整后的值就是arr中元素在result中的位置。 ///核心是下面两行代码,我暂时不知道怎么解释。下面两行代码处理完后buckets的数字 ///代表的是该桶前面有多少个已经排好序的数 for (i = 1; i < 10; i++) buckets[i] = buckets[i] + buckets[i - 1]; /// 将arr中的元素填充到result中。注意:一定得是倒序从后面一个一个读取哦! ///再说一遍,这里的倒序取非常关键! for (i = len - 1; i >= 0; i--) { int iexp = (arr[i] / exp) % 10; result[buckets[iexp] - 1] = arr[i]; buckets[iexp]--; } /// 将排序好的数组result复制到数组arr中。 ///memcpy(arr, result, len * sizeof(int)); for (int i = 0; i < len; i++) arr[i] = result[i]; } /// 基数排序主函数,arr——待排序的数组,len——数组arr的长度。 void radixsort(int *arr, int len) { int imax = arrmax(arr, len); /// 获取数组arr中的最大值。 int iexp; /// 排序指数,iexp=1:按个位排序;iexp=10:按十位排序;...... /// 从个位开始,对数组arr按指数位进行排序。 for (iexp = 1; imax / iexp > 0; iexp = iexp * 10) { _radixsort(arr, len, iexp); int i; ///cout << iexp << " "; ///输出指数 for (i = 0; i < len; i++) cout << arr[i] << " "; cout << endl; } } int main() { ///int arr[] = {144, 203, 738, 905, 347, 215, 836, 26, 527, 602, 946, 504, 219, 750, 848}; ///int len = sizeof(arr) / sizeof(int); int len; cin >> len; int *data = new int[len]; for (int i = 0; i < len; i++) cin >> data[i]; for (int i = 0; i < len; i++) cout << data[i] << " "; cout<
我是花花,祝自己也祝您变强了~