数据结构-排序

163 阅读3分钟

排序(Sort),就是重新排序表中的元素,使表中的元素满足按关键字允许的过程 image.png 排序算法的评价指标 时间复杂度、空间复杂度 算法的稳定性: image.png image.png

插入排序

算法思想:每次将一个待排序的记录按其关键字大小插入到前面已排好序的子序列中,直到全部记录插入完成 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

算法实现

//直接插入排序
void InserSort(int A[],int n){
	int i,j,temp;
    for(i=1;i<n;i++)		//将各元素插入已排好序的序列中
        if(A[i]<A[i-1]){	//若A[i]关键字小于前驱
            temp=A[i];		//用temp暂存A[i] 
            for(j=i-1;j>=0 && A[j]>temp;--j) //检查所有前面已排好序的元素
                A[j+1]=A[j];	//所有大于temp的元素都向后挪位
            A[j+1]=temp;		//复制到插入位置
        }
}

算法实现(带哨兵) image.png 算法效率分析 空间复杂度:O(1) 时间复杂度:主要来自对比关键字、移动元素若有n个元素,则需要n-1趟处理 最好情况: 共n-1趟处理,每一趟只需要对比关键字1次,不用移动元素 最好时间复杂度--O(n) 最坏情况: image.png 最坏时间复杂度--O(n^2) image.png

优化--折半插入排序

思路:先用折半查找找到应该插入的位置,再移动元素 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

image.png image.png image.png image.png image.png image.png image.png image.png image.png

//折半插入排序
void InserSort(int  A[],int n){
	int i,j,low,high,mid;
    for(i=2;i<=n;i++){
        A[0]=A[i];
        low=1;high=i-1;
        while(low<=high){
            mid=(low+high)/2;
            if(A[mid]>A[0]) high=mid-1;
            else low=mid+1;
        }
        for(j=i-1;j>=high+1;--j)
            A[j+1]=A[j];
        A[high+1]=A[0];
    }
}

image.png image.png

希尔排序(Shell Sort)

先追求表中元素部分有序,再逐渐逼近全局有序 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 算法实现

//希尔排序
void Shell Sort(int A[],int n){
	int d,i,j;
    for(d=n/2;d>=1;d=d/2)
        for(i=d+1;i<=n;++i)
            if(A[i]<A[i-d]){
                A[0]=A[i];
                for(j=i-d;j>0&&A[0]<A[j];j-=d)
                    A[j+d]=A[j];
                A[j+d]=A[0];
            }
}

image.png image.png image.png

冒泡排序

基于“交换”的排序:根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.pngimage.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png
image.png image.png image.png 算法实现

//交换
void swap(int &a,int &b){
	int temp=a;
    a=b;
    b=temp;
}
//冒泡排序
void BubbleSort(int A[],int n){
	for(int i=0;i<n-1;i++){
        bool flag=false;
        for(int j=n-1;j>i;j--)
            if(A[j-1]>A[j]){
                swap(A[j-1],A[j]);
                flag=true;
            }
        if(flag==false)
            return;
    }
}

image.png 算法性能分析 image.png image.png

快速排序

基于“交换”的排序:根据序列中两个元素关键字的比较结果来对换这两个记录在序列中的位置 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

int Partition(int A[],int low,int high){
	int pivot=A[low];
    while(low<high){
        while(low<high&&A[high]>=pivot)--high;
        A[low]=A[high];
        while(low<high&&A[low]<=pivot)++low;
        A[high]=A[low];
    }
    A[low]=pivot;
    return low;
}
void QuickSort(int A[],int low,int high){
	if(low<high){
        int pivotpos=Partition(A,low,high);
        QuickSort(A,low,pivotpos-1);
        QUickSort(A,pivotpos+1,high);
    }
}

image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png
image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 算法效率分析 image.png image.png image.png image.png 最坏情况 image.png 比较好的情况 若每一次选中的“枢轴”将待排序序列划分为均匀的两个部分,则递归速度最小,算法效率最高 image.png image.png image.png

