程序员面试宝典_第13章_数据结构基础_排序算法小结(1)
来源:互联网 发布:80后和90后的区别 知乎 编辑:程序博客网 时间:2024/04/30 16:55
一、冒泡算法
[算法思想]:将被排序的记录数组R[0..n-1]垂直排列,每个记录R[i]看作是重量为 R[i].key的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"飘浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。
#include<iostream>using namespace std;void BubbleSort(int R[],int n)//R(0..n-1)是待排序的文件,采用自下向上扫描,对R做冒泡排序 { int i,j;bool flag; //交换标志for(i=0;i<n-1;i++) //外循环控制循环趟数,最多做n-1趟排序{flag=false;int temp; for(j=n-1;j>i;j--) //对当前无序区R[i..n-1]自下向上扫描 if(R[j]<R[j-1]) { temp=R[j]; R[j]=R[j-1]; R[j-1]=temp; flag=true; } if(!flag) return;//本趟排序未发生交换,提前终止算法} } int main(){int a[10]={5,8,4,78,12,96,1,4,16,50};int i;for(i=0;i<10;i++)cout<<a[i]<<" ";cout<<endl; BubbleSort(a,10);for(i=0;i<10;i++)cout<<a[i]<<" ";cout<<endl; system("pause");return 0;}
[算法思想]:将被排序的记录数组R[0..n-1]垂直排列,每个记录R[i]看作是重量为 R[i].key的气泡。根据重气泡不能在轻气泡之上的原则,从上往下扫描数组R,凡扫描到违反本原则的重气泡,就使其向下"下沉"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。
#include<iostream>using namespace std;void BubbleSort(int R[],int n)//R(0..n-1)是待排序的文件,采用自下向上扫描,对R做冒泡排序 { int i,j;bool flag; //交换标志for(i=0;i<n-1;i++) //外循环控制循环趟数,最多做n-1趟排序{flag=false;int temp; for(j=0;j<n-i-1;j++) //对当前无序区R[i..n-1]自上向下扫描 if(R[j]>R[j+1]) { temp=R[j]; R[j]=R[j+1]; R[j+1]=temp; flag=true; } if(!flag) return;//本趟排序未发生交换,提前终止算法} } int main(){int a[10]={5,8,4,78,12,96,1,4,16,50};int i;for(i=0;i<10;i++)cout<<a[i]<<" ";cout<<endl; BubbleSort(a,10);for(i=0;i<10;i++)cout<<a[i]<<" ";cout<<endl; system("pause");return 0;}
注意:冒泡排序的空间复杂度为常量O(1),表示只需要一个辅助的temp存储单元来实现交换数据,即冒泡排序为就地排序。
冒泡排序的时间复杂度最好为O(n),最坏为O(n^2);
二、鸡尾酒算法(双向冒泡算法)
[算法思想]:数组中的数字本是无规律的排放,先找到最小的数字,把他放到第一位,然后找到最大的数字放到最后一位。然后再找到第二小的数字放到第二位,再找到第二大的数字放到倒数第二位。以此类推,直到完成排序
#include<iostream>using namespace std;void CocktailSort(int R[],int n){ int i,j,tail;tail=n-1;bool flag; //交换标志for(i=0;i<tail;) {flag=false;int temp;for(j=tail;j>i;j--)//第一轮,先将最小的数据排到前面if(R[j]<R[j-1]){temp=R[j]; R[j]=R[j-1];R[j-1]=temp;flag=true;}i++;//原来i处数据已排好序,加1for(j=i;j<tail;j++) //第二轮,将最大的数据排到后面if(R[j]>R[j+1]){temp=R[j]; R[j]=R[j+1];R[j+1]=temp;flag=true;}tail--;//原tail处数据也已排好序,将其减1if(!flag) return;//本趟排序未发生交换,提前终止算法} } int main(){int a[10]={5,8,4,78,12,96,1,4,16,50};int i;for(i=0;i<10;i++)cout<<a[i]<<" ";cout<<endl; CocktailSort(a,10);for(i=0;i<10;i++)cout<<a[i]<<" ";cout<<endl; system("pause");return 0;}
三、快速排序算法
[算法思想]:快速排序法原理也是用了分治法,主要原理是将数组分为A[p..q-1] 和A[q+1..r],然后调整元素使得A[p..q-1]小于等于q,也小于等于A[q+1..r]。然后不断的递归,到最后就排序完成。
快速排序是一种排序算法,对包含n个数的输入数组,平均时间为O(nlgn),最坏情况是O(n^2)。通常是用于排序的最佳选择。因为,基于比较的排序,最快也只能达到O(nlgn)。
快速排序方法1:
QUICKSORT(A, p, r)
1 if p < r
2 then q ← PARTITION(A, p, r) //关键
3 QUICKSORT(A, p, q - 1)
4 QUICKSORT(A, q + 1, r)
数组划分
快速排序算法的关键是PARTITION过程,它对A[p..r]进行就地重排:
PARTITION(A, p, r)
1 x ← A[r]
2 i ← p - 1
3 for j ← p to r - 1
4 do if A[j] ≤ x
5 then i ← i + 1
6 exchange A[i] <-> A[j]
7 exchange A[i + 1] <-> A[r]
8 return i + 1
例子如下:
1、i p/j
2 8 7 1 3 5 6 4(主元)
j指的2<=4,于是i++,i也指到2,2和2互换,原数组不变。
j后移,直到指向1..
2、j(指向1)<=4,于是i++
i指向了8,所以8与1交换。
数组变成了:
i j
2 1 7 8 3 5 6 4
3、j后移,指向了3,3<=4,于是i++
i这是指向了7,于是7与3交换。
数组变成了:
i j
2 1 3 8 7 5 6 4
4、j继续后移,发现没有再比4小的数,所以,执行到了最后一步,
即上述PARTITION(A, p, r)代码部分的 第7行。
因此,i后移一个单位,指向了8
i j
2 1 3 8 7 5 6 4
A[i + 1] <-> A[r],即8与4交换,所以,数组最终变成了如下形式,
2 1 3 4 7 5 6 8
快速排序第一趟完成。
4把整个数组分成了俩部分,2 1 3,7 5 6 8,再递归对这俩部分分别快速排序。
i p/j
2 1 3(主元)
2与2互换,不变,然后又是1与1互换,还是不变,最后,3与3互换,不变,最终,3把2 1 3,分成了俩部分,2 1,和3。再对2 1,递归排序,最终结果成为了1 2 3。
7 5 6 8(主元),7、5、6、都比8小,所以第一趟,还是7 5 6 8,不过,此刻8把7 5 6 8,分成了 7 5 6,和8.[7 5 6->5 7 6->5 6 7],再对7 5 6,递归排序,最终结果变成5 6 7 8。
#include<iostream>using namespace std;int Partition(int A[],int p,int r) //分治法 {int i,j,x,temp;x=A[r];i=p-1;for(j=p;j<r;j++) {if(A[j]<x){temp=A[j]; A[j]=A[++i];A[i]=temp;}}A[r]=A[++i];A[i]=x;return i;}void QuickSort(int A[],int p,int r){ int q;if (p<r){q=Partition(A,p,r) ;QuickSort(A,p,q-1);QuickSort(A,q+1,r);}} int main(){int a[11]={5,8,4,78,12,56,96,1,4,16,50};int i;for(i=0;i<11;i++)cout<<a[i]<<" ";cout<<endl; QuickSort(a,0,10);for(i=0;i<11;i++)cout<<a[i]<<" ";cout<<endl; system("pause");return 0;}
快速排序方法2:这个版本不再选取(如上第一版本的)数组的最后一个元素为主元,而是选择数组中的第一个元素为主元。
还是以上述相同的数组,应用此快排算法的版本二,来演示此排序过程:
这次,以数组中的第一个元素2为主元。
2(主) 8 7 1 3 5 6 4
请细看:
2 8 7 1 3 5 6 4
i-> <-j
(找大) (找小)
1、j
j找第一个小于2的元素1,1赋给(覆盖重置)i所指元素2
得到:
1 8 7 3 5 6 4
i j
2、i
i找到第一个大于2的元素8,8赋给(覆盖重置)j所指元素(NULL<-8)
1 7 8 3 5 6 4
i <-j
3、j
j继续左移,在与i碰头之前,没有找到比2小的元素,结束。
最后,主元2补上。
第一趟快排结束之后,数组变成:
1 2 7 8 3 5 6 4
第二趟,
7 8 3 5 6 4
i-> <-j
(找大) (找小)
1、j
j找到4,比主元7小,4赋给7所处位置
得到:
4 8 3 5 6
i-> j
2、i
i找比7大的第一个元素8,8覆盖j所指元素(NULL)
4 3 5 6 8
i j
4 6 3 5 8
i-> j
i与j碰头,结束。
第三趟:
4 6 3 5 7 8
......
以下,分析原理,一致,略过。
最后的结果,如下图所示:
1 2 3 4 5 6 7 8
#include<iostream>using namespace std;int Partition(int A[],int p,int r) //分治法 {int i=p,j=r,x;x=A[p];while (i<j){ while (i<j&&A[j]>=x) { j--; } if (i<j) { A[i]=A[j]; } while (i<j&&A[i]<=x) { i++; } if (i<j) { A[j]=A[i]; } }A[i]=x;return i;}void QuickSort(int A[],int p,int r){ int q;if (p<r){q=Partition(A,p,r) ;QuickSort(A,p,q-1);QuickSort(A,q+1,r);}} int main(){int a[11]={5,8,4,78,12,56,96,1,4,16,50};int i;for(i=0;i<11;i++)cout<<a[i]<<" ";cout<<endl; QuickSort(a,0,10);for(i=0;i<11;i++)cout<<a[i]<<" ";cout<<endl; system("pause");return 0;}
- 程序员面试宝典_第13章_数据结构基础_排序算法小结(1)
- 程序员面试宝典_第13章_数据结构基础_排序算法小结(2)
- 程序员面试宝典_第13章_数据结构基础_排序算法小结(3)
- 程序员面试宝典_第13章_数据结构基础_排序算法小结(4)
- 程序员面试宝典_第21章_智力测试
- 程序员面试宝典_笔记
- 排序_算法_数据结构
- 面试宝典第6章_ 1(预处理)
- 程序员面试宝典_程序设计基本概念
- 程序员面试宝典_8.2_典型递归问题_面试例题1
- 基础数据结构算法_快速排序,堆排序,归并排序
- 数据结构_快速排序算法
- 基础数据结构算法_哈夫曼树
- 基础数据结构算法_计数排序,基数排序,桶排序
- 程序员面试宝典_7.2 _面试例题9
- 栈与队列_第10章_基本数据结构_算法导论
- 链表_第10章_基本数据结构_算法导论
- 有根树的表示_第10章_基本数据结构_算法导论
- 第六周作业
- 求前k个最小的数---类似快排思想的O(n)
- 细说(int) , int.parse() , convert.int32() 区别
- Java <--> C#
- HDU Tour
- 程序员面试宝典_第13章_数据结构基础_排序算法小结(1)
- ccd相机介绍网址
- 原子操作的实现原理
- jQuery实现遮罩弹出对话框(仿天猫的删除对话框)
- jQuery和zTree实现的下拉树
- 周鸿祎:互联网思维不是“万能药”
- hosts.equiv和.rhosts文件——远程登录rlogin网络配置解析
- stm32时钟分析
- Spring事务管理—aop:pointcut expression解析