博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
排序sort (一)
阅读量:5269 次
发布时间:2019-06-14

本文共 9682 字,大约阅读时间需要 32 分钟。

这两天学习排序,简单的记录下,等看完之后再进行总结。

1.首先看了交换排序,顾名思义,也就是当无序时进行元素交换,从而达到元素有序。

【1】初级的是冒泡排序,冒泡排序的思想是:两两相邻的数据元素进行比较,如果反序则交换,直到有序为止,同时每一轮比较之后较小(大)的数上浮,较大(小)的数下沉,因此命名为冒泡排序。因为是两两相邻的数进行比较,且相等时不进行交换,所以是一种稳定的排序算法。

冒泡排序(Bubble Sort)代码实现为:

void bubblesort(vector
& a) //这里的排序进行从小到大的排序,当从大到小时改变if中的条件即可{ bool change = true; //此处设置标志位的作用是当两两元素比较为有序时,则不需要进行后面的比较 for (int i = 0; i
= 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】)继续进行快排。(递归)。

当元素基本上有序时,此时选择的pivotkey将待排序的元素可能分成严重不均等的两部分,(一部分可能有一个元素,另一部分可能有n-1个元素),此时快速排序退化为冒泡排序。同时因为它比较和交换是跳跃的,所以是一种不稳定的排序方法。

快速排序(Quick Sort)代码实现为:

/*************************************************Quick Sort***********************************************************/int partition(vector
& 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
& 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
& 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)代码实现为:

 

void HeapAdjust(vector
& array, int i, int len) //调整第i个元素,使之成为一个大顶堆(下溯过程),(隐含了i的左右两边已经是堆的情况){ int temp = array[i]; int j = 2 * i + 1; while (j < len) { if (j + 1 < len && array[j] < array[j + 1]) ++j; if (array[j] < temp) break; else { array[i] = array[j]; i = j; j = 2 * i + 1; } } array[i] = temp;}void heapsort(vector
& 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 ); //表示调整第0个元素,让剩下的i个元素保持大顶堆 }
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
& 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
& 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
& 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
&temp,vector
&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,再传回给avoid Msort(vector
&temp, vector
&a, int s, int e){ int m; if (s
&a){ vector
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
&a, vector
&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
&a){ vector
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 << " ";}

 5.测试代码:

int main(){    vector
a = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; vector
b = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; vector
c = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; vector
d = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; vector
e = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; vector
f = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; vector
g = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; vector
h = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; vector
i = { 9, 1, 5, 8, 3, 7, 4, 6, 2 }; int low = 0, high = a.size()-1; bubblesort(b); cout << endl; selectsort(c); cout << endl; Quicksort(a,low,high); cout << "Quick sort:" << endl; for (auto c : a) cout << c << " "; cout << endl; heapsort(d); cout << endl; Insertsort(e); cout << endl; Shellsort(f); cout << endl; BInsertsort(g); cout << endl; Mergingsort(h); cout << endl; Mergesort(i); return 0;}

测试结果:

转载于:https://www.cnblogs.com/liuamin/p/6698307.html

你可能感兴趣的文章
C# Stream 和 byte[] 之间的转换
查看>>
自定义不等高的cell-(storyboard)
查看>>
Cracking the code interview
查看>>
linux命令 rpm
查看>>
OMG: daily scrum nine
查看>>
【蓝桥杯】历届试题 连号区间数(运行超时)
查看>>
交换机练习的心得
查看>>
docker 常用命令
查看>>
自己动手写俄罗斯方块(C语言+Windows API)
查看>>
有源汇有上下界可行流/最大流
查看>>
Destroying the bus stations HDU - 2485(最小割点)
查看>>
Makefile之文件搜索
查看>>
【开发工具】Pycharm使用
查看>>
[ Python ] Flask
查看>>
GNUPLOT 画多组柱状图 以及 折线图 以及各种问题的解决方案
查看>>
51nod 1381 硬币游戏
查看>>
Webpack打包React踩到的坑
查看>>
黑马程序员——生成随机数
查看>>
ASCII,Unicode和UTF-8
查看>>
ERROR 1062 (23000): Duplicate entry '0' for key 'PRIMARY'
查看>>