Day_44希尔排序

news/2024/7/7 21:35:21

目录

一. 关于希尔排序

二. 希尔排序的实现过程

三. 希尔排序的代码实现

        1. 核心代码

        2. 修改后的代码

四. 代码展示

五. 数据测试

六. 总结与反思


一. 关于希尔排序

       希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由希尔在 1959 年所发表的论文“A high-speed sorting procedure”中所描述。1961年,IBM 公司的女程序员 Marlene Metzner Norton(玛琳·梅茨纳·诺顿)首次使用 FORTRAN 语言编程实现了希尔排序算法。在其程序中使用了一种简易有效的方法设置希尔排序所需的增量序列:第一个增量取待排序记录个数的一半,然后逐次减半,最后一个增量为 1。该算法后来被称为 Shell-Metzner 算法。

        希尔排序可以说是排序算法里面最特别的一种存在,它是集合了直接插入算法的两种特殊情况改进而来。我们对直接插入排序进行讨论:例如若待排序列为“正序”时,其时间效率可以提升至O(n),由此可见直接插入更适用于①基本有序②数据量不大的表。希尔排序正是基于这两点分析对直接插入排序进行改进而来,又称缩小增量排序。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

        1. 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。

        2. 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。

        (最特别的是希尔排序的平均时间复杂度是O(n^{1.3}),这在排序算法里面几乎是最具有辨识度的存在)

二. 希尔排序的实现过程

        希尔排序的的基本思想是:先将待排序表分割成若干形如L[i,i+d,i+2d...i+kd]的“特殊”子表,即把相隔某个“增量”的记录组成一个子表,对各个子表分别进行直接插入排序,当整个表中的元素已呈“基本有序”时,再对全体记录进行一次直接插入排序。

        希尔排序的过程如下:先取一个长度小于n的步长d_{1},把表中的全部记录分成d_{1}组,所有距离为d_{1}倍数的记录放在同一组,在各组内部进行直接插入排序;然后取第二个步长d_{2}<d_{1},重复上述过程,直到所取到的d_{t}=1,即所有记录已放在同一组中,再进行直接插入排序,由于此时已经具有较好的局部性,故可以很快得到最终的结果。

        第一趟排序结果如图所示:

第一趟排序结果

        第二趟排序结果如图所示:

第二趟排序结果

         第三趟排序结果如图所示:

第三趟排序结果

三. 希尔排序的代码实现

        1. 核心代码

                第一层循环是确定步长的大小和进行多少次步长的更新;第二层循环是确定一个步长内有多少组数据;第三个循环和第四个循环是对同一个步长里面同一组的数据直接插入排序。这里和书上的有点不同,这里用了四次循环,后面我将再讨论和书上的不同。

    /**
     *********************
     * Shell sort. We do not use sentries here because too many of them are needed.
     *********************
     */
    public void shellSort() {
        DataNode tempNode;
        int[] tempJumpArray = { 5, 3, 1 };
        int tempJump;
        int p;
        for (int i = 0; i < tempJumpArray.length; i++) {
            tempJump = tempJumpArray[i];
            for (int j = 0; j < tempJump; j++) {
                for (int k = j + tempJump; k < length; k += tempJump) {
                    tempNode = data[k];
                    // Find the position to insert.
                    // At the same time, move other nodes.
                    for (p = k - tempJump; p >= 0; p -= tempJump) {
                        if (data[p].key > tempNode.key) {
                            data[p + tempJump] = data[p];
                        } else {
                            break;
                        } // Of if
                    } // Of for p

                    // Insert.
                    data[p + tempJump] = tempNode;
                } // Of for k
            } // Of for j
            System.out.println("Round " + i);
            System.out.println(this);
        } // Of for i
    }// Of shellSort

        2. 修改后的代码

        这里用的三重循环,第一重循环和上面其实是一样的,只不过闵老师用了一个确定的数组来设定步长,我是根据数据长度来设定的步长。

        最重要的是第二重和第三重循环这里等同于上面的第二,三,四重循环。不一样的地方在于我是对于同一步长分类完成之后直接插入排序,而闵老师是根某一个步长先将数据分成几个小组,再将同一个小组的数据进行直接插入排序;相当于后面修改的代码将闵老师的第二,三重循环合并了。

    /**
     *********************
     * Shell sort. We do not use sentries here because too many of them are needed.
     *********************
     */
    public void shellSort1() {
        DataNode tempNode;
        int tempJump;
        int position;
        int i;
        int round=1;

        for (tempJump = length / 2; tempJump >= 1; tempJump = tempJump / 2) {
            for (position = tempJump;  position< length; position += 1) {
                tempNode = data[position];
                // Find the position to insert.
                // At the same time, move other nodes.
                for (i = position - tempJump; i >= 0&&tempNode.key<data[i].key; i -= tempJump) {
                    data[i+tempJump]=data[i];
                } // Of for i
                // Insert.
                data[i + tempJump] = tempNode;
            } // Of for position

            System.out.println("Round " + round);
            System.out.println(this);
            round++;
        }
    }// Of shellSort

