zoukankan      html  css  js  c++  java
  • 数据结构之排序算法

    一、分类

    1.1 内部排序

    一、插入排序

      1.直接插入排序

      2.折半插入排序

      3.希尔排序

    二、交换类排序

      1.冒泡排序

      2.快速排序

    三、选择类排序

      1.简单选择排序

      2.堆排序

    四、归并排序

      二路归并排序

    1.2 外部排序

      归并排序

    二、各排序详解

    直接插入排序

    public static void insertionSort(int[] a) {

            int tmp;

            for (int i = 1; i < a.length; i++) {

                for (int j = i; j > 0; j--) {

                    if (a[j] < a[j - 1]) {

                        tmp = a[j - 1];

                        a[j - 1] = a[j];

                        a[j] = tmp;

                    }

                }

            }

    }

    折半插入排序

    寻找插入的位置采用折半查找法

    希尔排序

    希尔(Shell)排序又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版。

    把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。gap1 = N / 2  gapk = gap(k-1) / 2

     

    冒泡排序

    public static void bubbleSort(int[] a) {

            int flag;

         int temp;

            for (int i = a.length-1; i > 0; --i) {

          flag = 0;

                 for (int j = 1; j <= i; ++j) {

                    if (a[j] < a[j - 1]) {

                         temp = a[j];

                         a[j] = a[j - 1];

                         a[j - 1] = temp;

            flag = 1;

                    }

                }

         if(flag == 0)

            return;

              } 

    }

    快速排序

    public static void partition(int []array,int lo,int hi){

            //固定的切分方式

            int key=array[lo];

            while(lo<hi){

                while(array[hi]>=key&&hi>lo){ 

                    hi--;

                }

                array[lo]=array[hi];

                while(array[lo]<=key&&hi>lo){ 

                    lo++;

                }

                array[hi]=array[lo];

            }

            array[hi]=key;

            partition(int []array,lo, hi-1);

        partition(int []array, lo, hi+1);

    }

    简单选择排序

    public void selectionSort(int[] list) {
         // 需要遍历获得最小值的次数
         // 要注意一点,当要排序 N 个数,已经经过 N-1 次遍历后,已经是有序数列
         for (int i = 0; i < list.length - 1; i++) {
             int temp = 0;
             int index = i; // 用来保存最小值得索引 
             // 寻找第i个小的数值
             for (int j = i + 1; j < list.length; j++) {
                   if (list[index] > list[j]) {
                       index = j;
                   }

           temp = list[index];
               list[index] = list[i];
                  list[i] = temp; 
                  printAll(list);

         } 

    堆排序

    先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区

    再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key

    由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。

    ……

    直到无序区只有一个元素为止。

     

    public class HeapSort {

        /**

         * 构建大顶堆  数组下标从1开始

         */

        public static void adjustHeap(int[] a, int i, int len) {

            int temp, j;

            temp = a[i];

            for (j = 2 * i; j <= len; j *= 2) {// 沿关键字较大的孩子结点向下筛选

                if (j < len && a[j] < a[j + 1])

                    ++j; // j为关键字中较大记录的下标

                if (temp >= a[j])

                    break;

                a[i] = a[j];

                i = j;

            }

            a[i] = temp;

        }

     

        public static void heapSort(int[] a) {

            int i;

            for (i = a.length / 2; i > 0; i--) {// 构建一个大顶堆

                adjustHeap(a, i, a.length);

            }

            for (i = a.length; i > 1; i--) {// 将堆顶记录和当前未经排序子序列的最后一个记录交换

                int temp = a[1];

                a[1] = a[i];

                a[i] = temp;

                adjustHeap(a, 1, i - 1);// a中前i-1个记录重新调整为大顶堆

            }

        }

     

        public static void main(String[] args) {

            int a[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };

            heapSort(a);

            System.out.println(Arrays.toString(a));

        }

    }

    二路归并排序(内部)

     

    K路归并排序(外部)

    外部排序指的是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。外部排序最常用的算法是多路归并排序,即将原文件分解成多个能够一次性装内存的部分,分别把每一部分调入内存完成排序。然后,对已经排序的子文件进行归并排序。

    过程 :

    1.初始归并段生成

      将文件分段输入内存并排序,排序完的文件称归并段,将其写入外存,这样就形成了许多初始归并段。

    置换-选择排序

      文件输入记录,当填满缓冲区后,选择最小记录输出,空缺位置由下个输入记录取代,输出记录即为初始归并段的一部分。(新填充的记录如果不能成为当前归并段的一部分,也就是说比当前归并段最大记录小,那么等待下一个归并段提供选择)

    2.最佳归并树建立

    二路归并即用哈夫曼树,I/O次数 = 带权路径长度*2

    三、复杂度与稳定性

    3.1 时间复杂度

    平均情况

      快速排序、希尔排序、堆排序、归并排序 O(log2n)

      其他的为On平方)

    最坏情况

      快排为On平方),越无序越好

      其他和平均情况一样

    最好情况

      有序的情况下,直接插入排序和冒泡排序为On

    3.2 空间复杂度

      快排为Olog2n

      归并排序为On

    3.3 稳定性

      快速排序、希尔排序、简单选择排序、堆排序为不稳定的

      其余为稳定的

  • 相关阅读:
    VS2013搭建wxWidgets开发环境
    LinuxSystemProgramming-Syllabus
    Python入门2(Python与C语言语法的不同、Notepad++运行Python代码)
    Python入门1(简介、安装)
    面试题收集---grep和find的区别
    浅拷贝 和深拷贝
    使用 system.io.filesysteminfo 来查找文件。
    使用FileSystemWatcher捕获系统文件状态
    system.io.file创建
    Javascript诞生记 [转载]
  • 原文地址:https://www.cnblogs.com/wmbg/p/6899815.html
Copyright © 2011-2022 走看看