数据结构——排序(Part2:直接插入排序和希尔排序)

(图源:大话数据结构)

好文分享:排序算法解析:https://blog.csdn.net/kexuanxiu1163/article/details/103051357 

目录

0准备工作

1直接插入排序

2希尔排序


0准备工作

保存排序内容的自定义结构体,其中顺序表的长度,不算哨兵(下标为零的部分)

#define MAX 10
typedef struct SqlistData
{
    int r[MAX+1];//把r[0]空出来当哨兵或者临时变量
    int length;//记录长度,因为0被空出来了,所以长度和下标此时统一了

}SqList;

交换接口

void swap(SqList * L,int i,int j)//交换
{
    int temp = L->r[i];
    L->r[i] = L->r[j];
    L->r[j] = temp;
}

打印接口

void print(SqList * L)
{
    qDebug()<<"开始打印";
    for(int i = 1;i<=L->length;++i)
    {
        qDebug()<<L->r[i];
    }
}

顺序表的储存结构如下:

                           

零位下标什么也不储存,所以无论是遍历还是排序,都是从下标1开始,顺序表长度为5,小标和顺序表中的元素序号完全一致。

1直接插入排序

进行排序的顺序表

    SqList Data = {{0,9,1,5,8,3,7,4,6,2},9};

 排序代码:

void InsertSort(SqList * L)
{
    int i,j;
    for(i = 2;i<=L->length;++i)
    {
        if(L->r[i]<L->r[i-1])//后面的小,需要插入,后面的要是大了就可以不管了
        {
            L->r[0] = L->r[i];//0位被当成了哨兵处理,暂时存放要交换的数据,相当于temp
            for(j = i-1;L->r[j]>L->r[0];--j)//因为L->r[j]不断往前,迟早会碰见0,也就是L->r[j]==L->r[0],自然跳出
            {
                L->r[j+1] = L->r[j];//要插入的元素是[0],有序数列的末尾是j(i-1),比[0]大了,就换,之后继续和[0]比较
            }
            L->r[j+1] = L->r[0];//最后把[0]放入队列中即可
            //放外面少移动,减少操作
        }

    }

}

代码讲解:

插入排序将整个顺序表看成两个部分,有序数列等待插入部分

 一般默认将第一个元素看成是“有序数列”

后面其他的都是“等待插入部分”

                                    

如图所示,5为有序部分,其他为等待插入部分

外循环从小标2开始进行循环

“等待插入部分”的首元素,和有序部分的末尾元素进行比较,如果大,则自动成为新的末尾

如果小于,则往前放,知道新插入的元素找到合适的位置。

                               

                       

最终完成循环,跳出后,j依旧会发生一次减一,所以最终的程序是要给下标为j+1的元素进行重新赋值。

之后我们再看一次整个过程,验证一下后程序:

                            

                           

            

具体操作:

    print(&Data);
    InsertSort(&Data);
    qDebug()<<"简单的插入排序后";
    print(&Data);

 

外循环主要是处理无序元素的遍历

内循环主要是比较要插入元素在有序队列中的位置

                      

2希尔排序

                            

希尔排序的思路非常类似于插入排序,但是又很有跳跃性

void ShellSort(SqList * L)
{
    int i,j;
    int increment = L->length;
    do
    {
        increment = increment/3+1;
        for(i = increment+1;i<=L->length;++i)
        {
            if(L->r[i]<L->r[i-increment])
            {
                L->r[0] = L->r[i];
                for(j=i-increment;j>0&&L->r[0]<L->r[j];j-=increment)
                    L->r[j+increment] = L->r[j];
                L->r[j+increment] = L->r[0];
            }
        }
    }while(increment>1);

}

从程序的大致结构上也可以看出,和插入排序接近,但是加入了增量increment,所以整个过程也变得繁琐,

可以将上述的increment理解成插入排序中的两个元素之间的间距,插入排序是1,此处是increment 

下面是两种解释方法: 

                  

                      

                    

               

                    

                  

(以上图源:) 

以下动画演示源自:

动画图解:十大经典排序算法动画与解析,看我就够了!(配代码完全版):

https://blog.csdn.net/kexuanxiu1163/article/details/103051357

十大经典排序算法动画与解析,看我就够了!(配代码完全版)

              

                   

发布了85 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41605114/article/details/104822183