排序算法--考研复习

注意:!!
1、在排序过程中,每趟排序都能确定一个元素的最终位置的有冒泡排序、简单选择排序、堆排序、快速排序,其中前三者能形成全局有序的子序列,后者能确定枢轴元素的最终位置。
2、选择排序是不稳定的,再想想它的代码实现
3、对N个元素进行k路归并排序,排序的趟数m满足k^m=N–>m=logkN向上取整。
4、稳定性记忆–复杂的算法都不稳定(堆快希),简单的算法都稳定除了选择排序

这张图分析理解记忆
在这里插入图片描述

1、插入排序

文章链接
直接插入排序
折半插入排序
希尔排序

2、交换排序(冒泡和快排)

(1)冒泡例子
数组int a[10]={10,9,8,7,6,5,4,3,2,1};
以下为排序过程
9 8 7 6 5 4 3 2 1 10
8 7 6 5 4 3 2 1 9 10
7 6 5 4 3 2 1 8 9 10
6 5 4 3 2 1 7 8 9 10
5 4 3 2 1 6 7 8 9 10
4 3 2 1 5 6 7 8 9 10
3 2 1 4 5 6 7 8 9 10
2 1 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10

代码

//冒泡排序
void BobbleSort(int a[],int n)//求一个递增序列
{
    for(int i=0;i<n-1;i++){
        bool flag = 0;
        for(int j=0;j<=n-1-i;j++){//从前往后冒泡
            if(a[j]>a[j+1]){//如果为逆序--前比后大
                //swap
                int temp = a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
                flag=1;
            }
        }
        if(flag==0){//本趟遍历后没有发生交换,说明表已经有序
            cout<<1<<endl;
            break;
        }
    }
}

在这里插入图片描述

(2)快排
快速排序例子

//从小到大排序
//算法思想:选取基准 划分为左小右大
void Quick_sort(int a[],int low,int high)
{
    if(low<high){
        int i,j;i=low-1;j=high+1;
        int x = a[ (low+high) >>1 ];
        while(i<j){
            do j--;while(a[j]>x);//找到右边比基数小的数
            do i++;while(a[i]<x);//找到左边比基数大的数
            
            if(i<j)swap(a[i],a[j]);//交换 两个数
        }
        Quick_sort(a,low,j);
        Quick_sort(a,j+1,high);
    }
}

3、选择排序(简单选择、堆排序)

(1)简单选择排序
!!举个例子,序列arr = [5 8 5 2 9],我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。
请添加图片描述

void simple_sort(int a[],int n)//
{
    for(int i=0;i<n;i++){
        int min_index = i;
        for(int j=i;j<n;j++){
            if(a[min_index]>a[j])min_index=j;
        }
        int temp = a[i];
        a[i]=a[min_index];
        a[min_index]=temp;
    }
}

(2)堆排序
导图–和完全二叉树性质对应复习
请添加图片描述

例子请添加图片描述

在这里插入图片描述

代码
绝了,之前直接build heap,没分清建堆和堆调整的区别。。

#include<bits/stdc++.h>
using namespace std;
void adjustHeap(int a[],int i,int len)//将以i为根的子树调整为大根堆
{
    for(int j=2*i;j<=len;j*=2){//遍历结点直到为5步情况
        if(j+1<=len){//说明结点i有两个孩子
            //比较a[j]和a[j+1]的大小,选出孩子结点中最大的和i结点进行比较
            if(a[j]>a[j+1]&&a[j]>a[i])swap(a[i], a[j]);
            else if(a[j]<a[j+1]&&a[j+1]>a[i])swap(a[i], a[j+1]);
        }else{//只有一个左孩子,所以比较一次
            if(a[i]<a[j]){
                swap(a[i], a[j]);
            }
        }
    }
}
void BuildMaxHeap(int a[],int len)//建立大根堆
{
    for(int i=len/2;i>0;i--){
        adjustHeap(a, i,len);
    }
}
void Heapsort(int a[],int len)
{
    BuildMaxHeap(a, len);
    for(int i=1;i<len;i++){
        swap(a[1],  a[len-i+1]);//堆顶和最后一个交换
        adjustHeap(a, 1, len-i);
    }
}
int main()
{
    int a[11]={0,10,9,8,7,6,5,4,3,2,1};//index从1号算起,a[0]不存储数据
//    int a[11]={0,1,2,3,4,5,6,7,8,9,10};
    Heapsort(a,10);
    for(int i=1;i<11;i++){
        cout<<a[i]<<' ';
    }
}

不大好的代码

#include<bits/stdc++.h>
using namespace std;
void BuildMaxHeap(int a[],int len)//index 从1开始--建立大根堆
{
    for(int i=len/2;i>0;i--){
        for(int j=2*i;j<=len;j*=2){//遍历结点直到为5步情况
            if(j+1<=len){//说明结点i有两个孩子
                //比较a[j]和a[j+1]的大小,选出孩子结点中最大的和i结点进行比较
                if(a[j]>a[j+1]&&a[j]>a[i])swap(a[i], a[j]);
                else if(a[j]<a[j+1]&&a[j+1]>a[i])swap(a[i], a[j+1]);
            }else{//只有一个左孩子,所以比较一次
                if(a[i]<a[j]){
                    swap(a[i], a[j]);
                }
            }
        }
    }
}
void Heapsort(int a[],int len)
{
    BuildMaxHeap(a, len);
    for(int i=1;i<len;i++){
        swap(a[1],  a[len-i+1]);//堆顶和最后一个交换
        BuildMaxHeap(a,len-i);
    }
}
int main()
{
    int a[11]={0,10,9,8,7,6,5,4,3,2,1};//index从1号算起,a[0]不存储数据
//    int a[11]={0,1,2,3,4,5,6,7,8,9,10};
    Heapsort(a,10);
    for(int i=1;i<11;i++){
        cout<<a[i]<<' ';
    }
}

归并排序

请添加图片描述

代码

#include<bits/stdc++.h>
using namespace std;
//采用递归实现 --递增序列
void Merge_sort(int b[],int a[],int low,int high)//时间复杂度 o(nlog2n)  空间复杂度 o(n)
{
    if(low<high){//--递归记得break条件
        int mid = (high+low)/2;
        Merge_sort(b,a, low,mid);//对左子序列 进行归并排序
        Merge_sort(b,a, mid+1,high);//对右子序列 进行归并排序
        //将上述两个排好序的序列进行2路归并
        for(int i=low;i<=high;i++){//copy原数组
            b[i]=a[i];
        }
        int index = low;
        int i=low,j=mid+1;
        while(i<=mid&&j<=high){
            if(b[i]<b[j]){
                a[index]=b[i];
                i++;
            }else{
                a[index] = b[j];
                j++;
            }
            index++;
        }
        while(i<=mid)a[index++]=b[i++];
        while(j<=high)a[index++]=b[j++];
    }

}
int main()
{
    int a[11]={0,10,9,8,7,6,5,4,3,2,1};//index从1号算起,a[0]不存储数据
    int b[11];
//    int a[11]={0,1,2,3,4,5,6,7,8,9,10};
    Merge_sort(b,a, 1, 10);
    for(int i=1;i<11;i++){
        cout<<a[i]<<' ';
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_47696370/article/details/129636852