【算法】常见的七种排序及其算法优化

来源:互联网 发布:jpg转换成pdf mac 编辑:程序博客网 时间:2024/05/21 16:57

1、插入排序

有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。
插入排序的基本思想是:每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。

大概步骤如上图,下面实现代码

void InsertSort(int* arr,size_t n)//插入排序{assert(arr);for(size_t index=1;index<n;index++){size_t tmp=arr[index];int pos=index-1;while (pos>=0&&arr[pos]>tmp){arr[pos+1]=arr[pos];pos--;}arr[pos+1]=tmp;}}


2、希尔排序

希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

大概过程如上图,代码如下

void ShellSort(int* arr,size_t n)//希尔排序{int gap=n/3+1;for(size_t index=gap;index<n;index++){size_t tmp=arr[index];int pos=index-gap;while(pos>=0&&arr[pos]>tmp){arr[pos+gap]=arr[pos];pos-=gap;}arr[pos+gap]=tmp;}}


3、冒泡排序

重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

不再做过多解释,直接上代码

void PopSort(int* arr,size_t n)//冒泡排序{for(int i=0;i<n;i++){for(int j=i+1;j<n;j++){if(arr[i]>arr[i+1]){int tmp=arr[i];arr[i]=arr[i+1];arr[i+1]=tmp;}}}}


4、选择排序

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。



代码如下

void selectSort(int*arr ,size_t n){int min;int tmp;for(int i=0;i<n;i++){for(int j=0;j<n;j++){min=i;if(arr[min]>arr[j]){min=j;}tmp=arr[min];arr[min]=arr[j];arr[j]=tmp;}}}



优化的选择排序

每次选一个最小值放最前面,选最大一个值放后面


代码如下

void SelectSort2(int* arr,int n){assert(arr);int left=0;int right=n-1;    while (left<right)    {int min=left;int max=right;for (int i=left;i<=right;++i){if (arr[min]>=arr[i]){min=i;}                if(arr[max]<=arr[i]){max=i;}}    swap(arr[left],arr[min]);if (left==max){max=min;}swap(arr[right],arr[max]);    left++;right--;    }}



5、快速排序

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列


挖坑法块排,选第一数做比较

void FastSort(int* arr,int low,int high)//设置一个低位一个高位,进行快速排序{if(low>=high)return;int first=low;int last=high;int mid=ThreeMid(arr,first,last);swap(arr[mid],arr[first]);int key=arr[first];//用挖坑法while (first<last){while(first<last&&arr[last]>=key){--last;}arr[first]=arr[last];while (first<last&&arr[first]<=key){++first;}arr[last]=arr[first];}arr[first]=key;FastSort(arr,low,first-1);FastSort(arr,first+1,high);}


挖坑法选最后数做比较

单趟:

int PartSort2(int* arr,int first,int last)//挖坑法{int left=first;int right=last;int key=ThreeMid(arr,first,last);swap(arr[key],arr[last]);int tmp=arr[last];while (left<right){while (left<right&&arr[left]<=tmp){++left;}arr[right]=arr[left];while(left<right&&arr[right]>=tmp){--right;}arr[left]=arr[right];}arr[left]=tmp;return left;}


递归

void QuickSort2(int* arr,int first,int last){if(first<last){int key=PartSort2(arr,first,last);QuickSort2(arr,first,key-1);QuickSort2(arr,key+1,last);}}


快排优化

当数组数超过13个进行快排,否则插入排序

void QuickSort2(int* arr,int first,int last){if(first<last){if ((last-first)>=13){int key=PartSort2(arr,first,last);QuickSort2(arr,first,key-1);QuickSort2(arr,key+1,last);}elseInsertSort(arr,sizeof(arr)/sizeof(arr[0]));}}


前后指针法,数组前后个一个指针,同时进行排序

int PartSort(int* arr,int left,int right){    int mid=ThreeMid(arr,left,right);swap(arr[mid],arr[right]);int key=arr[right];int first=left;int last=right-1;while(first<last){while (first<last&&arr[first]<=key){++first;}while (first<last&&arr[last]>=key){--right;}swap(arr[first],arr[last]);}if(arr[first]>arr[right]);swap(arr[first],arr[right]);return first;}void QuickSort3(int* arr,int left,int right){while (left<right){int mid=PartSort(arr,left,right);QuickSort3(arr,left,mid-1);QuickSort3(arr,mid+1,right);}}




6、堆排序

堆分为大根堆和小根堆,是完全二叉树。大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i]。在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶。

建堆

void AdjustDown(int* arr,int index,int n){int parent=index;int child=2*parent+1;while (child<n){if(child<n&&arr[child]<arr[child+1])child++;    if (child<n&&arr[child]>arr[parent]){swap(arr[parent],arr[child]);parent=child;child=2*parent+1;}elsebreak;}child=parent;}


堆排序

void HeapSort(int* arr,int n){for(int i=n/2-1;i>=0;--i){      AdjustDown(arr,i,n);}for(int j=n-1;j>0;--j){swap(arr[j],arr[0]);        AdjustDown(arr,0,j);}if(arr[0]>arr[1])swap(arr[0],arr[1]); }


7、归并排序

归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。



单趟排序