简单选择排序

选择排序:简单选择排序、堆排序 选择排序:每一趟在待排序元素中选取关键字最小(或最大)的元素加入有序子序列

每一趟在待排序元素中选取关键字最小的元素加入有序子序列 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 算法实现

void SelectSort(int A[],int n){
	for(int i=0;i<n-1;i++){
        int min=i;
        for(int j=i+1;j<n;j++)
            if(A[j]<A[min]) min=j;
        if(min!=i) swap(A[i],A[min]);
    }
}
void swap(int &a.int &b){
	int temp=a;
    a=b;
    b=temp;
}

image.png 算法性能分析 image.png image.png image.png

堆排序

什么是堆 image.png image.png image.png 建立大根堆 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

void BuildMaxHeap(int A[],int len){
	for(int i=len/2;i>0;i--)
        HeadAdjust(A,i,len);
}
void HeadAdjust(int A[],int k,int len){
	A[0]=A[k];
    for(int i=2*k;i<=len;i*=2){
        if(i<len&&A[i]<A[i+1])
            i++;
        if(A[0]>=A[i])break;
        else{
            A[k]=A[i];
            k=i;
        }
    }
    A[k]=A[0];
}

image.png 基于大根堆进行排序 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

void BuildMaxHeap(int A[],int len)

void HeadAdjust(int A[],int k,int len)

void HeapSort(int A[],int len){
	BuildMaxHeap(A,len);
    for(int i=len;i>1;i--){
        swap(A[i],A[1]);
        HeadAdjust(A,1,i-1)
    }
}

image.png image.png 算法效率分析 image.png image.png image.png

在堆中插入新元素

image.png image.png image.png image.png image.png

在堆中删除元素

image.png image.png image.png image.png image.png image.png image.png image.png image.png

归并排序

归并:把两个或多个已经有序的序列合并成一个 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 代码实现

int *B=(int *)malloc(n*sizeof(int));
void Merge(int A[],int low,int mid,int high){
	int i,j,k;
    for(k=low;k<=high;k++)
        B[k]=A[k];
    for(i=low,j=mid+1,k=i;i<=mid&&j<=high;k++){
        if(B[i]<=B[j])
            A[k]=B[i++];
        else 
            A[k]=B[j++];
    }
    while(i<=mid) A[k++]=B[i++];
    while(j<=high) A[k++]=B[j++];
}

image.png

image.png image.png image.png image.png

image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

void MergeSort(int A[],int low,int high){
	if(low<high){
        int mid=(low+high)/2;
        MergeSort(A,low,mid);
        MergeSort(A,mid+1,high);
        Merge(A,low,mid,high);
    }
}

image.png image.png image.png

基数排序(Radix Sort)

image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 算法效率分析 image.png image.png image.png 稳定性 image.png image.png image.png image.png 基数排序的应用 image.png image.png image.png image.png

外部排序

外存、内存之间的数据交换

image.png image.png image.png image.png image.png

外部排序原理

image.png 构造初始“归并段” image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 第一趟归并 把8个有序子序列(初始归并段)两两归并 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png 第二趟归并 把4个有序子序列(归并段)两两归并 image.png image.png image.png image.png 第三趟归并 把2个有序子序列(归并段)归并 image.png image.png 时间开销分析 image.png 外部排序时间开销=读写外存的时间+内部排序所需时间+内部归并所需时间 优化:多路归并 image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

败者树

多路平衡归并带来的问题 image.png 什么是败者树 image.png image.png image.png 基于已经构建好的败者树,选出新的胜者只需进行3场比赛

败者树在多路平衡归并中的应用

image.png image.png image.png image.png image.png image.png

置换-选择排序

image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

最佳归并树

归并树的神秘性质 image.png image.png 构造2路归并的最佳归并树 image.png 多路归并的情况 image.png 多路归并的最佳归并树 image.png image.png image.png image.png image.png 如果减少一个归并段 image.png image.png image.png 正确的做法 image.png image.png image.png image.png image.png image.png image.png image.png