2020-10-19 排序

排序

一、插入排序

  1. 直接插入排序
    算法步骤:
    在这里插入图片描述

时间复杂度O(n2),空间复杂度O(1)。
特点:
1.稳定排序
2.算法简便,容易实现
3.也适用于链式存储结构,只是在单链表上无需移动记录,只需修改相应的指针
4.更适合于初始记录基本有序的情况,当初始记录无序,n较大时,此算法时间复杂度较高,不宜采用

直接插入排序代码如下:

#include<bits/stdc++.h>
using namespace std;
#define MAXNUMS 999999

int main()
{
    int n = 8;
    int a[n] = {49,38,65,97,76,13,27,49};
    for(int i=1;i<n;i++)
    {
        if(a[i]<a[i-1])
        {
            int t = a[i];
            a[i] = a[i-1];
            int j;
            for(j = i - 1 ; t<a[j] && j>=0 ; j--)
            {
                a[j+1] = a[j];
            }
            a[j+1] = t;
        }
    }
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
}

在这里插入图片描述

  1. 折半插入排序
    思想:直接插入排序+折半查找
    时间复杂度:O(n2),空间复杂度O(1)。
    特点:
    1.稳定排序
    2.因为要进行折半查找,只能用于顺序结构,不能用于链式结构
    3.适合初始记录无序、n较大时的情况。
#include<bits/stdc++.h>
using namespace std;
#define MAXNUMS 999999

int main()
{
    int n = 8;
    int a[n] = {49,38,65,97,76,13,27,49};
    for(int i=1;i<n;i++)
    {
        int t = a[i];
        int low = 0,high = i - 1;
        while(low<=high)
        {
            int mid = (low+high)/2;
            if(a[mid]>t)
            {
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
            }
        }
        for(int j = i - 1;j>=high+1;j--)
        {
            a[j+1] = a[j];
        }
        a[high+1] = t;
    }
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
}

在这里插入图片描述
3. 希尔排序(缩小增量排序)
思想:实际上采用分组插入的方法,将整个序列分割成几组,从而减少参与直接插入排序的数据量,对每组分别进行直接插入序列,然后增加每组的数据量,重新分组。这样当经过几次分组排序后,整个序列中的记录“基本有序”时,在对全体记录进行一次直接插入排序。
时间复杂度O(n1.3) 或 O(n2),空间复杂度O(1)。
特点:
1.记录跳跃式地移动导致排序方法是不稳定的
2.只能用于顺序结构,不能用于链式结构
3.增量序列可以有各种取法,但应该使增量序列中的值没有除1之外的公因子,并且最后一个增量值必须等于1
4.记录总的比较次数和移动次数都比直接插入序列要少,n越大时,效果越明显。所以适合初始记录无序、n较大时的情况

#include<bits/stdc++.h>
using namespace std;
#define MAXNUMS 999999

int main()
{
    int n = 10;
    int a[n] = {49,38,65,97,76,13,27,49,55,04};
    int len_d = 3;
    int dt[len_d] = {5,3,1};
    printf("初始序列:");
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    for(int k=0;k<len_d;k++)
    {
        for(int i = dt[k];i<n;i++)
        {
            if(a[i]<a[i-dt[k]])
            {
                int t = a[i];
                int j;
                for(j = i - dt[k];j>=0 &&t<a[j];j = j -dt[k])
                {
                    a[j+dt[k]] = a[j];
                }
                a[j+dt[k]] = t;
            }
        }
        printf("第%d趟排序结果:",k+1);
        for(int z=0;z<n;z++)
        {
            printf("%d ",a[z]);
        }
        printf("\n");
    }
}

程序运行结果如下:
在这里插入图片描述

二、交换排序

  1. 冒泡排序
    时间复杂度:O(n2),空间复杂度O(1)。
    特点:
    1.稳定排序
    2.可用于链式存储结构
    3.移动记录次数较多,算法平均时间性能比直接插入排序差
#include<bits/stdc++.h>
using namespace std;
#define MAXNUMS 999999

int main()
{
    int n = 10;
    int a[n] = {49,38,65,97,76,13,27,49,55,04};
    printf("初始序列:");
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    ///冒泡排序
    for(int i=0;i<n-1;i++)
    {
        for(int j=i+1;j<n;j++)
        {
            if(a[i]>a[j])
            {
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
            }
        }
        printf("第%d趟排序结果:",i+1);
        for(int j=0;j<n;j++)
        {
            printf("%d ",a[j]);
        }
        printf("\n");
    }
}

在这里插入图片描述
2. 快速排序
思路:
Partition函数:
两个指针low指向最左边,high指向最右边,设置变量t存储最左边的值。
进行循环while(low<high):

while(low<high && a[high]>=t):
	指针high向左移一位
指针low指向的值更改为指针high指向的值(此时a[high]<t)
while(low<high && a[low]<=t):
	指针low向右移一位
指针high指向的值更改为指针low指向的值(此时a[low]>t)

