排序1(数据结构)

1.1排序的基本概念和方法概述

1.1.1排序的基本概念

定义:是按关键字的非递减或非递增顺序对一组记录重新进行排列的操作。

1.1.2稳定性

当排序中存在两个或两个以上关键字相等时,若排序后的序列中R1仍领先于R2,则所用的排序的方法是稳定的,反之则是不稳定的。

1.1.3内部排序和外部排序

内部排序:是指排序记录数据全部存放在计算机内存中进行排序的过程。

外部排序:是指待排序记录的数量很大,以至于内存一次不能容纳全部记录,在排序过程中尚需对外存进行访问的排序过程。

1.2内部排序方法的分类

插入类,交换类,选择类,归并类,分配类。

1.3待排序记录的储存方式

1)顺序表:记录的次序关系由储存位置决定,实现排序需要移动记录。

2)链表:记录的次序关系由储指针指示,实现排序仅需修改指针。

以顺序表储存为例,待排序的数据类型为:

#define MAXSIZE 1000//顺序表的最大长度
typedef int KeyType;//关键字为整形

typedef struct{
KeyType key;//关键字
InfoType otherinfo;//其他数据项
}RedTye;

typedef struct{
RedType r[MAXSIZE+1];//r[0]闲置或者做哨兵单元
int length;//顺序表长度
}SqList;//顺序表类型

2.插入排序

三种方法:直接插入排序,折半插入排序和希尔排序。

2.1直接插入排序

直接插入排序是一种最简单的排序方法。

void insertList(Sqlist &L)//直接插入法
{
    if(L.r[i]<L.r[i-1])
    {
    for(i=2;i<=L.length;i++)
    {
        L.r[0]=L.r[i];//复制监视哨
        for(j=i-1;L.r[0]<L.r[j];j--)//从后往前
        {
            L.r[j+1]=L.r[j];
        }
        L.r[j+1]=L.r[0];//注意是j+1
    }
    }



}

时间复杂度为O(n*n)

空间复杂度为O(1)

特点:稳定排序,方法简单容易实现,也适用于链式存储结构。

但时间复杂度高,当n较大时不适宜使用。

2.2折半插入排序

就是查找操作时用折半查找来实现。

void BinsertSot(Sqlist &L)//折半插入排序,这个就是先把折半查找算法写出来,就是找插入的位置,然后再写后移的算法,一定要列举列子
{
    int i,low,j,m,high;
    for(i=2;i<L.length;i++)//跟直接插入排序相似
    {
        L.r[0]=L.r[i];
        low=1;
        high=i-1;
        while(low<=high)//折半查找找到位置插入,注意这里等号能不能取
        {
           m=(low+high)/2;
           if(L.r[0]<L.r[m])
           {
               high=m-1;//从其前面一个开始查找,不能从m位置开始
           }
           else{
            low=m+1;//从后一位开始
           }
        }
        for(j=i-1;j>=high+1;j--)//不一定用high,也可以用low或者m
        {
            L.r[j+1]=L.r[j];//找个简单的例子试试,容易出错
        }
        L.r[high+1]=L.r[0];
    }
}

时间复杂度也是O(n*n)但是就平均性能来说,折半查找要优于直接插入排序

空间复杂度为O(1)。

算法特点:稳定排序,适合初始记录无序、n较大的情况;不能用于链式存储。

2.3希尔排序

希尔排序又称缩小增量排序。

基本思想:从减少记录个数和序列基本有序两个方面对直接插入排序进行改进。(分别对每个子序列进行插入排序)

就是将n个记录分成d个子序列,其中d为增量,增量是从大到小是我一组值,增量序列中的值没有除1以外的公因子,而且最后一个增量一定为1。

