• 数据结构:从插入排序到希尔排序


    数据结构:从插入排序到希尔排序

    插入排序

    算法思路

        每次从无序表中取出第一个元素,将其插入到有序表中的适当位置,使有序表的长度不断加长,完成排序过程。
      n个待排序的元素由一个有序表和一个无序表组成,开始时有序表中只包含一个元素。

    流程演示

        
        蓝色表示由有序表,黑色表示无序表!

      分析

        元素基本有序时,直接插入排序的时间复杂度接近于O(n)
          元素数目n较少时,直接插入排序的效率较高

    数据结构定义

      首先我们要构建一个顺序表来存放待排序的元素!这是我排序的基础,我的所有的排序算法都会依赖于这个简单的顺序表!

    typedef  int  KeyType;              // 定义关键字类型为整型
    typedef  int  InfoType;
    
    typedef struct  {
        KeyType    key;                  // 关键字项
        InfoType  otherinfo;          // 其他数据项
    }RedType;                               // 记录类型
    
    typedef struct {
        RedType r[MAXSIZE+1];    // r[0]闲置或用作哨兵
        int length;                            // 顺序表长度
    }SqList;

      编写了两个方法可以对顺序表进行初始化和遍历

    void initSqList(SqList & S)
    {
        int t,count=0;
        while(scanf("%d",&t)!=0)
        {
            count++;
            S.r[count].key=t;
        }
        S.length=count;
    }
    
    void traverseSqList(SqList S)
    {
        for(int i=1;i<=S.length;i++)
            printf("%d",S.r[i].key);
    }

    优化的直接插入排序

    我们在这里采用了优化,我们进行的是元素的移动和覆盖,而不仅仅是简单的交换。

    void sortByDirectlyInsert(SqList &L)
    {
        for(int i = 2; i <= L.length; i++)      //第一个元素默认有序,所以直接从2开始
            if (L.r[i].key < L.r[i-1].key) {    //这里进行了优化,如果i >i-1,说明从1~i这一段都是有序的,我们不需要进行后续操作
                L.r[0] = L.r[i];    
                L.r[i] = L.r[i-1];
                int j;
                for(j = i - 2;L.r[0].key < L.r[j].key; j--)
                    L.r[j+1] = L.r[j];
                L.r[j+1] = L.r[0];
            }//if
    }

    思路举例:
      [ ]5 9 6 3 8 //待排序元素
      [ ]5 9 //到这里是有序的
      [ ]5 9 6 //到这里发现6小于9
        [6 ]5 9 空 //将6移到监视哨,把它的位置空出来
        [6 ]5 空 9 //让9来到原来6的位置,把9的位置空出来,看看6能不能填在那里
        [6 ]5 6 9 //6可以填在那里,让空的位置等于监视哨
      []5 6 9 3
        [3 ]5 6 9 空
        [3 ]5 6 空 9
        [3 ]5 空 6 9
        [3 ]空 5 6 9
        [3 ]3 5 6 9
      []3 5 6 9 8
        [8 ]3 5 6 9 空
        [8 ]3 5 6 空 9
        [8 ]3 5 6 8 9
      []3 5 6 8 9

    进一步优化版的插入排序

    我们这样想,既然左半部分是是有序的,我们在有序的数组中找到插入位置,最好的方法非二分查找莫属。

    void sortByBinaryDirectlyInsert(SqList &L)
    {
        for(int i=2;i <= L.length; i++)
        {   L.r[0] = L.r[i];                /* 保存待插入元素 */
            int low = 1,high = i-1;    /* 设置初始区间 */
            while(low <= high)       /* 确定插入位置 */
            {   int mid = (low+high)/2;
                if (L.r[0].key > L.r[mid].key)
                    low = mid+1;      /* 插入位置在高半区中 */
                else
                    high = mid-1;   /* 插入位置在低半区中 */
            }/* while */
            for(int j = i - 1; j >= high +1;  j--) /* high+1为插入位置 */
                L.r[j+1] = L.r[j];          /* 后移元素,留出插入空位 */
            L.r[high+1] = L.r[0];      /* 将元素插入 */
        }/* for */
    }

    希尔排序

    算法思想

      先将整个待排序元素序列分割成若干个小序列,在小序列内插入排序;
      逐渐扩大小序列的长度(序列个数减少),使得整个序列基本有序;
      最后再对全体元素进行一次直接插入排序。

    代码实现

    void ShellInsert(SqList &L,int dk)  {//对顺序表L作一趟希尔排序
        for(int i =dk+1; i <= L.length; i++)
            if (L.r[i].key < L.r[i-dk].key) {
                L.r[0] = L.r[i];
                int j;
                for(j = i - dk;  j>0 &&L.r[0].key < L.r[j].key;  j -= dk)
                    L.r[j+dk] = L.r[j];
                L.r[j+dk] = L.r[0];
            }//if
    } //ShellInsert
    void ShellSort(SqList &L,int dlta[],int t)  {
        //按增量序列dlta[0..t-1]进行希尔排序
        for(int k = 0; k < t; k++)
            ShellInsert(L,dlta[k]);     //一趟增量为dlta[k]的希尔排序
    } //ShellSort

      说明:

      1.希尔排序的实质是插入排序!希尔排序的分析是一个复杂的问题,增量序列的设置是关键,尚没有正式的依据说明何种设置最为合理!

      2.空间复杂度为O(1),是一种不稳定的排序算法!


  • 相关阅读:
    JSTL fn:split()函数
    JSTL判断list是否为空
    oracle 合并列的函数wm_concat
    Eclipse软件使用说明
    Caused by: org.hibernate.HibernateException: identifier of an instance of ... is alterde from
    SpringData JPA详解
    关于JPA方法名创建自动查询
    jquery移除、绑定、触发元素事件使用示例详解
    js String对象中常用方法小结(字符串操作)
    java中list的使用方法
  • 原文地址:https://www.cnblogs.com/MrSaver/p/6131600.html
Copyright © 2020-2023  润新知