四. 代码展示

        主类:

package Day_44;

import Day_41.DataArray;



import Day_41.DataArray;

    public class demo1 {
        /**
         *********************
         * The entrance of the program.
         *
         * @param args Not used now.
         *********************
         */
        public static void main(String args[]) {
//        System.out.println("\r\n-------sequentialSearchTest-------");
            int []paraKeyArray;
            paraKeyArray=new int[]{11,2,3};
            String[] paraContentArray = new String[]{"121","21","324"};
            DataArray test=new DataArray(paraKeyArray,paraContentArray);

//        test.insertionSort();
//        System.out.println("Result\r\n" + test);
            test.shellSortTest();


        }// Of main
    }

        调用类(我喜欢将同一个类的代码写到一起,这样虽然长一点,但是更全面):

package Day_41;
/**
 * Data array for searching and sorting algorithms.
 *
 * @author Jian An 2569222191@qq.com.
 */
public class DataArray {
    /**
     * An inner class for data nodes. The text book usually use an int value to
     * represent the data. I would like to use a key-value pair instead.
     */
    class DataNode {
        /**
         * The key.
         */
        int key;

        /**
         * The data content.
         */
        String content;

        /**
         * ********************
         * The first constructor.
         * ********************
         */
        DataNode(int paraKey, String paraContent) {
            key = paraKey;
            content = paraContent;
        }// Of the first constructor

        /**
         * ********************
         * Overrides the method claimed in Object, the superclass of any class.
         * ********************
         */
        public String toString() {
            return "(" + key + ", " + content + ") ";
        }// Of toString
    }// Of class DataNode

    /**
     * The data array.
     */
    DataNode[] data;

    /**
     * The length of the data array.
     */
    int length;

    /**
     * ********************
     * The first constructor.
     *
     * @param paraKeyArray     The array of the keys.
     * @param paraContentArray The array of contents.
     *                         ********************
     */
    public DataArray(int[] paraKeyArray, String[] paraContentArray) {
        length = paraKeyArray.length;
        data = new DataNode[length];

        for (int i = 0; i < length; i++) {
            data[i] = new DataNode(paraKeyArray[i], paraContentArray[i]);
        } // Of for i
    }// Of the first constructor

    /**
     * ********************
     * Overrides the method claimed in Object, the superclass of any class.
     * ********************
     */
    public String toString() {
        String resultString = "I am a data array with " + length + " items.\r\n";
        for (int i = 0; i < length; i++) {
            resultString += data[i] + " ";
        } // Of for i

        return resultString;
    }// Of toString

    /**
     * ********************
     * Sequential search. Attention: It is assume that the index 0 is NOT used.
     *
     * @param paraKey The given key.
     * @return The content of the key.
     * ********************
     */
    public String sequentialSearch(int paraKey) {
        data[0].key = paraKey;

        int i;
        // Note that we do not judge i >= 0 since data[0].key = paraKey.
        // In this way the runtime is saved about 1/2.
        // This for statement is equivalent to
        //for (i = length - 1; data[i].key != paraKey; i--);
        for (i = length - 1; data[i].key != paraKey; i--) {
            ;
        }//Of for i
        return data[i].content;
    }// Of sequentialSearch

