十种排序算法总结(详解附实现代码)

排序

在这里插入图片描述

直接插入排序

折半插入排序是在直接插入排序上的一个优化,举个例子,我们左边的数据元素本身是有序的,这个时候要插入的关键字跟这个有序序列的最后一个元素对比,也就是前一个元素对比,发现是逆序,那么这个时候就能确定这个元素得插在这个序列里面,怎么快速找到要插入的位置呢,直接插入排序的做法是通过指针遍历前面的每个元素,找到带插入的位置。

但是我们可以通过折半查找的思想快速定位到要插入的位置,但是找到位置后,插入,右边元素移动还是跟原来一样,这个就是折半插入排序由来。

值得注意的是,直接插入排序我们可以用顺序表、也可以用链表,但是折半只能用顺序表

在这里插入图片描述

希尔插入排序

在这里插入图片描述

冒泡排序

在这里插入图片描述

快速排序

在这里插入图片描述

简单选择排序

在这里插入图片描述

堆排序

在这里插入图片描述

归并排序

在这里插入图片描述

基数排序

在这里插入图片描述

外部排序

在这里插入图片描述
外部排序要求我们尽量减少访问磁盘次数,怎么减少呢,磁盘数量是固定不变的,每次排序我们要读入还要写回,既然磁盘数量不变,我们能不能用几趟就排序好呢,所以优化方向是减少趟数S = h-1 = Logkr (k是几个输入缓冲区,r是初始归并段)

  • 加多几个缓冲区,带来的代价是内部归并关键字对比加大,要从k个输入缓冲区也就是归并段中比较k-1次,不过我们可以通过败者树优化
  • 减少初始归并段的个数,我习惯叫0趟归并排序,这里可以通过置换-选择排序进一步优化

外部排序时间开销 = 读写外存的时间+0趟内部排序所需时间+内部归并所需时间

代码

//
//  seq_sort.cpp


#include <stdio.h>


#include<iostream>

using namespace std;
void print_data(int A[], int n){
//    cout << "下标从0开始:";
    for (int i = 0; i<n; i++) {
        cout << A[i] << " ";
    }
    cout << endl << endl;
}

//下标1开始
void print_data1(int A[], int n){
//    cout << "下标从1开始:";
    for (int i = 1; i<=n; i++) {
        cout << A[i] << " ";
    }
    cout << endl << endl;
}
//直接插入排序
//算法思想,把前面看成有序,后面的元素查找合适的位置然后插进去
void insert_sort(int A[], int n){
    cout << "初始序列:" << endl;
    print_data(A, n);
    int i, j, temp;
    for (i = 1; i<n; i++) {
        
        if (A[i-1]>A[i]) {//只有前驱比当前元素大的时候,才需要发生循环对比,当前元素之前的元素都是有序的
            temp = A[i];
        
            for (j = i - 1; j>=0; j--) {
                if (temp<A[j]) {
                    A[j+1] = A[j];
                }else{
//                    cout << "break j:" << j << endl;
                    break;//跳出, 前面是有序的
                }
            }
            A[j+1] = temp;
        }
       
    }
    cout << "直接插入排序1 insert_sort:" << endl;
    print_data(A, n);
}
//直接插入排序 优化for循环判断
void insert_sort1(int A[], int n){
    cout << "初始序列:" << endl;
    print_data(A, n);
    int i, j, temp;
    for (i = 1; i<n; i++) {
        
        if (A[i-1]>A[i]) {//只有前驱比当前元素大的时候,才需要发生循环对比,当前元素之前的元素都是有序的
            temp = A[i];
        
            for (j = i - 1; temp<A[j] && j>=0; j--) {
                A[j+1] = A[j];
            }
            A[j+1] = temp;
        }
       
    }
    cout << "直接插入排序2 insert_sort1:" << endl;
    print_data(A, n);
}
// 加个哨兵 下标0 不存实际数据
void insert_sort2(int A[], int n){
    cout << "初始序列:" << endl;
    print_data1(A, n);
    int i,j;
    for (i = 2; i<=n; 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];
        }
    }
    cout << "直接插入排序3 insert_sort2:" << endl;
    print_data1(A, n);
}