void ShellInsert(Sqlist &L,int k)//希尔排序,就是将直接排序中的减一换成减k
{
    for(i=k+1;i<=L.length;i++)//注意不能从1开始,而是从K+1开始
    {
        if(L.r[i]<L.r[i-k])
        {
            L.r[0]=L.r[i];
            for(j=i-k;j>0 && L.r[j]<L.r[0];j=j-k)
            {
                L.r[j+k]=L.r[j]
            }
            L.r[j+k]=L.r[0];
        }
    }
    
}
void ShellSort(SqList &L,int dt[],int t)
{
    int k;
    for(k=0;k<t;k++)//希尔排序需要很多次排序,按照数组中的增量来排序
    {
        ShellInsert(L,dt[k]);
    }
}

需要对顺序表L进行t趟希尔插入排序。

空间复杂度为O(1)

算法特点:排序算法不稳定,不能用于链式存储,增量序列中没有除1之外的公因子,而且最后一个增量值必须等于1,其中n越大越明显。

这三个排序都是将插入的数据放入到监视哨中。

3.交换排序

3.1冒泡排序

冒泡排序是一种简单的交换排序方法,通过两两比较相邻记录的关键字来进行排序。

//冒泡排序
void BubbleSort(SqList &L)//这个是两两交换,先确定最后一个,所以先写一次交换的,再写嵌套循环
{
    int a,change;
    change=1;
    for(j=1;j<L.length && change=1;j++)//change是用来判断循环是否结束的
    {
        change=0;

    for(i=1;i<L.length-j+1;i++)//注意r0的位置是被闲置的,这个是相邻的依次做比较,与交换法区分开
    {
        if(L.r[i]>L.r[i+1])
        {
            a=L.r[i+1];
            L.r[i+1]=L.r[i];
            L.r[i]=a;
            change=1;
        }
    }
    }
}
//交换法
void SwapSort(SqList &L)//这个是先排第一个,与冒泡法类似,但是有差别
{
    int i,j;
    for(i=1;i<L.length;i++)
    {
        for(j=i+1;j<L.length;j++)
        {
            if(L.r[i]>L.r[j])
            {
                int a;
                a=L.r[j];
                L.r[j]=L.r[i];
                L.r[i]=a;
            }
        }
    }
}

在平均的情况下,时间复杂度为O(n的平方)。

空间复杂度为O(1)。

算法特点:是一种稳定排序,也可用于链式存储结构,当n较大时此算法不宜采用。

3.2快速排序

快速排序是由冒泡排序改进而得的。

快速排序的目标:找一个记录,以他的关键字作为枢纽,凡是关键字小于枢纽的记录均移动到该记录之前,反之,凡是关键字大于枢纽的记录均移动到该记录之后,在一趟快速排序之后将无序序列分成两部分,利用递归,重复n次,最后只剩一个数,可完成排序。

//快速排序
int Partition(SqList &L,int low,int high)//这个不太好想
{
    L.r[0]=L.r[low];//low一般就是1
    int a;
    a=L.r[low];//low作为中枢,来分割
    while(low<high)
    {

    while(L.r[high]>=a &&low<high)
    {
        high=high-1;
    }
    L.r[low]=L.r[high];
    while(L.r[low]<=a && low<high)
    {
        low=low+1;
    }
    L.r[high]=L.r[low];
    }
    L.r[low]=L.r[0];
}
void QSort(SqList &L,int low,int high)//low一般就是初值1
{
    int pivotloc;
    if(low<high)
    {
        pivotloc=Partition(L,low,high);//寻找枢纽位置,方便递归的使用
        QSort(L,low,pivotloc-1);//这里的low跟调用函数中的low不同,对左子表进行排序
        QSort(L,pivotloc+1,high);//对右子表进行排序
    }
}
void QuickSort(SqList &L)
{
    QSort(L,1,L.length);
}

平均情况下,快速排序的时间复杂度为O(n*logn)

快速排序下,最好的空间复杂度为O(logn),最坏的情况下为O(n)

算法特点:是不稳定的排序方法,需要确定上下界,很难适用于链式存储中,当n较大时,在平均情况下,快速排序是所有内部排序中速度最快的一种,所以适合于初始记录无序、n较大的情况,反而不适用于已经排好的数据中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值