八、排序
- 排序概述
- 排序的分类:内部排序和外部排序(若待排序记录都在内存中,称为内部排序;若待排序记录一部分在内存,一部分在外存,则称为外部排序)。稳定排序和不稳定排序。
- 内部排序的算法:插入排序(希尔排序)、交换排序(快速排序)、选择排序(堆排序)、归并排序、基数排序。
- 插入排序
- 思想:每次将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。
- 具体实现算法:直接插入排序、折半插入排序、希尔排序
- 直接插入排序:
void InsertSort(int a[]){
int i,j;
//按照有小到大的顺序排序
for(i=2;i<a.length;i++){
//找到无序表的第一个位置
if(a[i]<a[i-1]){
a[0]=a[i];
//将无序表依次向后移动
for(j=i-1;a[0]<a[j];j--){
a[j+1]=a[j];
}
//将数据插入相应位置
a[j+1]=a[0];
}
}
}
该算法的时间复杂度是:O(n2)
- 折半插入排序:
void BInsertSort(int a[]){
int i,j,high,low;
for(i=2;i<a.length;i++){
a[0]=a[i];
low=1;
high=i-1;
int min;
while(low<=high){ //使用折半查找到插入的位置
min=(high+low)/2;
if(a[0]<a[min])
high=min-1;
else
low=min+1;
}
for(j=i-1;j=>high+1;j++) //插入的位置是在high位置之后
a[j+1]=a[j];
a[high+1]=a[0];
}
}
- 希尔排序:
void SheelSort(int a[],int dx){
//这是对直接插入排序的修改
//dx表示增量
//当j<=0时,插入位置已经找到
int i,j;
for(i=dx+1;i<a.length;i++){
if(a[i]<a[i-dx]){
a[0]=a[i];
for(j=i-dx;j>0&&a[0]<a[j];j-=dx)
a[j+dx]=a[j];
a[j+dx]=a[0];
}
}
}
- 交换排序
- 两两比较待排序记录的关键码,如果发生逆序(即排列顺序与排序后次序正好相反),则交换之,直到所有记录都排好序为止。
- 冒泡排序:
void bubbleSort(int a[]){
int i,j;
for(i=1;i<a.length-1;i++){
for(j=1;j<a.length-i;j++){
if(a[j]>a[j+1]){
a[0]=a[j];
a[j]=a[j+1];
a[j+1]=a[0];
}
}
}
}
- 快速排序:
void Partition(int a[],int low,int high){
//这只是一趟快速排序的算法
a[0]=a[low];
while(low<high){
//从高位往低位扫描,找到数值小于关键字的位置,与low位置交换
while(low<high&&a[0]<=a[high])
high--;
a[low]=a[high];
//从低位往高位扫描,找到数值大于关键字的位置,与high位置交换
while(low<high&&a[low]<=a[0])
low++;
a[high]=a[low];
}
//最后将关键字放入数组中
a[low]=a[0];
}
快速排序平均时间复杂度和最好时间复杂度为:O(log2n),最坏时间复杂度为O(n2)。
- 选择排序
- 不断从待排记录序列中选出关键字最小的记录插入已排序记录序列的后面,直到n个记录全部插入已排序记录序列中。
- 简单选择排序:
- 堆排序:借助于完全二叉树结构进行的排序,是一种树形选择排序。其特点是——在排序过程中,将R[1...N]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录。
- 建立一个堆排序的方法:
- 堆排序的过程:
- 堆排序算法实现:
void HeapAdjust(int *a,int i,int size) //调整堆
{
int lchild=2*i; //i的左孩子节点序号
int rchild=2*i+1; //i的右孩子节点序号
int max=i; //临时变量
if(i<=size/2) //如果i不是叶节点就不用进行调整
{
if(lchild<=size&&a[lchild]>a[max])
{
max=lchild;
}
if(rchild<=size&&a[rchild]>a[max])
{
max=rchild;
}
if(max!=i)
{
swap(a[i],a[max]);
}
}
}
void BuildHeap(int *a,int size) //建立堆
{
int i;
for(i=size/2;i>=1;i--) //非叶节点最大序号值为size/2
{
HeapAdjust(a,i,size);
}
}
void HeapSort(int *a,int size) //堆排序
{
int i;
BuildHeap(a,size);
for(i=size;i>=1;i--)
{
//cout<<a[1]<<" ";
swap(a[1],a[i]); //交换堆顶和最后一个元素,即每次将剩余元素中的最大者放到最后面
//BuildHeap(a,i-1); //将余下元素重新建立为大顶堆
HeapAdjust(a,1,i-1); //重新调整堆顶节点成为大顶堆
}
}
- 归并排序
- “归并”的含义是将两个或两个以上的有序表合并成一个新的有序表。
-
- 两个有序表的合并算法Merge():
- 算法分析:
- 基数排序
- 基数排序是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法,即先将关键字分解成若干部分,然后通过对各部分关键字的分别排序,最终完成对全部记录的排序。
- 多关键字的排序:
- 链式基数排序:
- 排序算法总结
九、时间复杂度
- 该时间复杂度表达作用于递归过程。
- n/b表示下一回递归的数据量为n/b,a表示递归的次数为a,除了递归之外的时间复杂度为O(nd)。
作者:龙猫小爷
链接:http://www.jianshu.com/p/2469a4d9708e
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。