美文网首页
排序算法算法总结

排序算法算法总结

作者: karlsu | 来源:发表于2017-03-28 23:28 被阅读12次

    评价一个好的算法有以下几个标准
    ① 正确性(Correctness )
    ② 可读性(Readability)
    ③ 健壮性(Robustness)
    ④ 通用性(Generality)
    ⑤ 效率与存储量需求:
    对于效率指的是算法执行的时间,存储量需求指算法执行过程中所需要的最大存储空间。一般地,这两者与问题的规模有关,其实就是时间复杂度和空间复杂度。

    时间复杂度

    基本操作重复执行的次数是问题规模n的某个函数,其时间量度记作 T(n)=O(f(n)),称作算法的渐近时间复杂度(Asymptotic Time complexity),简称时间复杂度。
     "O"的定义: 若f(n)是正整数n的一个函数,则 O(f(n))表示 M≥0 ,使得当n ≥ n0时,| f(n) | ≤ M | f(n0) | 。
    表示时间复杂度的阶有:
    O(1) :常量时间阶
    O (n):线性时间阶
    O(㏒n) :对数时间阶
    O(n㏒n) :线性对数时间阶
    O (n^k): k≥2 ,k次方时间阶

    下面看个例子:

        for(i=1,i<=n; ++i)  {
             for(j=1; j<=n; ++j)  {
                 c[i][j]=0 ;
                   for(k=1; k<=n; ++k)  {
                        c[i][j]+=a[i][k]*b[k][j] ;  
                    }
              }
        }
    
    

    由于是一个三重循环,每个循环从1到n,则总次数为: n×n×n=n3 时间复杂度为T(n)=O(n3)

    空间复杂度

    空间复杂度(Space complexity) :是指算法编写成程序后,在计算机中运行时所需存储空间大小的度量。记作: S(n)=O(f(n))
    其中: n为问题的规模(或大小)
    该存储空间一般包括三个方面:

    • 指令常数变量所占用的存储空间;
    • 输入数据所占用的存储空间;
    • 辅助(存储)空间。
    • 一般地,算法的空间复杂度指的是辅助空间。
    • 一维数组a[n]: 空间复杂度 O(n)
    • 二维数组a[n][m]: 空间复杂度 O(n*m)

    冒泡排序

    排序思想
     依次比较相邻的两个记录的关键字,若两个记录是反序的(即前一个记录的关键字大于后前一个记录的关键字),则进行交换,直到没有反序的记录为止。
    ① 首先将L->R[1]与L->R[2]的关键字进行比较,若为反序(L->R[1]的关键字大于L->R[2]的关键字),则交换两个记录;然后比较L->R[2]与L->R[3]的关键字,依此类推,直到L->R[n-1]与L->R[n]的关键字比较后为止,称为一趟冒泡排序,L->R[n]为关键字最大的记录。
    ② 然后进行第二趟冒泡排序,对前n-1个记录进行同样的操作。

    排序示例
    设有9个待排序的记录,关键字分别为23, 38, 22, 45, 23, 67, 31, 15, 41,冒泡排序的过程如下图所示

    Paste_Image.png

    算法实现:

    /**
         * 冒泡排序
         *
         * @param data
         */
        public static void bubbleSort(int[] data) {
    
            for (int i = 0; i < data.length - 1; i++) {
                for (int j = 0; j < data.length - 1 - i; j++) {
                    if (data[j] > data[j + 1]) {
                        int temp = data[j];
                        data[j] = data[j + 1];
                        data[j + 1] = temp;
                    }
                }
            }
        }
    

    快速排序

    排序思想

    通过一趟排序,将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,再分别对这两部分记录进行下一趟排序,以达到整个序列有序。

    排序过程

    设待排序的记录序列是R[s…t] ,在记录序列中任取一个记录(一般取R[s])作为参照(又称为基准或枢轴),以R[s].key为基准重新排列其余的所有记录,方法是:

    • 所有关键字比基准小的放R[s]之前;
    • 所有关键字比基准大的放R[s]之后。
      以R[s].key最后所在位置i作为分界,将序列R[s…t]分割成两个子序列,称为一趟快速排序。

    一趟快速排序方法

    从序列的两端交替扫描各个记录,将关键字小于基准关键字的记录依次放置到序列的前边;而将关键字大于基准关键字的记录从序列的最后端起,依次放置到序列的后边,直到扫描完所有的记录。
     设置指针low,high,初值为第1个和最后一个记录的位置。
     设两个变量i,j,初始时令i=low,j=high,以R[low].key作基准(将R[low]保存在R[0]中) 。
    ① 从j所指位置向前搜索:将R[0].key与R[j].key进行比较:

    • 若R[0].key≤R[j].key :令j=j-1,然后继续进行比较, 直到i=j或R[0].key>R[j].key为止;
    • 若R[0].key>R[j].key :R[j]R[i],腾空R[j]的位置, 且令i=i+1;
      ② 从i所指位置起向后搜索:将R[0].key与R[i].key进行比较:
    • 若R[0].key≥R[i].key :令i=i+1,然后继续进行比较, 直到i=j或R[0].key<R[i].key为止;
    • 若R[0].key<R[i].key :R[i]R[j],腾空R[i]的位置, 且令j=j-1;
      ③ 重复①、②,直至i=j为止,i就是R0所应放置的位置。

    一趟排序示例

    设有6个待排序的记录,关键字分别为29, 38, 22, 45, 23, 67,一趟快速排序的过程如图下图所示。

    Paste_Image.png

    算法实现:

    /**
         * 查找中轴所在位置
         *
         * @param data
         * @param low
         * @param high
         * @return
         */
        public static int getMiddle(int[] data, int low, int high) {
            //取第一个元素作为基准点
            int key = data[low];
            while (low < high) {
                //从后半部分向前扫描
                while (data[high] >= key && high > low) {
                    high--;
                }
                //比中轴小的记录移到低端
                data[low] = data[high];
                //从前半部分向后扫描
                while (data[low] <= key && high > low) {
                    low++;
                }
                //比中轴大的记录移到高端
                data[high] = data[low];
            }
            data[low] = key;
            // 返回中轴的位置
            return low;
        }
    
        /**
         * 递归形式的分治排序算法
         *
         * @param data
         * @param low
         * @param high
         */
        public static void quickSort(int[] data, int low, int high) {
            if (low < high) {
                //将数组一分为二
                int index = getMiddle(array, low, high);
                quickSort(array, low, index - 1);
                quickSort(array, index + 1, high);
            }
        }
    
    

    选择排序

    选择排序(Selection Sort)的基本思想是:每次从当前待排序的记录中选取关键字最小的记录表,然后与待排序的记录序列中的第一个记录进行交换,直到整个记录序列有序为止。
      简单选择排序(Simple Selection Sort ,又称为直接选择排序)的基本操作是:通过n-i次关键字间的比较,从n-i+1个记录中选取关键字最小的记录,然后和第i个记录进行交换,i=1, 2, … n-1 。

    设有关键字序列为:7, 4, -2, 19, 13, 6,直接选择排序的过程如下图所示。


    Paste_Image.png

    算法实现:

     /**
         * @param data
         */
        public static void selectSort(int[] data) {
            for (int i = 0; i < data.length; i++) {
                //待确定的位置
                int k = i;
                // 选最小的记录
                for (int j = k + 1; j < data.length; j++) {
                    if (data[j] < data[k]) {
                        k = j;
                    }
                }
                //交换a[i]和a[k]
                if (i != k) {
                    int temp = data[i];
                    data[i] = data[k];
                    data[k] = temp;
                }
            }
        }
    

    插入排序

    采用的是以 “玩桥牌者”的方法为基础的。即在考察记录Ri之前,设以前的所有记录R1, R2 ,…., Ri-1已排好序,然后将Ri插入到已排好序的诸记录的适当位置。
    最基本的插入排序是直接插入排序(Straight Insertion Sort) 。

    排序思想

    将待排序的记录Ri,插入到已排好序的记录表R1, R2 ,…., Ri-1中,得到一个新的、记录数增加1的有序表。 直到所有的记录都插入完为止。
    设待排序的记录顺序存放在数组R[1…n]中,在排序的某一时刻,将记录序列分成两部分:

    • R[1…i-1]:已排好序的有序部分;
    • R[i…n]:未排好序的无序部分。
      显然,在刚开始排序时,R[1]是已经排好序的。

    设有关键字序列为:7, 4, -2, 19, 13, 6,直接插入排序的过程如下图所示:


    Paste_Image.png

    算法实现:

     /**
         * 
         * @param data
         */
        public static void insertionSorts(int[] data) {
            for (int i = 1; i < data.length; i++) {
                int temp = data[i];
                int j = i - 1;
                // 从右到左扫描有序区
                while (j >= 0 && temp < data[j]) {
                    // 将左侧有序区中元素比array[i]大的array[j+1]后移
                    data[j + 1] = data[j];
                    j--;
                }
                // 将右侧无序区第一个元素tmp = array[i]放到正确的位置上
                data[j + 1] = temp;
            }
        }
    
    

    相关文章

      网友评论

          本文标题:排序算法算法总结

          本文链接:https://www.haomeiwen.com/subject/gethottx.html