void Merge(int* arr,int* tmp,int first,int mid,int last)//归并{int i=first;int j=mid+1;int k=first;while (i!=mid+1&&j!=last+1){if(arr[i]>arr[j])tmp[k++]=arr[j++];elsetmp[k++]=arr[i++];}while(i!=mid+1){tmp[k++]=arr[i++];}while (j!=last+1){tmp[k++]=arr[j++];}for(i=first;i<=last;i++)arr[i]=tmp[i];}


递归归并

void MergeSort(int* arr,int* tmp,int first,int last)//归并排序{int mid;if (first<last){mid= first+((last-first)>>1);          MergeSort(arr,tmp,first,mid);MergeSort(arr,tmp,mid+1,last);Merge(arr,tmp,first,mid,last);}}

三数求中法int ThreeMid(int* arr,int left,int right)//找首位,末尾和中点中中间的数{int mid=left+((right-left)>>1);while (left<right){if(arr[left]<arr[right]){if(arr[mid]<arr[left])return left;else if(arr[right]<arr[mid])return right;elsereturn mid;}if(arr[left]>arr[right]){if(arr[mid]<arr[right])return right;else if(arr[mid]>arr[left])return left;elsereturn mid;}}return mid;}


三数中中间值进行比较避免了用最后一位比较时最后一位是最大值或用第一位比较时第一位是最小值,降低了时间复杂度。

测试代码

int main(){int arr[]={9,3,5,1,4,7,8,0};int tmp[8];//int arr[]={2,3,6,5,4,13,56};cout<<"原数组  : ";Print(arr,sizeof(arr)/sizeof(arr[0]));InsertSort(arr,sizeof(arr)/sizeof(arr[0]));cout<<"插入排序: ";Print(arr,sizeof(arr)/sizeof(arr[0]));ShellSort(arr,sizeof(arr)/sizeof(arr[0]));cout<<"希尔排序: ";Print(arr,sizeof(arr)/sizeof(arr[0]));PopSort(arr,sizeof(arr)/sizeof(arr[0]));cout<<"冒泡排序: ";Print(arr,sizeof(arr)/sizeof(arr[0]));selectSort(arr,sizeof(arr)/sizeof(arr[0]));cout<<"选择排序: ";Print(arr,sizeof(arr)/sizeof(arr[0]));FastSort(arr,0,sizeof(arr)/sizeof(arr[0])-1);cout<<"快速排序: ";Print(arr,sizeof(arr)/sizeof(arr[0]));SelectSort2(arr,sizeof(arr)/sizeof(arr[0]));cout<<"选择排序2:";Print(arr,sizeof(arr)/sizeof(arr[0]));HeapSort(arr,sizeof(arr)/sizeof(arr[0]));cout<<"堆排序:   ";Print(arr,sizeof(arr)/sizeof(arr[0]));QuickSort2(arr,0,sizeof(arr)/sizeof(arr[0])-1);cout<<"快速排序2: ";Print(arr,sizeof(arr)/sizeof(arr[0]));MergeSort(arr,tmp,0,sizeof(arr)/sizeof(arr[0])-1);cout<<"归并排序: ";Print(arr,sizeof(arr)/sizeof(arr[0]));QuickSort2(arr,0,sizeof(arr)/sizeof(arr[0])-1);cout<<"快速排序3:";Print(arr,sizeof(arr)/sizeof(arr[0]));system("pause");                return 0;}



测试用例

int arr[]={9,3,5,1,4,7,8,0};






测试用例

int arr[]={2,3,6,5,4,13,56};



欢迎补充

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 头顶头发长得慢怎么办 每次洗头发都掉很多头发怎么办 拔了头发不长怎么办 6岁儿童头发稀少怎么办 2岁宝宝胆子小怎么办 坐到小孩的头怎么办 托班幼儿不刷牙怎么办 两岁的宝宝蛀牙怎么办 小孩在学校被打怎么办 油画棒画在墙上怎么办 宝宝把蜡笔吃了怎么办 吃鸡更新了怎么办开始 数字画涂料干了怎么办 广告画颜料干了怎么办 宝宝断奶后瘦了怎么办 腿一个粗一个细怎么办 两条小腿不一样粗怎么办 两岁宝宝坐不了怎么办 q糖孩子吃多了怎么办 q糖孩子吃的太多怎么办 ps图层不能覆盖怎么办 孩子的字写的不好怎么办 孩子爱打人怎么办 6招 一岁宝宝爱打人怎么办 2岁小朋友爱打人怎么办 小朋友爱动手怎么办4岁 5,6岁爱动手打人怎么办 七个月宝宝大便干燥怎么办 两岁宝宝吐奶怎么办 2岁宝宝轻微蛀牙怎么办 2岁宝宝喝水都吐怎么办 2岁宝宝吐的厉害怎么办 两岁宝宝个子矮怎么办 宝宝吐了一天了怎么办 3岁宝宝吃饭呕吐怎么办 3岁宝宝突然呕吐怎么办 11个月婴儿呕吐怎么办 2岁宝宝呕吐是怎么办 2岁宝宝呕吐腹泻怎么办 七个月的宝宝拉肚子怎么办 两岁宝宝玩手机怎么办