• 希尔排序算法


    希尔排序的基本思想

      ①希尔排序又称缩小增量排序 ,它本质上是一个插入排序算法。为什么呢?

      因为,对于插入排序而言,插入排序是将当前待排序的元素与前面所有的元素比较,而希尔排序是将当前元素  与前面增量位置上的元素进行比较,然后,再将该元素插入到合适位置。当一趟希尔排序完成后,处于增量位置上的元素是有序的。

      ②希尔排序算法的效率依赖于增量的选取

      假设增量序列为 h(1),h(2).....h(k),其中h(1)必须为1,且h(1)<h(2)<...h(k) 。

      第一趟排序时在增量为h(k)的各个元素上进行比较;

      第二趟排序在增量为h(k-1)的各个元素上进行比较;

      ..........

      最后一趟在增量h(1)上进行比较。由此可以看出,每进行一趟排序,增量是一个不断减少的过程,因此称之为缩小增量。

    希尔排序的效率和适用场景

      希尔排序的执行时间为O(N*(logN)2),比快速排序慢(O(N*logN)),比简单排序快(O(N2))

      希尔排序对于中等规模的数据量的排序是良好的比如1000量级的数据量(亲测1000量级马上排序完成,10000量级等了差不多一分钟)他的特点是在最坏的情况和在平均情况下执行效率基本没有什么差别,而快速排序在最坏的情况下执行效率会非常差,相比较而言,在稳定性上希尔算法更好。

    java程序

    package sy;
    
    class ArraySh{
        private long[] theArray;
        private int nElems;
        
        public ArraySh(int max)
        {
            theArray = new long[max];
            nElems = 0;
        }
        
        public void inset(long value)
        {
            theArray[nElems] = value;
            nElems++;
        }
        
        public void display(){
            System.out.print("A = ");
            for(int j = 0; j < nElems; j++)
            {
                System.out.print(theArray[j] + " ");
            }
            System.out.println("");        
        }
        //希尔排序方法
        public void shellSort(){
            //定义内循环和外循环变量
            int outer,inner;
            //定义临时变量存储插入项
            long temp;
            //定义增量并赋值为1
            int h = 1;
            //寻找h最大的可能值,也是第一轮第一个数组的第二项,也是第一轮第一个数组的插入项,也是希尔排序的第一个插入项
            while(h <= nElems / 3)
            {
                h = h * 3 + 1;
            }
            //正式开始希尔排序,当h增量为0时停止希尔排序
            while(h > 0)
            {
                //1.这里其实是增量为h的插入排序,原插入排序增量始终为1,效率十分低下。            
                //2.在希尔排序的增量h为1的时候,整个数组其实基本有序了,在基本有序的数组使用插入算法相当高效,这时候的插入排序算法比较和复制的操作不超过两次
                //3.这层for循环其实在每一轮增量改变后执行,目的是排序小数组,比如增量为3的数组[12,34,45,21,54,23]被分成三个小数组,该循环第一轮执行[12,21]的排序,第二轮执行[34,54]的排序,第三轮执行[45,23]的排序
                for(outer = h; outer < nElems; outer++)
                {
                    //将插入项赋值给临时变量
                    temp = theArray[outer];
                    //将内外循环连接
                    inner = outer;
                    //判断插入项的插入位置  条件是插入项和前面的有序部分比较而且小,并且inner大于0
                    while(inner > h -1 && theArray[inner - h] >= temp)
                    {                    
                        //比插入项大的有序部分全部后移一位
                        theArray[inner] = theArray[inner - h];
                        inner -= h;
                    }
                    //把插入项发在比它大的数据项的位置
                    theArray[inner] = temp;            
                }
                //增量h减少
                h = (h - 1) / 3;        
            }
        }
    }
    class App{
        public static void main(String[] args)
        {
            int maxSize = 10;
            ArraySh arr;
            arr = new ArraySh(maxSize);
            
            for(int j = 0 ; j < maxSize; j++)
            {
                long n = (int)(java.lang.Math.random() * 99);
                arr.inset(n);
            }
            arr.display();
            arr.shellSort();
            arr.display();        
        }
    }
  • 相关阅读:
    再谈Linux内核中的RCU机制
    Linux下的crontab定时执行任务命令详解
    Linux 2.6内核中新的锁机制--RCU
    linux内核自锁旋spinlock常用宏解释
    Linux内核list/hlist解读
    Linux下0号进程的前世(init_task进程)今生(idle进程)----Linux进程的管理与调度(五)
    Linux下的进程类别(内核线程、轻量级进程和用户进程)以及其创建方式--Linux进程的管理与调度(四)
    Linux进程ID号--Linux进程的管理与调度(三)
    内核源码阅读(三)进程命名空间和用户命名的实现
    Linux的命名空间详解--Linux进程的管理与调度(二)
  • 原文地址:https://www.cnblogs.com/iwebkit/p/7613316.html
Copyright © 2020-2023  润新知