赞
踩
使用C++实现来插入排序、希尔排序、冒泡排序、快速排序、选择排序算法。
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而生成一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动 。
插入排序的工作方式像许多人排序一手扑克牌。开始时,我们的左手为空并且桌子上的牌面向下。然后,我们每次从桌子上拿走一张牌并将它插入左手中正确的位置。为了找到一张牌的正确位置,我们从右到左将它与已在手中的每张牌进行比较。拿在左手上的牌总是排序好的,原来这些牌是桌子上牌堆中顶部的牌 。
插入排序是指在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。按照此法对所有元素进行插入,直到整个序列排为有序的过程,称为插入排序 。
#include<iostream> using namespace std; int main() { int arr[6]={9,7,6,5,4,3}; //遍历数组,依次进行比较 for(int i=0;i<5;i++){ /* 比较i和i+1,如果升序排序,则判断第i个元素是否大于第i+1个 元素,如果是,则将第i+1个元素依次与之前的所有元素进行比较并 排序,完成后将第i个元素插入到第i+1个元素的位置上。降序也是 同样的原理。 */ if(arr[i]>arr[i+1]){ //交换 //从第i个元素开始交换 int j=i; //将需要插入的元素使用变量temp保存 int temp=arr[i+1]; /** 将第i个元素之前的所有元素进行一次重新排序,保证第0-i个元素 之间是排好序的。 */ while(j>=0&&temp<arr[j]){ arr[j+1]=arr[j]; j--; } arr[j+1]=temp; } } //打印输出排序结果 for(int i=0;i<6;i++){ cout<<arr[i]<<" "; } }
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因 D.L.Shell 于 1959 年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
#include<iostream> using namespace std; int main() { int arr[6]={9,7,6,5,4,3}; //控制步长 for(int gap=6/2;gap>0;gap/=2){ //遍历所有的组 for(int i=0;i<gap;i++){ //遍历每个组中的所有元素 for(int j=i-gap;j>=0;j-=gap){ /* 比较第j个元素和第j+gap个元素,不满足排序规则的交换 元素顺序。 */ if(arr[j]>arr[j+gap]){ int t=arr[j]; arr[j]=arr[j+gap]; arr[j+gap]=t; } } } } //打印输出排序结果 for(int i=0;i<6;i++){ cout<<arr[i]<<" "; } }
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
冒泡排序算法的原理如下:
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
#include <iostream> using namespace std; int main() { int array[8] = {8,7,6,5,4,3,2,1}; //打印输出排序前的数组 cout<<"排序前的数组为:"; for (int i = 0; i < 8; i++){ cout<<array[i]<<" "; } //冒泡排序 for(int i=0;i<8;i++){ for(int j=0;j<8-1-i;j++){ if(array[j]>array[j+1]){ int temp=array[j]; array[j]=array[j+1]; array[j+1]=temp; } } } //打印输出排序后的数组 cout<<"\n排序后的数组为:"; for (int i = 0; i < 8; i++){ cout<<array[i]<<" "; } return 0; }
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
原理设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它左边,所有比它大的数都放到它右边,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]的值交换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]的值交换;
5)重复第3、4步,直到ij; 3、4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,ij这一过程一定正好是i++或j–完成的时候,此时令循环结束。
排序演示
假设一开始序列{xi}是:5,3,7,6,4,1,0,2,9,10,8。
此时,ref=5,i=1,j=11,从后往前找,第一个比5小的数是x8=2,因此序列为:2,3,7,6,4,1,0,5,9,10,8。
此时i=1,j=8,从前往后找,第一个比5大的数是x3=7,因此序列为:2,3,5,6,4,1,0,7,9,10,8。
此时,i=3,j=8,从第8位往前找,第一个比5小的数是x7=0,因此:2,3,0,6,4,1,5,7,9,10,8。
此时,i=3,j=7,从第3位往后找,第一个比5大的数是x4=6,因此:2,3,0,5,4,1,6,7,9,10,8。
此时,i=4,j=7,从第7位往前找,第一个比5小的数是x6=1,因此:2,3,0,1,4,5,6,7,9,10,8。
此时,i=4,j=6,从第4位往后找,直到第6位才有比5大的数,这时,i=j=6,ref成为一条分界线,它之前的数都比它小,之后的数都比它大,对于前后两部分数,可以采用同样的方法来排序。
#include <iostream> using namespace std; void Qsort(int arr[], int low, int high){ if (high <= low){ return; } int left = low; int right = high; int key = arr[low]; while (true) { //将比key小的值放key左边,比key大的值放key右边 /*从左向右找比key大的值*/ while (arr[left] <= key) { left++;//从左往右,下标递增 //当遍历到最后一个元素时,结束循环 if (left == high){ break; } } /*从右向左找比key小的值*/ while (arr[right] >= key) { right--; //从右往左,下标递减 //当遍历到第一个元素时,结束循环 if (right == low){ break; } } // cout<<"left:"<<left<<" right:"<<right<<"\n"; /* 当比key小的数全在左边,比key大的数全在右边时,表 示第一次排序完成,结束循环 */ if (left >= right){ break; } /* 将比key小的数移到左边,比key大的数移到右边, 交换left,right对应的值 */ int temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; } /*分别对左右两边的数字进行排序, 中枢值与right对应值交换*/ arr[low] = arr[right]; arr[right] = key; Qsort(arr, low, right - 1); Qsort(arr, right + 1, high); } int main() { int arr[] = {52, 64, 59, 52, 75, 28, 98, 30, 25}; //获取数组长度 int len = sizeof(arr)/sizeof(arr[0]); //打印排序前的数组 cout<<"排序前:"; for(int i = 0; i < len; i++) { cout << arr[i] << " "; } //调用快速排序函数 Qsort(arr, 0, len- 1); //打印排序后的数组 cout<<"\n排序后:"; for(int i = 0; i < len; i++) { cout << arr[i] << " "; } return 0; }
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
排序思路:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
具体实现方法:
①初始状态:无序区为R[0…n-1](共n个元素),有序区为空。
②第1趟排序
设置一个变量i,让i从0至n-2循环的同时,在对比数组中元素i跟元素i+1的大小,如果R[i+1]比R[i]小,则用一个变量k来记住他的位置(即k=i+1)。等到循环结束的时候,我们应该找到了R中最小的那个数的位置了。然后进行判断,如果这个最小元素的不是R的第一个元素,就让第一个元素跟他交换一下值,使R[0…0]和R[1…n-1]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
……
③第i趟排序
第i趟排序开始时,当前有序区和无序区分别为R[0…i-1]和R[i…n-1]。该趟排序从当前无序区中选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[0…i]和R分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。
图1例子:(通过寻找最小值的选择排序)
#include<iostream> using namespace std; /*遍历寻找当前序列中的最小值,返回最小值的下标*/ int selectMin(int arr[],int i,int len){ int min=i; for(;i<len;i++){ if(arr[i]<arr[min]){ min=i; } } return min; } int main() { int arr[]={5,8,2,4,1,6}; int len=sizeof(arr)/sizeof(arr[0]); for(int i=0;i<len;i++){ //接收当前序列的最小值下标 int j=selectMin(arr,i,len); //判断最小值是否为当前元素,如果不是,则交换最小值和当前元素的位置 if(i!=j){ int temp=arr[i]; arr[i]=arr[j]; arr[j]=temp; } } for(int i=0;i<len;i++){ cout<<arr[i]<<" "; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。