数据结构【第十七天】:排序(基本概念和简单排序算法)

基本概念

假设含有n个记录的序列为{r1,r2,...,rn},其相应的关键字分别为{k1,k2,...,kn},需确定1,2,3...,n的一种排列p1,p2,...,pn,使其相应的关键字满足kp1<=kp2<=...<=kpn非递减(非递增)关系,即使得序列成为一个按关键字有序得序列{rp1,rp2,...,rpn},这样的操作称为排序。

排序得依据是关键字之间的大小关系,这个关键字可以是主关键字也可以是次关键字,同时多个关键字得排序最终都可以转换为单个关键字得排序。

排序得稳定性:假设ki=kj(1<=i<=n,1<=j<=n,i不等于j),且在排序前的序列中ri领先于rj(即i

 

内排序:在排序整个过程中,待排序的所有记录全部被放置在内存中。

外排序:由于排序的记录个数太多,不能全部放在内存中,需要内外存之间多次交换数据才行。

内排序的性能影响因素:

1.时间性能

2.辅助空间

3.算法的复杂性

内排序分为:插入排序、交换排序、选择排序、归并排序

以下讲解7中排序算法:
简单算法:冒泡排序 简单选择排序 直接插入排序

改进算法:希尔排序 堆排序 归并排序 快速排序 

排序常用结构和函数

#define MAXSIZE 10    //用于排序的数组个数最大值
typedef struct
{
    int r[MAXSIZE+1];    //用于存储要排序数组 r[0]用作哨兵或者临时变量
    int length;    //用于记录顺序表的长度
}


//交换L中的数组r的下标为i和j的值
void swap(SqList *L,int i,int j)
{
    int temp = L -> r[i];
    L->r[i] = L->[j];
    L->r[j] = temp;
}

冒泡排序

基本思想:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止

 

//对顺序表L做交换排序 普通方法
void BubbleSort0(SqList *L)
{
    int i,j;
    for(i=1;ilength;i++)
    {
        for(j=i+1;j<=L->length;j++)
        {
            if(L->r[i]>L->r[j])
            {
                swap(L,i,j);    //交换下标i与j的值
            }
        }
    }
}

//改进1
//在交换过程中不仅将最小的数字排到了第一,还将其余的较小数字排到了前面
void BubbleSort(SqList *L)
{
    int i,j;
    for(i=1;ilength;i++)
    {
        for(j=L->length-1;j>=i;j--)    //j为从后向前循环
        {
            if(L->r[j]>L->r[i])
            {
                swap(L,i,j);    //交换下标i与j的值
            }
        }
    }
}

//改进2
//
void BubbleSort2(SqList *L)
{
    int i,j;
    Status flag = True;    //用于标记是否发生交换
    for(i=1; ilength && flag; i++)    //flag为false时将退出循环
    {
        flag = FALSE;        //初始化为假
        for(j=L->length-1;j>=i;j--)    //j为从后向前循环
        {
            if(L->r[j]>L->r[i])
            {
                swap(L,i,j);    //交换下标i与j的值
                flag = True;    //有数据交换,设标记为真
            }
        }
    }
}

冒泡排序的时间复杂度为O(n^2)

简单选择排序算法

基本思想:通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第 i (1 <= i <= n)个记录交换之。

//简单选择排序算法

void SelectSort(SqList *L)
{
    int i,j,min;
    for(i=1;ilength;i++)
    {
        min = i;                      //当前下标定义为最小值下标
        for(j=i+1;jlength;j++)    //循环之后的数据
        {
            if(L->r[min]>L->r[j])    //如果有小于当前最小值的关键字
                min = j;              //将此关键字的下标给min
        }
        if(i != min)        //若min不等于i, 则说明找到最小值 ,交换
            swap(L,i,min);    
    }
}

时间复杂度为O(n^2),但是性能略优于冒泡排序

直接插入排序

基本思想:将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增 1 的有序表。

//直接插入排序算法
void InsertSort(SqList *L)
{
    int i,j;
    for(i=2;ilength;i++)
    {
        if(L->r[i]r[i-1])    //需要插入有序表
        {
            L->r[0] = L->r[i];    //设置哨兵,保存待插入值
            for(j=i-1;L->r[j]>L->r[0];j--)
                L->r[j+1] = L->r[j];    //大于插入值的记录后移
            L->r[j+1] = L->r[0];        //插入到正确位置
        }
    }
}

如果排序记录为随机的,其平均的比较和移动次数约为(n^2)/4,时间复杂度仍为O(n^2),其性能比冒泡和简单选择排序好一点

你可能感兴趣的:(数据结构)