// 定位插入的位置 我们用折半查找
void insert_sort3(int A[], int n){
    cout << "初始序列:" << endl;
    print_data1(A, n);
    int i,j;
    for (i = 2; i<=n; i++) {
        if (A[i]<A[i-1]) {
            A[0] = A[i];
            
            int low = 1, high = i-1, mid;
    
            while (high>=low) {
                mid = (low+high)/2;
                if (A[mid] < A[0]) {
                    low = mid+1;
                }else{//包含=的情况,排序的稳定性要求我们要继续查找
                    high = mid - 1;
                }
            }
            for (j=i-1; low<=j; j--) {
                A[j+1] = A[j];
            }
     
            A[low] = A[0];
        }
    }
    cout << "直接插入排序4 insert_sort3:" << endl;
    print_data1(A, n);
}

    
void bubble_sort(int A[], int n){
    cout << "初始序列:" << endl;
    print_data(A, n);
    for (int i = 0; i<n-1; i++) {
        bool flag = false;
        for (int j = 1; j<n-i; j++) {
            if (A[j-1]>A[j]) {
                int temp = A[j];
                A[j] = A[j-1];
                A[j-1] = temp;
                flag = true;
            }
        }
 
        if (flag==false) {
            break;
        }
        
    }
    cout << "冒泡排序 bubble_sort:" << endl;
    print_data(A, n);
}

// 希尔排序 中间目标是找出基本有序,最后增量为1,也就还是要用直接插入排序
// 这个用链表实现比较麻烦吧 因为要找增量对应的元素
// 不稳定,因为相同的元素在不同子表时会发生调换
void shell_sort(int A[], int n){
    cout << "初始序列:" << endl;
    print_data1(A, n);
    int i,j,d;
    //数组下标0不存放实际数据
    for (d = n/2; d>=1; d=d/2) {
        for (i = d+1; i<=n; i++) {//d+1不奇怪 正确的 下面的if要往回判断
            if (A[i]<A[i-d]) {//前面的比后面的大,需要交换
                A[0] = A[i];
                //现在要找位置,并把对应元素后移+d的位置
                for (j = i-d; A[0]<A[j]&&j>0; j = j-d) {
                    A[j+d] = A[j];
                }
            
                A[j+d] = A[0];
            }
        }
    }
    cout << "希尔排序1 shell_sort:" << endl;
    print_data1(A, n);
}

// 上面的实现是,每次根据当下的元素,进行插入,要到i=n时,全部子表才有序,
// 能不能直接把子表有序化,再有序下一个子表呢
void shell_sort1(int A[], int n){
    cout << "初始序列:" << endl;
    print_data1(A, n);
    int i,j,d;
    //数组下标0不存放实际数据
    for (d = n/2; d>=1; d=d/2) {
        int counter = 1;
        while (counter <= d) {

            for (i = d+counter; i<=n; i+=d) {
                if (A[i]<=A[i-d]) {//前面的比后面的大,需要交换
               
                    A[0] = A[i];
                    //现在要找位置,并把对应元素后移+d的位置
                    for (j = i-d; A[0]<A[j]&&j>0; j = j-d) {
                        A[j+d] = A[j];
                    }
                
                    A[j+d] = A[0];

                }
            }
           
         
            counter++;
        }
    }
    cout << "希尔排序2 shell_sort1:" << endl;
    print_data1(A, n);
}


//快速排序,居然敢自称快速排序,一定是很牛的算法
//顺序 或者 逆序效率最差。因为没办法没成2个部分 基准是第一个
//优化建议,基准选中间元素,或者随机
//最好时间复杂度是O(n) * O(log2n), 每次递归排序不超过n个元素,*递归深度就是全部的时间复杂度
//最坏时间复杂度是当递归深度=n,所以最坏时间复杂度是O(n2)
//不稳定,因为每次排序就确定了1个位置,如果2个相同元素离很近,排序后的下标又很大,那么先排的元素就去到后面
//平均时间复杂度是O(nlog2n)
int do_quick_sort(int A[], int low, int high);
void quick_sort(int A[], int n, int low, int high){
    if (low<high) {
        int temp = do_quick_sort(A, low, high);
        quick_sort(A, n, low, temp-1);
        quick_sort(A, n, temp+1, high);
   
    }
}

int do_quick_sort(int A[], int low, int high){

    int temp = A[low];//以low为第一个元素,说明要从high开始对比
    while(low<high){
        while (low<high && temp<A[high]) {//指针从右向左移动,找到比基准值小的元素,丢到基准值左边
         high--;
        }
        A[low] = A[high];
        while (low<high && temp>A[low]) {
         low++;
        }
        A[high] = A[low];

    }
    A[low] = temp;
    return low;
}

