王道数据结构-排序算法(c/c++)

1、插入排序-直接插入排序
特点:部分元素整体移动,确定该元素需要插入后,比较与移动同时进行。
可以使用顺序存储与链式存储。
该算法稳定
#include<stdio.h>
using namespace std;
void insertsort(int a[],int n){
    int i,j;
    for(i=2;i<=n;i++){//从第二个元素开始比较,所以比较到i时,i前面都是有序的
       if(a[i]<a[i-1]){//i前面是有序的,只需要找到合适的插入位置即可
         a[0]=a[i];//哨兵
         for(j=i-1;a[0]<a[j];j--){
             a[j+1]=a[j];//依次向后移
         }
         a[j+1]=a[0];
       }
       printf("i为%d时,排序结果:",i);//为什么最多只有n-1次,因为默认第一个元素是有序
       for(j=1;j<=n;j++){
          printf("%d ",a[j]);
       }
       printf("\n");
    }
}
        
int main(){
    int n,a[100];
    scanf("%d",&n);
    int i;
    for(i=1;i<=n;i++){
       scanf("%d",&a[i]);
    }
    insertsort(a,n);
    printf("直接插入排序最终结果:\n");
    for(i=1;i<=n;i++){
       printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

当输入数据为逆序时,需要比较的次数和移动的次数最多,时间复杂度为o(n*n),但是趟数不会变化。

10
9 8 7 6 5 4 3 2 1 0
i为2时,排序结果:8 9 7 6 5 4 3 2 1 0
i为3时,排序结果:7 8 9 6 5 4 3 2 1 0
i为4时,排序结果:6 7 8 9 5 4 3 2 1 0
i为5时,排序结果:5 6 7 8 9 4 3 2 1 0
i为6时,排序结果:4 5 6 7 8 9 3 2 1 0
i为7时,排序结果:3 4 5 6 7 8 9 2 1 0
i为8时,排序结果:2 3 4 5 6 7 8 9 1 0
i为9时,排序结果:1 2 3 4 5 6 7 8 9 0
i为10时,排序结果:0 1 2 3 4 5 6 7 8 9
直接插入排序最终结果:
0 1 2 3 4 5 6 7 8 9

当数据为有序时,不需要移动元素,每次进行if语句便跳出(即每次只比较一次),时间复杂度为o(n),但是趟数不会变化,只与n有关。

10
0 1 2 3 4 5 6 7 8 9
i为2时,排序结果:0 1 2 3 4 5 6 7 8 9
i为3时,排序结果:0 1 2 3 4 5 6 7 8 9
i为4时,排序结果:0 1 2 3 4 5 6 7 8 9
i为5时,排序结果:0 1 2 3 4 5 6 7 8 9
i为6时,排序结果:0 1 2 3 4 5 6 7 8 9
i为7时,排序结果:0 1 2 3 4 5 6 7 8 9
i为8时,排序结果:0 1 2 3 4 5 6 7 8 9
i为9时,排序结果:0 1 2 3 4 5 6 7 8 9
i为10时,排序结果:0 1 2 3 4 5 6 7 8 9
直接插入排序最终结果:
0 1 2 3 4 5 6 7 8 9

平均时间复杂度为o(n*n)

2、插入排序-折半插入排序
特点:不需要和前一位元素进行比较,直接折半查找进行比较来寻找插入位置,没找到则该元素位置正确。(由此可见,该排序算法的比较次数与初始状态无关)。找到位置后,再统一移动。即比较与移动分离。该比较与直接插入排序比较的意义不同。
由于折半查找的特性,只能使用顺序存储。
该算法稳定。
#include<stdio.h>
using namespace std;
void insertsort(int a[],int n){
    int i,j;
    int sum=1;
    for(i=2;i<=n;i++){
       a[0]=a[i];
       int low=1,high=i-1;
       while(low<=high){
            int mid=(low+high)/2;
            if(a[mid]>a[0])
              high=mid-1;
            else
            low=mid+1;//保证了算法的稳定性
       }
       for(j=i-1;j>=low;j--){
          a[j+1]=a[j];
       }
       a[low]=a[0];
       printf("i为%d时,排序结果:",i);
       for(j=1;j<=n;j++){
          printf("%d ",a[j]);
       }
       printf("\n");            
    }
}
        
int main(){
    int n,a[100];
    scanf("%d",&n);
    int i;
    for(i=1;i<=n;i++){
       scanf("%d",&a[i]);
    }
    insertsort(a,n);
    printf("折半插入排序最终结果:\n");
    for(i=1;i<=n;i++){
       printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

  值得注意的是:

当我们输入为逆序时:

10
9 8 7 6 5 4 3 2 1 0
i为2时,排序结果:8 9 7 6 5 4 3 2 1 0
i为3时,排序结果:7 8 9 6 5 4 3 2 1 0
i为4时,排序结果:6 7 8 9 5 4 3 2 1 0
i为5时,排序结果:5 6 7 8 9 4 3 2 1 0
i为6时,排序结果:4 5 6 7 8 9 3 2 1 0
i为7时,排序结果:3 4 5 6 7 8 9 2 1 0
i为8时,排序结果:2 3 4 5 6 7 8 9 1 0
i为9时,排序结果:1 2 3 4 5 6 7 8 9 0
i为10时,排序结果:0 1 2 3 4 5 6 7 8 9
折半插入排序最终结果:
0 1 2 3 4 5 6 7 8 9

正序时:

10
0 1 2 3 4 5 6 7 8 9
i为2时,排序结果:0 1 2 3 4 5 6 7 8 9
i为3时,排序结果:0 1 2 3 4 5 6 7 8 9
i为4时,排序结果:0 1 2 3 4 5 6 7 8 9
i为5时,排序结果:0 1 2 3 4 5 6 7 8 9
i为6时,排序结果:0 1 2 3 4 5 6 7 8 9
i为7时,排序结果:0 1 2 3 4 5 6 7 8 9
i为8时,排序结果:0 1 2 3 4 5 6 7 8 9
i为9时,排序结果:0 1 2 3 4 5 6 7 8 9
i为10时,排序结果:0 1 2 3 4 5 6 7 8 9
折半插入排序最终结果:
0 1 2 3 4 5 6 7 8 9

可以看到比较次数与初始状态无关,但是!!!移动的次数与初始状态有关!!!,排序的趟数只与n有关。

折半插入排序时间复杂度为o(nlog2n+n*n)=o(n*n)

3、插入排序-希尔排序
1、为什么会有希尔排序?
因为直接插入排序仅在数据元素基本有序时才有优势,希尔排序应运而生,将待排序表变为基本有序,然后再全体使用直接插入排序。
2、如何将排序表变的基本有序?
进行分组,每一次执行外层for循环,将待排序元素分成不同组。值得注意的是,如果刚开始dk=n/2,则第一次每个组只有两个元素,当i不断++时,都是再对不同的组进行组内直接插入排序。但是,当dk再次/2,进入新的循环时,此时分的组变少,但是组内元素变多,当i依旧为dk+1开始时,不同的组交叉进行各自组内的直接插入排序。当外层for循环进行到最后一步时,dk=1,此时所有元素都是一个组,进行直接插入排序。
希尔排序要用到[j+dk]快速查找,所以只能用顺序存储,不能用链式存储。
该算法不稳定。
#include<stdio.h>
using namespace std;
void shellsort(int a[],int n){
    int dk,i,j;
    for(dk=n/2;dk>=1;dk=dk/2){
       for(i=dk+1;i<=n;i++){
          if(a[i]<a[i-dk]){
            a[0]=a[i];
            for(j=i-dk;j>=1&&a[0]<a[j];j=j-dk){//注意:此时a[0]不再是哨兵,所以要加上j>=1的判断
            //为什么a[0]不再是哨兵?因为j=j-dk,j可能不会正好等于0,使得a[0]==a[0]。直接插入排序是j--,所以如果一直比较移动,会到0
               a[j+dk]=a[j];
            }
          a[j+dk]=a[0];
          }
       }
       printf("dk为%d时,排序结果:",dk);
       for(j=1;j<=n;j++){
          printf("%d ",a[j]);
       }
       printf("\n");         
    }
}
int main(){
    int n,a[100];
    scanf("%d",&n);
    int i;
    for(i=1;i<=n;i++){
       scanf("%d",&a[i]);
    }
    shellsort(a,n);//shell为框架,壳的意思
    printf("希尔排序最终结果:\n");
    for(i=1;i<=n;i++){
       printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

当元素为逆序时:

10
9 8 7 6 5 4 3 2 1 0
dk为5时,排序结果:4 3 2 1 0 9 8 7 6 5
dk为2时,排序结果:0 1 2 3 4 5 6 7 8 9
dk为1时,排序结果:0 1 2 3 4 5 6 7 8 9
希尔排序最终结果:
0 1 2 3 4 5 6 7 8 9

当元素为正序时:

10
0 1 2 3 4 5 6 7 8 9
dk为5时,排序结果:0 1 2 3 4 5 6 7 8 9
dk为2时,排序结果:0 1 2 3 4 5 6 7 8 9
dk为1时,排序结果:0 1 2 3 4 5 6 7 8 9
希尔排序最终结果:
0 1 2 3 4 5 6 7 8 9
可见,希尔排序的趟数同样也只与n有关,只不过希尔排序是间接与n有关,直接与dk有关,
时间复杂度最好为o(n^1.3),最坏为o(n*n),即dk初始就为1,则退化成直接插入排序。
4、交换排序-冒泡排序
特点:从n开始往前,元素之间两两进行比较,即n与n-1,n-1与n-2...,每一趟冒泡的结果是使得最小元素放到最终位置,每次趟结束后,比较范围缩小1个。
冒泡排序可以使用顺序表或者链表。
该算法是稳定的。
每一趟产生的有序序列一定是最终的位置,这点与插入排序不同,插入排序没到最后一刻,可能还要部分元素全体移动。
#include <stdio.h>

void swap(int &a, int &b) {
   int temp;
   temp = a;
   a = b;
   b = temp;
}

void bubbleinsert(int a[], int n) {
   int i = 0, j;
   bool flag = false;
   for (i = 1; i <n; i++) {//趟数
       flag = false;
       for (j=n;j>=i;j--) {
           if (a[j] < a[j-1]) {
               swap(a[j], a[j-1]),
               flag = true;
           }
       }
       printf("趟数为%d时,排序结果:",i);//为什么最多只有n-1次,因为默认第一个元素是有序
       for(j=1;j<=n;j++){
          printf("%d ",a[j]);
       }
       printf("\n");
       if (flag == false) {
           return;
       }
   }
   return;
}

int main() {
   int a[10];
   int i;
   int n;
   scanf("%d",&n);
   for (i = 1; i <=n; i++) {
       scanf("%d", &a[i]);
   }
   bubbleinsert(a, n);
   printf("冒泡排序最终结果:\n");
   for (i = 1; i <=10; i++) {
       printf("%d ", a[i]);
   }
   return 0;
}

当待排序列逆序时:

10
9 8 7 6 5 4 3 2 1 0
趟数为1时,排序结果:0 9 8 7 6 5 4 3 2 1
趟数为2时,排序结果:0 1 9 8 7 6 5 4 3 2
趟数为3时,排序结果:0 1 2 9 8 7 6 5 4 3
趟数为4时,排序结果:0 1 2 3 9 8 7 6 5 4
趟数为5时,排序结果:0 1 2 3 4 9 8 7 6 5
趟数为6时,排序结果:0 1 2 3 4 5 9 8 7 6
趟数为7时,排序结果:0 1 2 3 4 5 6 9 8 7
趟数为8时,排序结果:0 1 2 3 4 5 6 7 9 8
趟数为9时,排序结果:0 1 2 3 4 5 6 7 8 9
冒泡排序最终结果:
0 1 2 3 4 5 6 7 8 9

此时为最坏情况,要排序n-1趟。第i趟要进行n-i趟比较,求和后,比较次数时间复杂度为o(n*n)。每次比较后移动次数为3次(没有错,只有符合if比较条件,才会进入swap,必然交换)(swap函数交换三次),所以比较时间复杂度为o(n*n)。
时间复杂度最坏为o(n*n)。
注意:!!!冒泡排序的趟数与初始状态有关!!!,当序列已经有序后,flag==false,便退出函数,结束排序。

当待排序列正序时:

10
0 1 2 3 4 5 6 7  8 9
趟数为1时,排序结果:0 1 2 3 4 5 6 7 8 9
冒泡排序最终结果:
0 1 2 3 4 5 6 7 8 9

正序时,趟数为1趟,比较次数为n-1,移动次数为0,所以时间复杂度为o(n)。
平均时间复杂度为o(n*n)。

5、交换排序-快速排序
特点:关键字"枢轴"。不断的从大到小进行递归(这点与归并排序的递归截然相反),每次将序列通过枢轴一分为二,大于枢轴的在右边,小于枢轴的在左边。王道书上的枢轴元素默认为该区间的左边第一个元素,通过不断其他元素与其不断比较交换(交换不同步,因为low与high不是同时移动)
注意:!!!如果确定该枢轴最终的位置在边界时,只会将当前序列分成一份,不会一分为二!!! 当递归到low==high时,子序列只有一个元素,则排序结束。 
不稳定。
是平均性能最优算法。
不产生有序子序列。
可以使用链式存储,但是最好使用顺序存储,因为要先前向后查找。
#include<bits/stdc++.h>
using namespace std;
    int n;
    int sum=1;
int partition(int a[],int low,int high){
    int p1=low;
    int p2=high;
    cout<<"a数组全体元素目前状态如下(本轮未开始):"<<endl;
    for(int i=1;i<=n;i++){
       cout<<a[i]<<" ";
    }
    cout<<endl;
    a[0]=a[low];//将low对应的元素设置为枢轴,先保存起来,从逻辑上将该元素删除
    while(low<high){//当low==high时,即确定枢轴所在的位置
    while(a[high]>=a[0]&&low<high)
      high--;
    //一直到找到了小于枢轴的元素
    a[low]=a[high];//目前hgih对应的下标元素逻辑上为空
    //此时开始从low开始寻找
    while(a[low]<=a[0]&&low<high)
      low++;
    a[high]=a[low];//将low对应的下标填充到high上,low逻辑上为空
    //两步不管是否执行,都将有一个位置逻辑上为空,用来放枢轴
    }
    a[high]=a[0];
    cout<<"low为:"<<p1<<" "<<"枢轴为:"<<a[0]<<" "<<"high为:"<<p2<<endl;
    cout<<"调用递归函数第"<<sum++<<"次后,结果如下:"<<endl;
    for(int i=p1;i<=p2;i++){
       cout<<a[i]<<" ";
    }
    cout<<endl<<endl;
    return high;

void quicksort(int a[],int low,int high){
    if(low<high){//如果low==high,则分治到只有一个元素,必然是有序的
      int pivotpos=partition(a,low,high);
      quicksort(a,low,pivotpos-1);
      quicksort(a,pivotpos+1,high);
    }
}
int main(){
    int a[20];
    cin>>n;
    for(int i=1;i<=n;i++){
       cin>>a[i];
    }
    quicksort(a,1,n);//将选定的low,为最左边
    for(int i=1;i<=n;i++){
       cout<<a[i]<<" ";
    }
    cout<<endl;
    return 0;
}
   
当待排序列为逆序时:

10
9 8 7 6 5 4 3 2 1 0
a数组全体元素目前状态如下(本轮未开始):
9 8 7 6 5 4 3 2 1 0
low为:1 枢轴为:9 high为:10
调用递归函数第1次后,结果如下:
0 8 7 6 5 4 3 2 1 9

a数组全体元素目前状态如下(本轮未开始):
0 8 7 6 5 4 3 2 1 9
low为:1 枢轴为:0 high为:9
调用递归函数第2次后,结果如下:
0 8 7 6 5 4 3 2 1

a数组全体元素目前状态如下(本轮未开始):
0 8 7 6 5 4 3 2 1 9
low为:2 枢轴为:8 high为:9
调用递归函数第3次后,结果如下:
1 7 6 5 4 3 2 8

a数组全体元素目前状态如下(本轮未开始):
0 1 7 6 5 4 3 2 8 9
low为:2 枢轴为:1 high为:8
调用递归函数第4次后,结果如下:
1 7 6 5 4 3 2

a数组全体元素目前状态如下(本轮未开始):
0 1 7 6 5 4 3 2 8 9
low为:3 枢轴为:7 high为:8
调用递归函数第5次后,结果如下:
2 6 5 4 3 7

a数组全体元素目前状态如下(本轮未开始):
0 1 2 6 5 4 3 7 8 9
low为:3 枢轴为:2 high为:7
调用递归函数第6次后,结果如下:
2 6 5 4 3

a数组全体元素目前状态如下(本轮未开始):
0 1 2 6 5 4 3 7 8 9
low为:4 枢轴为:6 high为:7
调用递归函数第7次后,结果如下:
3 5 4 6

a数组全体元素目前状态如下(本轮未开始):
0 1 2 3 5 4 6 7 8 9
low为:4 枢轴为:3 high为:6
调用递归函数第8次后,结果如下:
3 5 4

a数组全体元素目前状态如下(本轮未开始):
0 1 2 3 5 4 6 7 8 9
low为:5 枢轴为:5 high为:6
调用递归函数第9次后,结果如下:
4 5

0 1 2 3 4 5 6 7 8 9

可以见的,此时递归调用次数最多所占的空间也最多,其容量与递归调用的深度一致,因为需要递归工作栈来保存每一次递归的信息。而每次次递归申请的空间都是1,所以最坏空间为o(n)。
最好情况就是每次枢轴都确定在在靠近中间的位置,则可以看成一个完全二叉树,深度为o(log2n),所以空间复杂度最好为o(log2n)。

同理,如果每次枢轴最终确定的位置都在边界,则可以看成每个节点都只有一个孩子的二叉树,此时树的深度最大,时间复杂度也最高,为o(n*n)(将每次递归的时间复杂度看成o(n))->对应序列基本正序或逆序。
同理,时间复杂度最好为o(nlog2n)。
代码中low<=high只有和折半有关.
快速排序的一趟和一次递归不是一个概念。
再次递归时,已经确定的位置的枢轴不再参与,其位置已经绝对固定。

6、选择排序-简单选择排序
特点:每次将区间内最小的元素比较出来,每次比较结束,区间长度减一。
不稳定。
产生绝对有序子序列。


//简单选择排序
#include <stdio.h>

void swap(int &a, int &b) {
   int temp;
   temp = a;
   a = b;
   b = temp;
}

void selectsort(int a[],int n)
{
   int i,j,min;
   for(i=0;i<n-1;i++){
   min=i;
   for(j=i;j<n;j++){
   if(a[j]<a[min])
     min=j;
   }
   if(min!=i)
   swap(a[i],a[min]);
   }
}     
   
int main() {
   int a[10];
   int i;
   for (i = 0; i < 10; i++) {
       scanf("%d", &a[i]);
   }
   selectsort(a, 10);
   for (i = 0; i < 10; i++) {
       printf("%d ", a[i]);
   }
   return 0;
}
逆序时:
10 9 8 7 6 5 4 3 2 1
趟数为1时,排序结果:1 9 8 7 6 5 4 3 2 10
趟数为2时,排序结果:1 2 8 7 6 5 4 3 9 10
趟数为3时,排序结果:1 2 3 7 6 5 4 8 9 10
趟数为4时,排序结果:1 2 3 4 6 5 7 8 9 10
趟数为5时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为6时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为7时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为8时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为9时,排序结果:1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
正序时:
1 2 3 4 5 6 7 8 9 10
趟数为1时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为2时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为3时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为4时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为5时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为6时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为7时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为8时,排序结果:1 2 3 4 5 6 7 8 9 10
趟数为9时,排序结果:1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10

时间复杂度:移动次数不会超过3(n-1)次,但是比较次数不会变化与初始状态无关,为n(n-1)/2次,所以时间复杂度为o(n*n),不存在最好最坏时间复杂度。

7、选择排序-堆排序
特点:大根堆,孩子结点都小于等于双亲节点。大根堆:孩子结点都大于等于双亲节点。
当初始化调整堆时,是从最后一个分支节点往前逐个执行headadjust直到根节点,进行调整。
当从堆顶取出元素后,将数组当前区间(每调整完一次,就要和数组尾部进行交换,同时,数组区间减一)最后一个元素和他交换后,是从根节点执行一次headadjust进行调整。
当在数组尾部加入元素后,是从该尾部向前(即对堆进行向上调整)。
三个不同的操作分别对应堆的不同位置。
稳定。

#include <stdio.h>

void swap(int &a, int &b) {
   int temp;
   temp = a;
   a = b;
   b = temp;
}

void headadjust(int a[], int k, int n) {
    a[0] = a[k];
    int i;
    for(i = 2 * k; i <= n; i = i * 2) {
        if(i < n && a[i] < a[i + 1]) {
            i++;
        }
        if(a[0] > a[i]) {
            break;
        } else {
            swap(a[k], a[i]);
            k = i;
        }
    }
    a[k] = a[0];
    int j;
    printf("对%d进行调整后的结果:",a[0]);//为什么最多只有n-1次,因为默认第一个元素是有序
    for(j=1;j<=n;j++){
       printf("%d ",a[j]);
    }
    printf("\n");
}

void buildmaxheap(int a[], int n) {
    int i;
    for(i = n/2; i >= 1; i--) {
        headadjust(a, i, n);
    }
}

void heapsort(int a[], int n) {
    buildmaxheap(a, n);
    int i;
    for(i = n; i >= 1; i--) {
        swap(a[1], a[i]);
        headadjust(a, 1, i - 1);
    }
}

int main() {
    int a[100];
    int i;
    int n;
    scanf("%d", &n);
    for (i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    heapsort(a, n);
    printf("堆排序结果如下:\n");
    for (i = 1; i <= n; i++) {
        printf("%d ", a[i]);
    }
    return 0;
}


10
9 8 7 6 5 4 3 2 1 0
对5进行调整后的结果:9 8 7 6 5 4 3 2 1 0
对6进行调整后的结果:9 8 7 6 5 4 3 2 1 0
对7进行调整后的结果:9 8 7 6 5 4 3 2 1 0
对8进行调整后的结果:9 8 7 6 5 4 3 2 1 0
对9进行调整后的结果:9 8 7 6 5 4 3 2 1 0
注意:!!!前几次的调整输出的只是对应该元素所做的全部交换变化后的最终结果,不是序列对应的各个变化!!!
对0进行调整后的结果:8 6 7 2 5 4 3 0 1
对1进行调整后的结果:7 6 4 2 5 1 3 0
对0进行调整后的结果:6 5 4 2 0 1 3
对3进行调整后的结果:5 3 4 2 0 1
对1进行调整后的结果:4 3 1 2 0
对0进行调整后的结果:3 2 1 0
对0进行调整后的结果:2 0 1
对1进行调整后的结果:1 0
对0进行调整后的结果:0
对0进行调整后的结果:
堆排序结果如下:
0 1 2 3 4 5 6 7 8 9

建初始堆的时间复杂度为o(n)。
调整堆的时间复杂度为o(log2n)。
堆排序的时间复杂度为o(nlog2n)。

8、归并排序
特点:刚开始讲一个一个元素视为n个有序表,两两比较合并。然后继续两两合并,直至合并成一个表。注意:!!!当n为为奇数数,手算合并与代码一致,当n为偶数时,代码与手算不一致,以手算为准!!!

//归并排序
#include<bits/stdc++.h>
using namespace std;
int n;
int *b=(int *)malloc((n+1)*sizeof(int));//为什么要设置b数组,如果a左边一直没有被取到
//但是k一直++,原有的值就会被覆盖
void merge(int a[],int low,int mid,int high){
   int i;
   for(i=low;i<=high;i++){
      b[i]=a[i];
    }
   int j,k;
   for(i=low,j=mid+1,k=low;i<=mid&&j<=high;k++){//不管a[i]与a[j]如何比较,总是要将值赋给a[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++];
   for(i=low;i<=high;i++)
      printf("%d ",a[i]);
   printf("\n");
}
   
void mergesort(int a[],int low,int high){
   if(low<high){
     int mid=(low+high)/2;//不是n/2
     mergesort(a,low,mid);
     mergesort(a,mid+1,high);
     //刚开始,左右子序列只有最左边的两个,每次归并后依次往回退,左右有序子序列逐渐变大
     merge(a,low,mid,high);
    }
   }
int main(){
   int a[11];
   scanf("%d",&n);
   int i;
   for(i=1;i<=n;i++){
      scanf("%d",&a[i]);
   }
   mergesort(a,1,n);//传递low与high
   for(i=1;i<=n;i++){
      printf("%d ",a[i]);
   }
   return 0;
}
   
由代码可知,递归过程与快速排序相反。
空间复杂度:因为要申请b数组,所以空间复杂度为o(n)。
时间复杂度:!与初始状态无关!每一趟归并的时间复杂度为o(n),需要o(log2n)(向上取整)
趟,所以时间复杂度为o(nlog2n)。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别出现在黎明的梦里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值