七大排序算法的研究与总结

来源:互联网 发布:阿里妈妈淘宝联盟客服 编辑:程序博客网 时间:2024/06/05 09:21

本文章描述了7大排序算法内容与实现,使用语言为java,代码贴在最后,可根据需要快速定位。由于笔者水平有限,有错误之处请指出,不足之处请包涵。

1.七大算法基本内容

2.算法比较与选择

3.代码实现与结果

1.七大算法基本内容

七大排序算法:冒泡排序,选择排序,直接插入排序,希尔排序,快速排序,堆排序,归并排序。

由于升序和降序逻辑一样,这里只讨论升序。

1.1. 冒泡排序:

算法简述:将元素中最大的元素依次移动到最后。

算法详细:

  1. 从开始到结尾依次比较相邻的元素,如果第一个比第二个大,就交换他们两个。(一趟过后,最大的元素移动到了最后。)
  2. 将最后的元素排除在下面操作之外。(最后元素已经是最大,无需重复比较)
  3. 重复1,2,直到没有任何一对元素需要比较。

1.2. 选择排序:

算法简述:将待排序的元素中最大的元素选出放到最后。

算法详细:

  1. 将待排序元素中第一个元素视为最小值,依次与后面元素做比较,若被比较元素小,则更新最小值。(一趟过后,选出最小值)
  2. 比较最小值与待排序元素的第一个元素,若相同则跳过,若不同,则交换最小元素与待排序元素的第一元素位置。(前面的元素慢慢有序化)
  3. 重复1,2,直到没有待排序元素。

1.3. 直接插入排序:

算法简述:每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。

算法详细:

  1. 起初将第一个元素视为有续,将无序表中第一个数与有序表作比较,插入到合适位置。
  2. 重复1,直到无序表没有元素。

1.4. 希尔排序:

算法简述:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

算法详细:

  1. 先取一个小于前一增量或小于n的整数作为增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。
  2. 对每一组中元素进行直接插入排序。
  3. 重复1,2直到增量等于0为止。

1.5. 快速排序:

算法简述:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

算法详细:

  1. 设置两个变量 i、j,排序开始的时候:i=0,j=N-1;以第一个数组元素作为关键数据,赋值给key,即key=A[0];
  2. 从 j 开始向前搜索,即由后开始向前搜索( j--),找到第一个小于key的值A[ j ],将A[ j ]和A[ i ]互换;
  3. 从 i 开始向后搜索,即由前开始向后搜索( i++),找到第一个大于key的A[ i ],将A[ i ]和A[ j ]互换;
  4. 重复2,3直到 i = j 为止。
  5. 将数组以 i 分为两部分,递归执行1,2,3,4,5.直到数组不能再分为止。

1.6. 堆排序:

算法简述:堆排序(Heapsort)是指利用堆积树(每个节点的值不大于其根节点的完全二叉树)这种数据结构所设计的一种排序,它是选择排序的一种,当数据很多时极大的减少了比较次数;数据量少时不适用。

算法详细:

  1. 建立大根堆。
  2. 将顶端元素与无序区最后元素交换,然后调整无序区堆为大根堆(调整堆)。
  3. 重复2,直到无序区元素为空。

建立大根堆算法:

  1. 从数组的 length / 2 处节点调整堆,依次到第一个节点。

调整堆算法:

  1. 将节点与其左右孩子比较,选出最大值。
  2. 若最大值为自己则结束,最大值为其孩子,则节点与孩子交换,并对其孩子进行1,2.直到结束。

1.7. 归并排序:

算法简述:将序列分为若干序列,对序列排序,然后将已有序序列两两合并并调整,直到没有序列可合并,得到完全有序的序列。

算法详细:

  1. 将序列依次中分为两序列,直到不能再分为止。
  2. 申请空间,使其大小为两个已排序序列之和,该空间用来存放合并后的序列。
  3. 将两序列中最小者依次放入1所申请空间类。
  4. 重复2,3,直到所有序列合并完成。
  5. (注意)分割与合并是相对的,即分割成的两序列会排序后会合并在一起。

2.算法比较与选择

2.1. 算法比较

2.2. 选择