// 简单选择排序
void simple_select_sort(int A[], int n){
    cout << "初始序列:" << endl;
    print_data(A, n);
    int min = 0 ;
    for (int i = 0; i<n-1; i++) {
        min = i;
        for (int j = i+1; j<n; j++) {
         
            if (A[min]>A[j]) {
                min = j;
            }
        }
        
        if (i!=min) {
            int temp = A[min];
            A[min] = A[i];
            A[i] = temp;
        }
    }
    cout << "简单选择排序 simple_select_sort:" << endl;
    print_data(A, n);
}

void max_heap_adjust(int A[], int k, int n);
// 堆排序
// 完全二叉树
// 建立大根堆的过程,先把给定的初始序列看成完成二叉树,然后对分支结点进行调整,调整到满足大根堆要求
// O(n) + O(nlog2n) = O(nlog2n)
// 不稳定,比如1、2、2。,建堆还是顺序的,2、1、2.但是排序时两个2会对掉,1、2.、2
void max_heap_sort(int A[], int n){
    cout << "大根堆初始序列:" << endl;
    print_data1(A, n);
    //从后往前调整非叶子结点 O(n)
    for (int i = n/2; i>0; i--) {
        max_heap_adjust(A, i, n);
       
    }
    cout << "建立大根堆 build_max_heap:" << endl;
    print_data1(A, n);
 
    //时间复杂度 O(nlog2n)
    for (int i = 1; i<=n; i++) {
        A[0] = A[1];
        A[1] = A[n-i+1];
        A[n-i+1] = A[0];
        max_heap_adjust(A, 1, n-i);
    }
    cout << "大根堆排序得到递增序列 max_head_sort:" << endl;
    print_data1(A, n);
}
void max_heap_adjust(int A[], int k, int n){
    A[0] = A[k];
    //i是k他的左孩子下标
    //小元素下坠
    for (int i = 2*k; i<=n; i*=2) {//下一个左孩子下标
        if (i<n) {//可能没有右孩子
            if (A[i]<A[i+1]) {
                i++;
            }
        }
        if (A[0]<A[i]) {
            A[k] = A[i];
            k = i;
        }else{
            break;
        }
    }
    A[k] = A[0];
 
}

void min_heap_adjust(int A[], int k, int n);
void min_heap_sort(int A[], int n){
    cout << "小根堆初始序列:" << endl;
    print_data1(A, n);
    cout << "建立小根堆 build_min_heap:" << endl;
    for (int i = n/2; i>0; i--) {//非叶子结点从后往前遍历
        min_heap_adjust(A, i, n);
    }

    print_data1(A, n);
    for (int i = n; i>0; i--) {
        A[0] = A[i];
        A[i] = A[1];
        A[1] = A[0];
        min_heap_adjust(A, 1, i-1);
    }
    cout << "小根堆排序得到递减序列 min_heap_sort:" << endl;
    print_data1(A, n);
}

void min_heap_adjust(int A[], int k, int n){
    A[0] = A[k];
 
    //分支结点肯定有左孩子
    for (int i = k*2; i<=n; i*=2) {
        if (i<n) {
            if (A[i]>A[i+1]) {
                i++;
            }
        }
        if (A[0]<A[i]) {
            break;
        }else{
            A[k] = A[i];
            k = i;//用于交换
        }
    }
    A[k] = A[0];
}
void min_heap_pop(int A[], int k, int n){
    //check A[]是否是小根堆
    
    //逻辑删除下标k元素
    A[k] = A[n];
    n--;
    cout << "n " << n << endl;
    min_heap_adjust(A, k, n);
    print_data1(A, n);
}
void min_heap_push(){
    int A[10]={0,1,2,3,4,5};
    int k = 6;
    int n = 5;
    //check A[]是否是小根堆
    
    //逻辑增加下标k元素
    A[0] = A[++n] = -1;
    for (int i = k/2; i>0; i/=2) {
        if (A[i]>A[0]) {
            A[k] = A[i];
            k = i;
        }
    }
    A[k] = A[0];
   
    print_data1(A, n);
}