    /**
     * ********************
     * Test the method.
     * ********************
     */
    public static void sequentialSearchTest() {
        int[] tempUnsortedKeys = {-1, 5, 3, 6, 10, 7, 1, 9};
        String[] tempContents = {"null", "if", "then", "else", "switch", "case", "for", "while"};
        DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);

        System.out.println(tempDataArray);

        System.out.println("Search result of 10 is: " + tempDataArray.sequentialSearch(10));
        System.out.println("Search result of 5 is: " + tempDataArray.sequentialSearch(5));
        System.out.println("Search result of 4 is: " + tempDataArray.sequentialSearch(4));
    }// Of sequentialSearchTest

    /**
     * ********************
     * Binary search. Attention: It is assume that keys are sorted in ascending
     * order.
     *
     * @param paraKey The given key.
     * @return The content of the key.
     * ********************
     */
    public String binarySearch(int paraKey) {
        int tempLeft = 0;
        int tempRight = length - 1;
        int tempMiddle = (tempLeft + tempRight) / 2;

        while (tempLeft <= tempRight) {
            tempMiddle = (tempLeft + tempRight) / 2;
            if (data[tempMiddle].key == paraKey) {
                return data[tempMiddle].content;
            } else if (data[tempMiddle].key <= paraKey) {
                tempLeft = tempMiddle + 1;
            } else {
                tempRight = tempMiddle - 1;
            }
        } // Of while

        // Not found.
        return "null";
    }// Of binarySearch

    /**
     * ********************
     * Test the method.
     * ********************
     */
    public static void binarySearchTest() {
        int[] tempSortedKeys = {1, 3, 5, 6, 7, 9, 10};
        String[] tempContents = {"if", "then", "else", "switch", "case", "for", "while"};
        DataArray tempDataArray = new DataArray(tempSortedKeys, tempContents);

        System.out.println(tempDataArray);

        System.out.println("Search result of 10 is: " + tempDataArray.binarySearch(10));
        System.out.println("Search result of 5 is: " + tempDataArray.binarySearch(5));
        System.out.println("Search result of 4 is: " + tempDataArray.binarySearch(4));
    }// Of binarySearchTest

//    ----------------------------------------------------
//    ----------------------------------------------------
//    ----------------------------------------------------


    /**
     *********************
     * The second constructor. For Hash code only. It is assumed that
     * paraKeyArray.length <= paraLength.
     *
     * @param paraKeyArray     The array of the keys.
     * @param paraContentArray The array of contents.
     * @param paraLength       The space for the Hash table.
     *********************
     */
    public DataArray(int[] paraKeyArray, String[] paraContentArray, int paraLength) {
        // Step 1. Initialize.
        length = paraLength;
        data = new DataNode[length];

        for (int i = 0; i < length; i++) {
            data[i] = null;
        } // Of for i

        // Step 2. Fill the data.
        int tempPosition;

        for (int i = 0; i < paraKeyArray.length; i++) {
            // Hash.
            tempPosition = paraKeyArray[i] % paraLength;

            // Find an empty position
            while (data[tempPosition] != null) {
                tempPosition = (tempPosition + 1) % paraLength;
                System.out.println("Collision, move forward for key " + paraKeyArray[i]);
            } // Of while

            data[tempPosition] = new DataNode(paraKeyArray[i], paraContentArray[i]);
        } // Of for i
    }// Of the second constructor

    /**
     *********************
     * Hash search.
     *
     * @param paraKey The given key.
     * @return The content of the key.
     *********************
     */
    public String hashSearch(int paraKey) {
        int tempPosition = paraKey % length;
        while (data[tempPosition] != null) {
            if (data[tempPosition].key == paraKey) {
                return data[tempPosition].content;
            } // Of if
            System.out.println("Not this one for " + paraKey);
            tempPosition = (tempPosition + 1) % length;
        } // Of while

        return "null";
    }// Of hashSearch

    /**
     *********************
     * Test the method.
     *********************
     */
    public static void hashSearchTest() {
        int[] tempUnsortedKeys = { 16, 33, 38, 69, 57, 95, 86 };
        String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
        DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents, 19);

        System.out.println(tempDataArray);

        System.out.println("Search result of 95 is: " + tempDataArray.hashSearch(95));
        System.out.println("Search result of 38 is: " + tempDataArray.hashSearch(38));
        System.out.println("Search result of 57 is: " + tempDataArray.hashSearch(57));
        System.out.println("Search result of 4 is: " + tempDataArray.hashSearch(4));
    }// Of hashSearchTest