循环结束,将指针low指向的值更改为t,函数运行结束,返回low。
时间复杂度:O(nlog2n),空间复杂度O(log2n)~o(n)。
特点:
1.记录非顺次的移动导致排序方法是不稳定的
2.排序过程中需要定位表的下界和上界,所以适合用于顺序结构,很难用于链式结构
3.当n较大时,在平均情况下快速排序是所有内部排序方法中速度最快的一种,所以其适合初始记录无序、n较大的情况

#include<bits/stdc++.h>
using namespace std;
#define MAXNUMS 999999


int Partition(int *a,int low,int high)
{
    int t = a[low];
    while(low<high)
    {
        while(low<high && a[high]>=t)
        {
            high--;
        }
        a[low] = a[high];
        while(low<high && a[low]<=t)
        {
            low++;
        }
        a[high] = a[low];
    }
    a[low] = t;
    return low;
}

void Mysort(int *a,int low,int high)
{
    if(low<high)
    {
        int tmp = Partition(a,low,high);
        Mysort(a,low,tmp-1);
        Mysort(a,tmp+1,high);
    }
}

int main()
{
    int n = 10;
    int a[n] = {49,38,65,97,76,13,27,49,55,04};
    int *p = a;
    printf("初始序列:");
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    Mysort(a,0,n);
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
}

在这里插入图片描述

三、选择排序

  1. 简单选择排序(直接选择排序)
    时间复杂度O(n2),空间复杂度O(1)。
    特点:
    1.稳定的排序方法
    2.可用于链式存储结构
    3.移动记录次数较少,当每一记录占用的空间较多时,此方法比直接插入排序快
#include<bits/stdc++.h>
using namespace std;
#define MAXNUMS 999999

int main()
{
    int n = 10;
    int a[n] = {49,38,65,97,76,13,27,49,55,04};
    int *p = a;
    printf("初始序列:");
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    for(int i=0;i<n;i++)
    {
        int k = i;
        for(int j = i + 1;j<n;j++)
        {
            if(a[j]<a[k])
            {
                k = j;
            }
        }
        if(k!=i)
        {
            int t = a[i];
            a[i] = a[k];
            a[k] = t;
        }
    }
    for(int i=0;i<n;i++)
    {
        printf("%d ",a[i]);
    }
}


  1. 树形选择排序(锦标赛排序)
    ①左右兄弟结点进行比较,选出最小的作为自己的双亲结点,最后输出根结点。
    ②输出根结点后,将叶子结点中最小关键字(即根结点对应的叶子结点)修改为最大值。
    ③重复执行①和②,当根结点为最大值时结束。
  2. 堆排序
    在这里插入图片描述
    大根堆a[n]>=a[2n]且a[n]>=a[2n+1];
    小根堆a[n]<=a[2n]且a[n]<=a[2n+1]。
    时间复杂度O(nlog2n),空间复杂度O(1)。
    特点:
    1.是不稳定排序
    2.只能用于顺序结构,不能用于链式结构
    3.初始建堆所需的比较次数较多,因此记录数较少时不宜采用。
#include<bits/stdc++.h>
using namespace std;
#define MAXNUMS 999999

void HeapMinAdjust(int *a,int s,int m)
{
    int t = a[s];
    for(int i=2*s;i<=m;i=i*2)
    {
        if(i<m && a[i]>a[i+1]) i++;
        if(t <= a[i]) break;
        a[s] = a[i];
        s = i;
    }
    a[s] = t;
}

void CreateMinHeap(int *a,int n)
{
    for(int i=n/2;i>0;i--)
    {
        HeapMinAdjust(a,i,n-1);
    }
}

void HeapMinSort(int *a,int n)
{
    CreateMinHeap(a,n);
    printf("最小堆:");
    for(int i=1;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");

    for(int i=n;i>1;i--)
    {
        int t = a[1];
        a[1] = a[i];
        a[i] = t;
        HeapMinAdjust(a,1,i-1);
    }
}

void HeapMaxAdjust(int *a,int s,int m)
{
    int t = a[s];
    for(int i=2*s;i<=m;i=i*2)
    {
        if(i<m && a[i]<a[i+1]) i++;
        if(t >= a[i]) break;
        a[s] = a[i];
        s = i;
    }
    a[s] = t;
}

void CreateMaxHeap(int *a,int n)
{
    for(int i=n/2;i>0;i--)
    {
        HeapMaxAdjust(a,i,n-1);
    }
}

void HeapMaxSort(int *a,int n)
{
    CreateMaxHeap(a,n);
    printf("最大堆:");
    for(int i=1;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");

    for(int i=n;i>1;i--)
    {
        int t = a[1];
        a[1] = a[i];
        a[i] = t;
        HeapMaxAdjust(a,1,i-1);
    }
}

int main()
{
    int n = 11;
    int a[n] = {0,49,38,65,97,76,13,27,49,55,04};
    printf("初始序列:");
    for(int i=1;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");

    HeapMaxSort(a,n-1);

    printf("堆排序结果:");
    for(int i=1;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");

    HeapMinSort(a,n-1);
    printf("堆排序结果:");
    for(int i=1;i<n;i++)
    {
        printf("%d ",a[i]);
    }
    printf("\n");

}

在这里插入图片描述

四、归并排序

1. 2-路归并排序

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值