排序sort
Posted liuamin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序sort 相关的知识,希望对你有一定的参考价值。
这两天学习排序,简单的记录下,等看完之后再进行总结。
1.首先看了交换排序,顾名思义,也就是当无序时进行元素交换,从而达到元素有序。
【1】初级的是冒泡排序,冒泡排序的思想是:两两相邻的数据元素进行比较,如果反序则交换,直到有序为止,同时每一次比较之后较小(大)的数上浮,较大(小)的数下沉,因此命名为冒泡排序。因为是两两相邻的数进行比较,且相等时不进行交换,所以是一种稳定的排序算法。
冒泡排序(Bubble Sort)代码实现为:
void bubblesort(vector<int>& a) //这里的排序进行从小到大的排序,当从大到小时改变if中的条件即可 { bool change = true; //此处设置标志位的作用是当两两元素比较为有序时,则不需要进行后面的比较 for (int i = 0; i<a.size() && change; i++) //注意此处i为有符号,a.size()为无符号,会有警告,可以设置为size_t类型,但注意超出a[]的下标,因为无符号类型没有负数,会转化为非常大的正数 { change = false; for (int j = a.size() - 2; j >= i; j--) if (a[j]>a[j + 1]) { swap(a[j], a[j + 1]); change = true; } } cout << "bubble sort:" << endl; for (size_t k = 0; k != a.size(); k++) //此处可以用范围for语句打印 { cout << a[k] << " "; } }
【2】在冒泡的基础上改进为快速排序,快速排序的思想是:将待排序的元素分为独立的两部分,(设置pivotkey,使得它左边元素均小于它,右边的元素均大于它,返回pivotkey的下标pivot)然后再对这两部分(【low到pivot-1】和【pivot+1到high】)继续进行快排。(递归)。
当元素基本上有序时,快速排序退化为冒泡排序,同时因为它比较和交换是跳跃的,所以是一种不稳定的排序方法。
快速排序(Quick Sort)代码实现为:
/*************************************************Quick Sort***********************************************************/ int partition(vector<int>& a,int low,int high) { //设置枢轴元素为第一个元素,使得枢轴元素的左边均小于它,右边均大于它,这里总是选择下标为low的元素作为pivot,改进为三中选一,或九中选一等。 int pivotkey = a[low]; while (low < high) { while (low < high&&a[high] >= pivotkey) high--; swap(a[low], a[high]); while (low < high&&a[low] <= pivotkey) low++; swap(a[low], a[high]); } return low; } void Quicksort(vector<int>& a,int low,int high) //当数组大时快排效果好,当数组小时,因为快排中总是用递归,反而性能不好,此处可以加一个判断,当大于某个临界时用快排,否则用直接插入排序 { int pivot; if (low < high) //if((high-low)>MAX_LENGTH) { pivot = partition(a, low, high); Quicksort(a,low,pivot-1); Quicksort(a,pivot+1,high); } //else //Insertsort(a); }
2.对选择排序,重点在选择二字,也就是每进行一轮比较,选择出最小(大)元素,选择好后再进行交换。
因为选择的都是重复元素的第一个,所以也是一种稳定的排序算法。
【1】简单选择排序(Simple Selection Sort)代码实现为:
void selectsort(vector<int>& a) { for (int i = 0; i < a.size(); i++) { int min = i; for (int j = i + 1; j < a.size(); j++) if (a[min]>a[j]) min = j; if (i != min) swap(a[min], a[i]); } cout << "simple selection sort:" << endl; for (auto c : a) cout << c << " "; }
【2】在简单选择选择排序的基础上改进出了一种新的方法为堆排序,堆排序重点在于建立堆和重建堆,堆首先是一颗完全二叉树,分为大顶堆和小顶堆。(这里默认读者已经对堆的概念已经掌握),算法的主要步骤是:首先对待排序的元素建立一个大顶堆(从非叶节点开始),然后交换堆顶元素(最大的元素)(移走)和末尾元素,对剩下的元素(n-1)进行重建堆,就会得到次大的元素,不断的重复,就可以得到一个有序序列了。
它比较和交换是跳跃的,所以是一种不稳定的排序方法。
堆排序(Heap Sort)代码实现为:
/*****************************************Heap Sort*********************************************************/ void HeapAdjust(vector<int>& a, int i, int len) //调整第i个元素,使之成为一个大顶堆 { int temp=a[i]; for (int j = 2 * i + 1; j <=len; j=j * 2 + 1) { if (j < len&&a[j] < a[j + 1]) ++j; if (temp > a[j]) break; a[i] = a[j]; i = j; } a[i] = temp; } void heapsort(vector<int>& a) { //建立一个大顶堆(也可以是小顶堆) for (int i = (a.size() - 2) / 2; i >= 0; i--) HeapAdjust(a, i, a.size()); for (int i = a.size() - 1; i>0;i--) { swap(a[0], a[i]); HeapAdjust(a, 0,i-1); } cout << "heap sort:" << endl; for (auto c : a) cout << c << " "; }
3.插入排序,它的思想是将一个记录插入到已经排序好的有序表中,从而得到一个新的,记录数增1的有序表。
也就是设置a[i]为哨兵,每次将a[i]和a[i-1]进行比较,如果无序,则将元素后移,直到找出正确的位置插入a[i]。因为插入的元素如果与之前一个元素相等,插入的位置为相等元素的后面,所以是一种稳定的排序算法。在直接插入排序的基础还有二分插入排序和二路插入排序。
【1】直接插入排序(Insertion Sort)代码实现为:
/**************************************************Insertion Sort***************************************************/ void Insertsort(vector<int>& a) { int temp,j; for (int i = 1; i != a.size(); ++i) { if (a[i] < a[i - 1]) { temp = a[i]; //复制为哨兵,也就是待排序(插入)的元素 for (j = i - 1; j >= 0 && temp < a[j]; j--) //比哨兵大(小)的元素后移 a[j + 1] = a[j]; a[j + 1] = temp; //插入到正确的位置 } } cout << "Insertion sort:" << endl; for (auto c : a) cout << c << " "; }
二分插入排序代码:
/******************在直接插入的基础上有二分插入排序和二路插入排序****************************************************/ void BInsertsort(vector<int>& a) //二分插入排序 { int temp, j,low,high; for (int i = 1; i != a.size(); ++i) { if (a[i] < a[i - 1]) { low = 0; high = i - 1; temp = a[i]; while (low <= high) //和直接插入排序不同的就是在low和high中折半查找插入的位置 { int m = (low + high) / 2; if (temp < a[m]) high = m - 1; else low = m + 1; } //循环完后low>high,[high+1]为插入位置 for (j = i - 1; j>=high+1; j--) a[j + 1] = a[j]; a[high + 1] = temp; //插入到正确的位置 } } cout << "Binary Insertion sort:" << endl; for (auto c : a) cout << c << " "; }
【2】在直接插入排序的基础上,对其进行了改进有了希尔排序,本质是一样的,都是找到正确的插入位置插入待排序的元素,希尔排序的精华在于:不像直接插入排序,小的关键字a[i]不是一步一步向前移动(a[i]与a[i-1]比较),而是跳跃式的向前移动(a[i] 与a[i - increasment]比较),跳跃的距离取决于增量序列 increasment,但最后的增量值一定是1,这样和直接插入排列一样,但移动的次数大大减小,因为元素已经基本有序。因为是跳跃式的移动和比较,所以是一种不稳定的排序方法。
希尔排序(Shell Sort)代码实现为:
/********************************************Shell Sort*****************************************************************/ void Shellsort(vector<int>& a) { int temp,j; int increasment = a.size() / 2; //设置增量序列 while (increasment >= 1) //最后的增量序列必须为1,类似与插入排序,才能保证序列有序 { for (int i = increasment; i != a.size(); ++i) { if (a[i] < a[i - increasment]) { temp = a[i]; //复制为哨兵,也就是待排序(插入)的元素 for (j = i - increasment; j >= 0 && temp < a[j]; j-=increasment) //比哨兵大(小)的元素后移 a[j + increasment] = a[j]; a[j + increasment] = temp; //插入到正确的位置 } } increasment/= 2; } cout << "Shell sort:" << endl; for (auto c : a) cout << c << " "; }
4.归并排序,它的思想是:借助辅助空间temp,将待排序序列a分成若干个子序列,再进行归并为有序的temp,之后再把有序的temp归并为整体有序序列a。
归并排序有两种实现方式:第一种是递归方法实现,空间复杂度除了temp,还有递归用到的栈空间,所以整体的空间复杂度为n+log2n;而非递归方法,只有辅助空间temp,所以它的空间复杂度为n,因此归并排序更推荐使用非递归归并排序方法。因为它比较元素时如果相等,先将位于序列前面的元素归并在前面,所以不会改变相等元素的顺序,是一种稳定的排序方法。此处是两两归并,也称2路归并排序。
归并排序(Merging Sort)代码实现为:
【1】递归方法:
/*******************************************Merging Sort(递归方法)*****************************************************************/ //此函数的功能是借助temp将a(从i到n大小,以m为分界的两个子序列)归并(合并)为一个有序的序列a.(先将a中的子序列归并到temp,再将归并好的子序列传回给a) void Merge(vector<int>&temp,vector<int>&a,int i,int m,int n) { int j,k,l,beg=i; for (j = m + 1, k = i; i <= m &&j <= n; ++k) { if (a[i] <= a[j]) //此处为小于等于,否则不是稳定的排序方法 temp[k] = a[i++]; else temp[k] = a[j++]; } if (i <= m) //将剩余的元素a[i.....,m]复制到temp { for (l = 0; l <= m - i; l++) temp[k + l] = a[i + l]; } if (j <= n) //将剩余的元素a[j.....,n]复制到temp { for (l = 0; l <= n - j; l++) temp[k + l] = a[j + l]; } for (; beg <= n; beg++) //这里实现将a归并的后的temp赋给a,也就是temp[beg....n]复制到a[beg....n],此处beg为刚传进来的i,所以开始的时候i没有参与运算时要进行初始化beg a[beg] = temp[beg]; } //temp为辅助空间,a为待排序的序列,将a不断分为若干个子序列,归并到temp,再传回给a void Msort(vector<int>&temp, vector<int>&a, int s, int e) { int m; if (s<e) { m = (s + e) / 2; //不断递归将a平分为a[s....m]和a[m+1....e]两部分 Msort(temp,a,s, m); //递归实现将a[s...m]归并为有序的temp[s...m]再到a[s...m] Msort(temp,a,m + 1,e); //递归实现将a[m+1....e]归并为有序的temp[m+1....e]再到a[m+1....e] Merge(temp,a,s,m,e); //将a[s...m]和a[m+1....e]归并到有序的temp[s...e]再到a[s...e] } } void Mergingsort(vector<int>&a) { vector<int> temp(a.size()); //申请了一个大小为a.size()的辅助空间 Msort(temp, a, 0, a.size() - 1); cout << "递归实现:Merging sort:" << endl; for (auto c : a) cout << c << " "; }
【2】非递归方法
/*************************************************Merging Sort(非递归方法)******************************************************************/ void MergePass(vector<int>&a, vector<int>&temp, int s, int e) { int i = 0; while (i <= e - 2 * s + 1) //归并长度相等的子序列 { Merge(temp, a, i, i + s - 1, i + 2 * s - 1); i = i + 2 * s; } if (i < e - s + 1) //归并长度不相等的子序列 Merge(temp, a, i, i + s - 1, e); //else //若剩下单独的子序列,此处可以省略,因为总是从a归并到temp再到a //for (int j = i; i <= e; j++) // temp[j] = a[j]; } void Mergesort(vector<int>&a) { vector<int>temp(a.size()); //辅助空间 int k = 1; while (k < a.size()) { MergePass(a, temp, k, a.size() - 1); k *= 2; } cout << "非递归实现:Merging sort:" << endl; for (auto c : a) cout << c << " "; }
以上是关于排序sort 的主要内容,如果未能解决你的问题,请参考以下文章
[原创]java WEB学习笔记61:Struts2学习之路--通用标签 property,uri,param,set,push,if-else,itertor,sort,date,a标签等(代码片段