//归并排序
int *B = (int *)malloc(10*sizeof(int));
void do_merge_sort(int A[], int low, int high){
    for (int i = low; i<=high; i++) {
        B[i] = A[i];
    }
    int mid = (low+high) / 2;

    int i = 0, j = 0, k = 0;
    for (i = low, j = mid+1, k = low; i<=mid&&j<=high; k++) {
      
        if (B[i]>B[j]){
            A[k] = B[j++];
        }else{
            A[k] = B[i++];
        }
    }
    while (i<=mid) {
        A[k++]=B[i++];
    }
    while (j<=high) {
        A[k++]=B[j++];
    }

}

void merge_sort(int A[], int low, int high){
    if (low < high) {
        //这里类似二叉树后序遍历,把合并的操作放在最后
        int mid = (low+high)/2;
        merge_sort(A, low, mid);
        merge_sort(A, mid+1, high);
        do_merge_sort(A, low, high);
    }
}
int main(){
    cout << "welcome, to my world!" << endl;
    cout << "下面求每个初始序列的递增排序:" << endl << endl;
//    int A[] = {9,8,7,6,5,4,3,2,1};
    int A[] = {49,38,65,97,76,13,27,8,9};
  
//    int A[] = {1,2,3,4,5,6,7,8,9};
    insert_sort(A, 9);//传指针
    int B[] = {49,38,65,97,76,13,27,8,9};
    insert_sort1(B, 9);//传指针
    
    int C[] = {999,49,38,65,97,76,13,27,8,9};//999表示这个位置不放实际数据,下面一样
    insert_sort2(C, 9);//传指针
    
    
    int D[] = {999,49,38,65,97,76,13,27,8,9};
    insert_sort3(D, 9);//传指针
    
    int E[] = {49,38,65,97,76,13,27,8,9};
    bubble_sort(E, 9);//传指针
    
    int F[] = {999,49,38,65,97,76,13,27,8,9};
    shell_sort(F, 9);//传指针
    
    
    int G[] = {999,49,38,65,97,76,13,27,8,9};
    shell_sort1(G, 9);
    
    int H[] = {49,38,65,97,76,13,27,8,9};
    cout << "初始序列:";
    print_data(H, 9);
    quick_sort(H, 9, 0, 8);
    cout << "快速排序 quick_sort:" << endl;
    print_data(H, 9);
    
    
    int I[] = {49,38,65,97,76,13,27,8,9};
    simple_select_sort(I, 9);
    
    
    int J[] = {999,49,38,65,97,76,13,27,8,9};
    cout << "初始序列:" << endl;
    print_data1(J, 9);
    max_heap_sort(J, 9);
    
    int K[] = {999,49,38,65,97,76,13,27,8,9};
    cout << "初始序列:" << endl;
    print_data1(K, 9);
    min_heap_sort(K, 9);

   
    int L[] = {49,38,65,97,76,13,27,8,9};
    cout << "初始序列:" << endl;
    print_data(L, 9);
    cout << "归并排序 merge_sort:" << endl;
    merge_sort(L, 0, 8);
    print_data(L, 9);
    return 0;
}



输出

welcome, to my world!
下面求每个初始序列的递增排序:

初始序列:
49 38 65 97 76 13 27 8 9

直接插入排序1 insert_sort:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

直接插入排序2 insert_sort1:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

直接插入排序3 insert_sort2:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

直接插入排序4 insert_sort3:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

冒泡排序 bubble_sort:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

希尔排序1 shell_sort:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

希尔排序2 shell_sort1:
8 9 13 27 38 49 65 76 97

初始序列:49 38 65 97 76 13 27 8 9

快速排序 quick_sort:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

简单选择排序 simple_select_sort:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

大根堆初始序列:
49 38 65 97 76 13 27 8 9

建立大根堆 build_max_heap:
97 76 65 38 49 13 27 8 9

大根堆排序得到递增序列 max_head_sort:
8 9 13 27 38 49 65 76 97

初始序列:
49 38 65 97 76 13 27 8 9

小根堆初始序列:
49 38 65 97 76 13 27 8 9

建立小根堆 build_min_heap:
8 9 13 38 76 65 27 97 49

小根堆排序得到递减序列 min_heap_sort:
97 76 65 49 38 27 13 9 8

初始序列:
49 38 65 97 76 13 27 8 9

归并排序 merge_sort:
8 9 13 27 38 49 65 76 97

Program ended with exit code: 0

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值