排序算法大总结
来源:互联网 发布:济宁seo 编辑:程序博客网 时间:2024/05/16 08:20
数据结构绝对是重中之重!
排序算法主要有9种
冒泡排序 交换排序 选择排序 插入排序 快速排序 归并排序 堆排序 基排序 希尔排序
每个排序都有自己的适宜场合,有不同的时间复杂度和空间复杂度。
时间复杂度主要是从比较次数和移动次数来看
接下来一一介绍
一、冒泡排序
算法思想:
1.待排序的数据看作气泡,通过n-1趟比较,从而使较小的数据浮在上层(前),较大的数据沉在下层(后)。
2.每一趟比较,从下层开始比较两个相邻的数据,如果上层的数据大于下层的数据,则交换;否则,不移动顺序继续往上比较。
void BubbleSort(int n,List &A){for (int i=0;i<n;i++){for (int j=n-1;j>=i+1;j--){if (A[j].key<A[j-1].key){swap(A[j],A[j-1]);}}}}
平均时间复杂度最差时间复杂度空间复杂度O(N*N)O(N*N)O(1)
算法思想:(分治算法)
1.找基准元素。FindPivot(int i,int j)
作用是,使数列左侧都比基准元素要小,右侧都比基准元素要大。
如何选取?从左侧开始查找两个不同数值中的较大值作为基准元素。如果找不到两个不相同的元素,则返回0。排序结束。例如 3 3 2 5 6 1 0 则选取3为基准元素。
2.划分
(1)l表示从左边开始遍历的下标,r表示从右边开始遍历的下标。l为指向数列中从左边开始第一个比基准元素大的值;r为数列中从右边开始第一个比基准元素小的值。
(2)如果l<r,则swap(A[l],A[r]);重复(1)
如果l>r,也即l=r+1。数列从l-1和l之间划分成两部分。
3.对于划分后的两个数列,继续采用快排算法。
int FindPivot(int i,int j,List &A){//选取基准元素,从数列左侧查找两个不同数值中的较大值为基准元素for (int k=i+1;k<=j;k++){if (A[k].key>A[i].key)return k;else if (A[k].key<A[i].key) return i;}return 0;}int Partition(int i,int j,List &A,int Pivot){//划分数列int l,r;do {for(l=i;A[l].key<Pivot;l++);for(r=j;A[r].key>=Pivot;r--);if (l<r) {swap(A[l],A[r]);}} while(l<=r);return l;}void QuickSort(int i,int j,List &A){int k;int pivot;int pivotindex;pivotindex=FindPivot(i,j,A);if(pivotindex!=0){//递归结束条件pivot=A[pivotindex].key;k=Partition(i,j,A,pivot);QuickSort(i,k-1,A);QuickSort(k,j,A);}}不过这里有点小错误啦~
就是结束递归结束条件设置的是pivotindex!=0,但是确实第一次可能pivotindex=0,如果结束,就没有进行排序。
最好情况
每次划分后,划分点左侧和右侧长度相同,则时间复杂度为O(nlogn)
T(n)<=2T(n/2)+n
<=2(2T(n/4)+n/2)+n
<=4(2T(n/8)+n/4)+2n
......
<=nT(1)+nlogn=O(nlogn)
最坏情况
每次划分只得到一个比上一次划分少一个记录的子序列
平均时间复杂度最差时间复杂度空间复杂度O(nlogn)O(N*N)O(logn)
三、选择排序(selectsort)
算法思想:
与冒泡排序类似,冒泡排序,是找到比前面元素小的元素就交换。而选择排序则是在序列中找到最小的元素,然后与最前面的元素互换
void SelectSort(int n,List &A){int low;int lowindex;for (int i=0;i<n;i++)//在数列中选择最小的值,与A[i]交换{lowindex=i;low=A[i].key;for (int j=i+1;j<n;j++)//找数列中的最小值{if (A[j].key<low){lowindex=j;low=A[j].key;}}swap(A[i],A[lowindex]);}}性能分析
算法思想:
数列->完全二叉树->初始建堆->整理堆
1.将数列按照完全二叉树的下标排成完全二叉树。
2.对该完全二叉树用PushDown算法依次对n/2,n/2-1,n/2-2,...1建堆。
3.取堆顶元素一定是最小值。
4.交换第N个和第1个元素。重复3。知道取遍所有元素。
首先必须明确一点,二叉树有完整的排序规则,从1开始到n.若某个节点为i,左孩子为2*i,右孩子为2*i+1.
void PushDown(int first,int last,List &A){//整理堆算法int r=first;while (r<=last/2)//如果r<=last/2,则为堆。否则都为叶子节点{if (r==last/2 && last%2==0)//r节点只有左节点{if (A[r].key>A[last].key){swap(A[r],A[last]); }r=last;}else if (A[r].key>A[2*r].key && A[2*r].key<=A[2*r+1].key)//r节点有左右孩子,左孩子小于根节点,左孩子小于右节点,则将根节点和左孩子交换{swap(A[r],A[2*r]);r*=2;}else if (A[2*r+1].key<A[2*r].key && A[2*r+1].key<A[r].key)//r节点有左右孩子,右孩子小于根节点,右孩子小于左节点,则将根节点和右孩子交换{swap(A[r],A[2*r+1]);r=2*r+1;}else//正常堆无需调整r=last;}}void HeapSort(int n,List &A){//堆排序int i;for (i=n/2;i>=1;i--)PushDown(i,n,A);for (i=n;i>=2;i--){ swap(A[1],A[i]);PushDown(1,i-1,A);}}
{
printf("%d\n",A[i].key);
}
五、直接插入排序
算法思想:
每次将待排序的数值插入有序区的相应位置。
什么才是相应位置,在该位置前面找不到元素比他大,则这个位置就是正确的相应位置。
{
printf("%d\n",A[i].key);
}
void InsertSort(int size,List &A){A[0].key=-100000;//哨兵for (int i=1;i<=size;i++){int j;j=i;//A[j]为待排序的值,在数列中i之前的为有序区//将j插入正确的位置while (A[j-1].key>A[j].key)//如果j之前的数值比A[j]大,则将该数值与A[j]交换{swap(A[j-1],A[j]);j=j-1;}}}
算法思想:
1.第一遍归并是一一归并。第二遍是二二归并,第三遍是四四归并。第n遍就是2的N次方。
2.归并是两个列表的归并,指针i,j分别指向A中的两段{p...q-1}{q...r}.比较A[i],A[j]的大小,将小者赋给B[k]。如果两段序列不一样长,则将剩下的直接赋给B[].【Merge(int p,int q,int r,List A,List B)】
3.每一遍归并,设当前归并长度为h,,从序列开头开始,尽量归并2个h的序列,直达归并不了,剩下的序列,如果大于h小于2h,则归并两段,如果小于h,则直接复制到归并后的序列。【MergePass(int n,int h,List A,List B)】
4.归并排序【MergeSort(int n,List &A)】,当前归并序列长度大于n,终止排序。若小于n,开始一趟排序。
/****************归并排序*********************/void Merge(int p,int q,int r,List A,List B)//A中两个序列【p...q-1】【q...r】合并到B{int i,j,k;i=p;j=q+1;k=p;while (i<=q&&j<=r){if (A[i].key <= A[j].key)B[k++]=A[i++];elseB[k++]=A[j++];}while (i<=q){B[k++]=A[i++];}while (j<=r){B[k++]=A[j++];}}void MergePass(int n,int h,List A,List B){//把A中长度为h的相邻序列归并为长度为2hint i;for (i=1;i+2*h-1<=n;i+=2*h)//归并长度为h的两个子序列{Merge(i,i+h-1,i+2*h-1,A,B);}if (i+h-1<n)//还有两个子序列,但第二个序列长度小于h{Merge(i,i+h-1,n,A,B);}else{//仅剩一个子序列for (int t=i;t<=n;t++){B[t]=A[i];}}}void MergeSort(int n,List &A){int h=1;List B;if (h<n)//当被归并子序列的长度小于总长度{MergePass(n,h,A,B);//将A中归并到B中h*=2;//归并长度加倍MergePass(n,h,B,A);//将B中归并到A中 h*=2;//归并长度加倍}}
void MergeSort_q(int low,int high,List &A,List &B){//折半归并int mid=(low+high)/2;//两序列分解,A[LOW...HIGH]一分为二,mid=LOW+HIGHif (low<high){MergeSort_q(low,mid,A,B);//递归的对序列A[LOW]...A[MID]和A[MID+1]...A[HIGH]进行归并排序MergeSort_q(mid+1,high,A,B);Merge(low,mid,high,A,B);//将两个已排序子序列归并为一个有序序列}}
void main(){List B;input_1();MergeSort_q(1,size,L,B);output_1(size,B);}
根据比较关键字的大小排序,复杂度下限为O(nlogn)
而基数排序不是根据比较关键字的大小,而是根据构成关键字的每个分量的值,比较大小,从而排列记录。
算法思想:
1.
- 排序算法大总结
- 排序算法大总结
- 排序算法大总结
- 排序算法大总结
- 【排序算法】:九大排序算法总结
- 九大排序算法总结
- 十大排序算法总结
- 九大排序算法总结
- 九大排序算法总结
- 九大排序算法总结
- 各大排序算法总结
- 九大排序算法总结
- 九大排序算法总结
- 8大排序算法总结
- 九大排序算法总结
- 九大排序算法总结
- 九大排序算法总结
- 10大排序算法总结
- Python性能鸡汤(转)
- FreeRTOS分析
- 计算机是如何工作的(最简单透彻的解释)
- 解决jquery mobile+phonegap页面切换闪屏问题
- 别人同一个房间
- 排序算法大总结
- 【开发工具】二、版本控制工具历史的十个里程碑
- 数据库系统概念 sql 查询语句 读书笔记
- 公司项目注意事项 教训三
- 2014年2月25日星期二(DEMO8-2,光照图调制)
- extjs4.0——目录结构
- 同样会尽快么
- Android平台架构
- C#模拟post提交HttpPost类(可以提交文件)