笔者测试数据容量范围为:10-100000,结论如下:

  • 数据量较小(笔者的程序n<80)时,直接插入排序最佳(稳定且快速)。

  • 通常情况下(100<n<100000),快速排序最优。

  • 数据量超大时(至少n>100000吧),选择堆排序,归并排序。(其它网友总结)

以下是其它网友关于排序的测试结果与选择总结。

http://www.360doc.com/content/14/0813/19/16948208_401618179.shtml

3. 代码实现与结果

由于笔者偷懒,把所有排序算法写到一个文件中了,后面测试时发现使用策略模式代码更清晰直观,有兴趣的网友可以试试。

3.1. 排序代码:

public class SortBase2 {    /**     * 冒泡排序.     * @param nums ( 需要排序的数组)     * @return     */    public void bubbleSort(int[] nums){        int temp;        for (int i = 0; i < nums.length - 1; i++){            for (int j = 0; j < nums.length - 1 - i; j++){                if(nums[j] > nums[j+1]){                    temp = nums[j];                    nums[j] = nums[j+1];                    nums[j+1] = temp;                }            }        }    }        /**     * 选择排序.     * (  每一次从待排序的数据元素中选出最小(或最大)的一个元素,     *    存放在序列的起始位置,直到全部待排序的数据元素排完. )     * @param nums     */    public void selectSort(int[] nums){        int temp;        int minIndex;        for (int i = 0; i < nums.length; i++){            minIndex = i;            for(int j = i + 1; j < nums.length; j++ ){                if(nums[minIndex] > nums[j]){                    minIndex = j;                }            }                        if(minIndex != i){                temp = nums[i];                nums[i] = nums[minIndex];                nums[minIndex] = temp;            }        }    }            /**     * 直接插入排序.     * 描述:每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序。     * @param nums ( 需要排序的数组)     */    public void insertSort(int[] nums){        int temp;        for (int i = 1; i < nums.length; i++){            for (int j = 0; j < i; j++){                if(nums[i] < nums[j]){                    temp = nums[i];                    for(int k =  i; k > j; k--){                        nums[k] = nums[k-1];                    }                    nums[j] = temp;                    break;                }            }        }    }        /**     * 直接插入排序2.     * 改进:从后面开始比较,并同时后移。较少了比较次数。     * @param nums     */    public void insertSort2(int[] nums){        int temp;        for (int i = 0; i < nums.length; i++){            for (int j = i - 1; j >= 0; j--){                if (nums[j+1] < nums[j]){                    temp = nums[j];                    nums[j] = nums[j+1];                    nums[j+1] = temp;                } else {                    break;                }            }        }            }    /**     * 直接插入排序3.     * 改进:从后面开始比较,并同时后移,和2相比减少交换次数。     * @param nums     */    public void insertSort3(int[] nums){        int temp;        for (int i = 1; i < nums.length; i++){            if(nums[i] < nums[i-1]){                temp = nums[i];                int j = i - 1;                for (; j >= 0 && temp < nums[j]; j--){                    nums[j+1] = nums[j];                }                nums[j+1] = temp;                            }                    }    }        /**     * 希尔排序.     * @param nums ( 需要排序的数组)     * @return     */    public void shellSort(int[] nums){          int temp;        int increment = nums.length;        while (increment > 1){            increment /= 2;            for (int i = increment; i < nums.length; i++){                if (nums[i] < nums[i - increment]){                    temp = nums[i];                    int j = i - increment;                    for(; j >= 0 && nums[j] > temp; j -= increment){                        nums[j + increment] = nums[j];                    }                    nums[j + increment] = temp;                }            }        }    }              /**     * 快速排序.     * @param nums     * @param low     * @param high     */    public void quicklySort(int[] nums) {          int low = 0;        int high = nums.length - 1;        quicklySort(nums, low, high);     }        public void quicklySort(int[] nums, int low, int high) {          int mid;          if (low < high) {              mid = partition(nums, low, high);             quicklySort(nums, low, mid - 1);              quicklySort(nums, mid + 1, high);          }      }        // 快排辅助程序    private int partition(int[] nums, int low, int high) {          int key = nums[low];        while(low < high){            while(low < high && nums[high] >= key){                high--;            }            if (low < high){                nums[low] = nums[high];              }            while(low < high && nums[low] <= key){                low++;            }            if (low < high){                nums[high] = nums[low];              }        }        nums[low] = key;        return low;      }        /**     * 快速排序2.     * @param nums     * @param low     * @param high     */    public void quicklySort2(int[] nums) {          int low = 0;        int high = nums.length - 1;        quicklySort2(nums, low, high);     }    public void quicklySort2(int[] nums, int low, int high) {          int mid;        if(low < high){            mid = partition2(nums, low, high);            quicklySort2(nums, low, mid - 1);            quicklySort2(nums, mid + 1, high);        }    }        private int partition2(int[] nums, int low, int high){        int key = nums[low];        while(low < high){            while(low < high && key <= nums[high]){                high -- ;            }            nums[low] = nums[high];// 差别之处,虽然可能会出现nums[10]=nums[10]这样没有意义的赋值,但减少if的比较与判断时间。            while(low < high && key >= nums[low]){                low ++ ;            }            nums[high] = nums[low]; // 差别之处                    }        nums[low] = key;        return low;    }        /**     * 堆排序.     * @param nums     * @return     */    public void heapSort(int[] nums){        int temp;        // 构建堆        for (int i = nums.length / 2; i >= 0 ; i--){            heapAdjust(nums, nums.length, i);        }        // 最大的放在后面并重构堆        for(int i = nums.length - 1; i > 0; i--){            temp = nums[0];            nums[0] = nums[i];            nums[i] = temp;            heapAdjust(nums, i, 0);        }    }        /**     * 调整堆.     * @param nums     * @param size     * @param index     */    private void heapAdjust(int[] nums, int size, int index){        int left = (index << 1) + 1;        int right = (index << 1) + 2;        int largest = index;                if(left < size && nums[left] > nums[largest]){            largest = left;        }                if(right < size && nums[right] > nums[largest]){            largest = right;        }                if(largest != index){            int temp = nums[index];            nums[index] = nums[largest];            nums[largest] = temp;                        heapAdjust(nums, size, largest);        }    }    /**     * 并归排序     * @param nums      * @return     */    public void mergingSort(int[] nums){        int tail = nums.length - 1;        sortSplit(nums, 0, tail);    }        /**     * 分割数组.     * @param nums     * @param head     * @param tail     */    public void sortSplit(int[] nums, int head, int tail){        if(head >= tail){            return;        }        int mid = (head + tail) / 2;        sortSplit(nums, head, mid);        sortSplit(nums, mid + 1, tail);        merging(nums, head, mid + 1, tail);    }        /**     * 合并数组     * @param nums     * @param start1 第一个有序表的起始下标     * @param start2 第二个有序表的起始下标     * @param tail 第二个有序表的结束小标     * @return     */    public void merging(int[] nums, int s1, int s2, int tail){        if(s1 >= tail){            return;         }        int[] tempArray = new int[tail - s1 + 1];        int index1 = s1;        int index2 = s2;        int i = 0;                while(index1 < s2 && index2 <= tail){            if(nums[index1] < nums[index2]){                tempArray[i] = nums[index1++];            }else{                tempArray[i] = nums[index2++];            }            i++;        }        // 剩下的补齐        while(index1 < s2){            tempArray[i++] = nums[index1++];        }        while(index2 <= tail){            tempArray[i++] = nums[index2++];        }                // 放入原数组        for(int j = 0; j < tempArray.length; j++){            nums[s1++] = tempArray[j];        }    }}

3.2. 测试辅助代码

public class ProduceArray {    /**     * 产生0-999的随机数组.     * @param amount (数组容量)     * @return     */    public int[] produceArray(int amount){        int[] array = new int[amount] ;        for (int i = 0; i < amount; i++){            array[i] = (int) (Math.random()*1000);        }        return array;    }        /**     * 打印数组。     * @param array     */    public void printArray(int[] array){        for (int i:array){            System.out.print(i + " ");        }        System.out.println();    }}

3.3. 测试程序代码:

import java.util.Arrays;public class Test2 {    int times = 10;    // 测试次数    int count = 10000;  // 数组容量        /**     * @param args     */    public static void main(String[] args) {        System.out.println("start");        Test2 mytest = new Test2();                ProduceArray pa = new ProduceArray();                int[][] array = new int[mytest.times][];                for(int i = 0; i < array.length; i++){            array[i] = pa.produceArray(mytest.count); // 生成随机数组。//            pa.printArray(array[i]);        }                mytest.bubbleSortTest(array);// 冒泡排序                mytest.selectSortTest(array);// 选择排序                mytest.insertSortTest(array);// 插入排序                mytest.insertSortTest2(array);                mytest.insertSortTest3(array);                mytest.shellSortTest(array);                mytest.quicklySort(array);                mytest.quicklySort2(array);                mytest.heapSort(array);                mytest.mergingSort(array);    }        public void bubbleSortTest(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);// 复制a的二维结构        int[] arrayTemp;// 零时数组        long start;// 记录排序运行开始时间        long end;// 记录排序运行结束时间        long[] times = new long[a.length];// 记录排序运行时间        long time = 0;// 第time次测试                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();// 纳秒级时间,基本能够满足测试精度需要            mybbSort.bubbleSort(arrayTemp);// 调用排序            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;// 算出平均运行时间                System.out.println("冒泡排序结果:");        if(array[0].length < 20){// 数组容量小于20时打印数组,大于20打印平均运行时间。            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }    }        // 与前面冒泡排序的测试相同,只是调用的排序方法不同,更清晰直观的写法是使用策略模式来写,这里笔者先写的排序算法文件,所以偷懒了,下同。     public void selectSortTest(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.selectSort(arrayTemp);// 这里是不同            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("选择排序结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }            }        public void insertSortTest(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.insertSort(arrayTemp);             end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("直接插入排序结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }            }        public void insertSortTest2(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.insertSort2(arrayTemp);            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("直接插入排序2结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }    }        public void insertSortTest3(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.insertSort3(arrayTemp);            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("直接插入排序3结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }            }        public void shellSortTest(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.shellSort(arrayTemp);            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("希尔排序结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }            }        public void quicklySort(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.quicklySort(arrayTemp);            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("快速排序结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }            }        public void quicklySort2(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.quicklySort2(arrayTemp);            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("快速排序2结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }            }        public void heapSort(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.heapSort(arrayTemp);            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("堆排序结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }    }        public void mergingSort(int[][] a){        ProduceArray pa = new ProduceArray();        SortBase mybbSort = new SortBase();        int[][] array = Arrays.copyOf(a, a.length);        int[] arrayTemp;        long start;        long end;        long[] times = new long[a.length];        long time = 0;                for(int i = 0; i < a.length; i++){            arrayTemp = Arrays.copyOf(array[i], array[i].length);            start = System.nanoTime();            mybbSort.mergingSort(arrayTemp);            end = System.nanoTime();            times[i] = end - start;            array[i] = arrayTemp;        }                for(long t : times){            time += t;        }        time /= times.length;                System.out.println("并归排序结果:");        if(array[0].length < 20){            for(int[] temp : array){                pa.printArray(temp);             }        }else{            System.out.println("平均运行时间: " + (time));        }    }}

3.4. 测试结果:

测试次数:10

数组容量:10000

时间单位:纳秒

start
冒泡排序结果:
平均运行时间: 236966562
选择排序结果:
平均运行时间: 82126896
直接插入排序结果:
平均运行时间: 68611189
直接插入排序2结果:
平均运行时间: 59882902
直接插入排序3结果:
平均运行时间: 41153782
希尔排序结果:
平均运行时间: 1392813
快速排序结果:
平均运行时间: 969936
快速排序2结果:
平均运行时间: 849098
堆排序结果:
平均运行时间: 2131108
并归排序结果:
平均运行时间: 1727959


测试次数:10000

数组容量:80

start
冒泡排序结果:
平均运行时间: 15689
选择排序结果:
平均运行时间: 8874
直接插入排序结果:
平均运行时间: 6209
直接插入排序2结果:
平均运行时间: 4893
直接插入排序3结果:
平均运行时间: 3590
希尔排序结果:
平均运行时间: 5127
快速排序结果:
平均运行时间: 3776
快速排序2结果:
平均运行时间: 3737
堆排序结果:
平均运行时间: 7203
并归排序结果:
平均运行时间: 8613




0 0
原创粉丝点击