//    ----------------------------------------------------
//    ----------------------------------------------------
//    ----------------------------------------------------

    /**
     *********************
     * Insertion sort. data[0] does not store a valid data. data[0].key should
     * be smaller than any valid key.
     *********************
     */
    public void insertionSort() {
        DataNode tempNode;
        int j;
        for (int i = 2; i < length; i++) {
            tempNode = data[i];

            //Find the position to insert.
            //At the same time, move other nodes.
            for (j = i - 1; data[j].key > tempNode.key; j--) {
                data[j + 1] = data[j];
            } // Of for j

            //Insert.
            data[j + 1] = tempNode;

            System.out.println("Round " + (i - 1));
            System.out.println(this);
        } // Of for i
    }// Of insertionSort

    /**
     *********************
     * Test the method.
     *********************
     */
    public static void insertionSortTest() {
        int[] tempUnsortedKeys = { -100, 5, 3, 6, 10, 7, 1, 9 };
        String[] tempContents = { "null", "if", "then", "else", "switch", "case", "for", "while" };
        DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);

        System.out.println(tempDataArray);

        tempDataArray.insertionSort();
        System.out.println("Result\r\n" + tempDataArray);



    }// Of insertionSortTest


//    ----------------------------------------------------
//    ----------------------------------------------------
//    ----------------------------------------------------
    /**
     *********************
     * Shell sort. We do not use sentries here because too many of them are needed.
     *********************
     */
    public void shellSort() {
        DataNode tempNode;
        int[] tempJumpArray = { 5, 3, 1 };
        int tempJump;
        int p;
        for (int i = 0; i < tempJumpArray.length; i++) {
            tempJump = tempJumpArray[i];
            for (int j = 0; j < tempJump; j++) {
                for (int k = j + tempJump; k < length; k += tempJump) {
                    tempNode = data[k];
                    // Find the position to insert.
                    // At the same time, move other nodes.
                    for (p = k - tempJump; p >= 0; p -= tempJump) {
                        if (data[p].key > tempNode.key) {
                            data[p + tempJump] = data[p];
                        } else {
                            break;
                        } // Of if
                    } // Of for p

                    // Insert.
                    data[p + tempJump] = tempNode;
                } // Of for k
            } // Of for j
            System.out.println("Round " + i);
            System.out.println(this);
        } // Of for i
    }// Of shellSort



    /**
     *********************
     * Shell sort. We do not use sentries here because too many of them are needed.
     *********************
     */
    public void shellSort1() {
        DataNode tempNode;
        int tempJump;
        int position;
        int i;
        int round=1;

        for (tempJump = length / 2; tempJump >= 1; tempJump = tempJump / 2) {
            for (position = tempJump;  position< length; position += 1) {
                tempNode = data[position];
                // Find the position to insert.
                // At the same time, move other nodes.
                for (i = position - tempJump; i >= 0&&tempNode.key<data[i].key; i -= tempJump) {
                    data[i+tempJump]=data[i];
                } // Of for i
                // Insert.
                data[i + tempJump] = tempNode;
            } // Of for position

            System.out.println("Round " + round);
            System.out.println(this);
            round++;
        }
    }// Of shellSort
    /**
     *********************
     * Test the method.
     *********************
     */
    public static void shellSortTest() {
        int[] tempUnsortedKeys = { 5, 3, 6, 10, 7, 1, 9, 12, 8, 4 };
        String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while", "throw", "until", "do" };
        DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);

        System.out.println(tempDataArray);

        tempDataArray.shellSort1();
        System.out.println("Result\r\n" + tempDataArray);
    }// Of shellSortTest





}// Of class DataArray

