赞
踩
目录
排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。(递增或递减)
一图以蔽之:
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<iostream> using namespace std; void display(int* array, int size) { for (int i = 0; i < size; i++) { cout<<array[i]; if(i!=size-1) cout<<" "; } cout<<endl; } int getStandard(int array[], int i, int j) { /// 基准数据 int key = array[i]; /// i是low,j是high,整个大循环如果i==j就停止 while (i < j) { /// 因为默认基准是从左边开始,所以从右边开始比较 /// 当队尾的元素大于等于基准数据时,就一直向前挪动 j 指针 while (i < j && array[j] >= 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<<size<<" \n"; QuickSort(array, 0, size - 1); display(array, size); return 0; }
1、概念
归并排序是一种效率较高的排序方法,它分为拆分和合并两大部分,先拆后合。
所谓拆分,就是将一堆无序的数拆成单个,方便合并。
所谓合并,就是将拆分好的数按照排序规则再拼凑起来。
详细解释请看下图:
看完这幅图你应该明白了,归并排序原来就是将一堆数字分开,再合成有序的数列。其实,这就是分治的思想,将大问题化小问题,将每个最小的问题处理好,合并起来大问题也就处理好了。
2、代码实现
#include <iostream> 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]<data[j]) tmp[k++]=data[i++]; else tmp[k++]=data[j++]; } while(i<=mid) tmp[k++]=data[i++]; while(j<=right) tmp[k++]=data[j++]; for(int i=left;i<=right;i++) data[i]=tmp[i]; } ///拆 void Msort(int* data,int* tmp,int left,int right){ if(left<right){ int mid=(left+right)/2; Msort(data,tmp,left,mid); Msort(data,tmp,mid+1,right); merge(data,tmp,left,mid,right); } } ///归并排序入口 void msort(int* data,int n){ int* tmp=new int[n]; if(tmp){ Msort(data,tmp,0,n-1); delete[] tmp; } } int main() { int n; cin>>n; int* data=new int[n]; for(int i=0;i<n;i++) cin>>data[i]; for(int i=0;i<n;i++) cout<<data[i]<<" "; cout<<endl; ///归并排序入口 msort(data,n); for(int i=0;i<n;i++) cout<<data[i]<<" "; cout<<endl; return 0; } /** 输入: 10 2 8 4 9 1 10 22 15 11 34 输出: 2 8 4 9 1 10 22 15 11 34 1 2 4 8 9 10 11 15 22 34 */
1、堆排序基本思想
(1)将待排序序列构造成一个大顶堆。
(2)此时,整个序列的最大值就是堆顶的根节点。
(3)将其与末尾元素进行交换, 此时末尾就为最大值。
(4)然后将剩余 n-1 个元素重新构造成一个堆, 这样会得到 n 个元素的次小值。 如此反复执行, 便能得到一个有序序列了。
最后可以看到在构建大顶堆的过程中, 元素的个数逐渐减少,最后就得到一个有序序列了。
注:一般升序采用大顶堆, 降序采用小顶堆。
2、代码实现
/**以大顶堆举例*/ #include<iostream> 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<<arr[i]<<" "; } cout<<endl; delete[] arr; return 0; } /** 输入: 6 9 2 4 23 10 1 输出: 1 2 4 9 10 23 */
1、概念
(1)直接插入排序
把待排序的数据插入到已经排好序的数据中,直到所有的数据插入完成,即就是直接插入排序。(如流行于陕西一带的纸牌游戏,挖坑)一般待排序的区间是第二个数到最后一个数。注意动态移动插入的过程,结合图与代码去理解。例如下面的例子就是待排序区间从 7 到 8,把第一个数当作已经排序的数据:
(2)希尔排序
希尔排序实在前面直接插入排序的基础上进行改进的一种排序。直接插入排序的变量 i 其实就是一个间隔,而希尔排序的间隔不是 1,它的间隔逐渐缩小直到为 1 的一种排序(当间隔gap到达1时停止),因此又叫缩小增量法。它是对直接插入排序算法的优化,当间隔不为 1 的时候,都是预排序。下图是举例,第一次的间隔是数据长度的三分之一再加一。即 gap = size / 3 + 1
2、代码实现
#include <iostream> 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<iostream> 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<<endl; radixsort(data, len); /// 基数排序。 /// 显示排序结果。 cout<<"显示最后排完序的结果:"<<endl; for (int i = 0; i < len; i++) cout << data[i] << " "; cout << endl; return 0; } /** 输入: 15 144 203 738 905 347 215 836 26 527 602 946 504 219 750 848 输出: 144 203 738 905 347 215 836 26 527 602 946 504 219 750 848 750 602 203 144 504 905 215 836 26 946 347 527 738 848 219 602 203 504 905 215 219 26 527 836 738 144 946 347 848 750 26 144 203 215 219 347 504 527 602 738 750 836 848 905 946 显示最后排完序的结果: 26 144 203 215 219 347 504 527 602 738 750 836 848 905 946 */
我是花花,祝自己也祝您变强了~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。