五. 数据测试

        原先的代码和修改后的代码都是一样的运行结果:

六. 总结与反思

        这一小节关键思想是理解直接插入算法在①基本有序,②数据量小的前提下,排序效率很高,然后我们根据这两个线索,构造出来先设定大步长然后慢慢减小步长的算法,从而每一次都是对一个基本有序且数据量较小的数组进行排序;这样得到的最终效率是比较高的。这一小节的知识是完全从前面知识剥离出来的;告诉我们关于算法完全可以在前者的基础上更改条件构造出更好的算法。


http://lihuaxi.xjx100.cn/news/1215991.html

相关文章

《.NET 下最快比较两个文件内容是否相同》之我的看法验证

我对文件对比这一块还是比较感兴趣的&#xff0c;也想知道哪种方式性价比最高&#xff0c;效率最好&#xff0c;所以&#xff0c;根据这篇文章&#xff0c;我自己也自测一下&#xff0c;顺便留出自己对比的结果&#xff0c;供大佬们参考一二。 大致对比方案 我这边根据文章里…

[chatGPT攻略] 如何检测文本内容是否由ChatGPT生成 ?

[chatGPT攻略] 如何检测文本内容是否由ChatGPT生成 ? 在 ChatGPT 爆火的两个月内&#xff0c;学生就已经自发用这种工具做作业、写论文偷懒&#xff0c;编剧会用它编故事试试出乎人意料的故事走向&#xff0c;文案编辑用它来给自己打工。 在用工具给自己省事这件事上&#xf…

VMware虚拟机Ubuntu磁盘空间扩充详细教程

文章目录 一、写在前面二、具体步骤三、最后总结 一、写在前面 最近在做Linux内核相关实验的时候&#xff0c;发现有时候我们编译出来的内核太大&#xff0c;如果VMware虚拟机空间分配不足会导致编译Linux内核失败&#xff0c;经过摸索&#xff0c;发现可以扩充Ubuntu的磁盘空间…

【链表的分类】

链表是一种常用的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含一个数据元素和指向下一个节点的指针。根据节点的连接方式和节点的性质&#xff0c;链表可以分为多种类型。 单向链表&#xff08;Singly Linked List&#xff09; 单向链表是最基本的链表类…

【Java】深入理解Java虚拟机 | 垃圾收集器GC

《深入理解Java虚拟机》的阅读笔记——第三章 垃圾收集器与内存分配策略。 参考了JavaGuide网站的相关内容&#xff1a;https://javaguide.cn/ Q&#xff1a;哪些内存需要回收&#xff1f;什么时候回收&#xff1f;如何回收&#xff1f; 2 对象已死吗&#xff1f; 2.1 引用…

java设计模式(十二)代理模式

目录 定义模式结构角色职责代码实现静态代理动态代理jdk动态代理cglib代理 适用场景优缺点 定义 代理模式给某一个对象提供一个代理对象&#xff0c;并由代理对象控制对原对象的引用。说简单点&#xff0c;代理模式就是设置一个中间代理来控制访问原目标对象&#xff0c;以达到…

javascript基础二十九:JavaScript如何判断一个元素是否在可视区域中?

一、用途 可视区域即我们浏览网页的设备肉眼可见的区域&#xff0c;如下图 在日常开发中&#xff0c;我们经常需要判断目标元素是否在视窗之内或者和视窗的距离小于一个值&#xff08;例如 100 px&#xff09;&#xff0c;从而实现一些常用的功能&#xff0c;例如&#xff1a;…

每日一练 | 华为认证真题练习Day52

1、OSPFv3邻接关系无法建立&#xff0c;可能是由以下哪些原因引起&#xff1f;&#xff08;多选&#xff09; A. Router-ID冲突 B. HELLO报文发送周期不一致 C. 区域号码不一致 D. 接口IPv6地址前缀不一致 2、IPv6报文头比IPv4报文头增加了哪个字段&#xff1f; A. Versio…