zoukankan      html  css  js  c++  java
  • C#排序算法之快速排序

    排序规则:

      1、从数列中挑出一个元素称为“基准”(privot)(一般用数组的第一个位置);

      2、重新排序数列,所有元素比基准小的摆放在基准前面,所有元素比基准大的摆放在基准后面(相同的数可以放到任一边)。在这个分区退出后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

      3、递归地(recursive)把小于基准元素的子数列和大于基准值元素的子数列排序

    时间复杂度:

      平均时间复杂度:O(nlogn) 最好情况:O(nlogn); 最坏情况: O(n^2)

    namespace 排序算法
    {
        class QuickSort1
        {
            public static void Sort(int[] arr)
            {
                int n = arr.Length;
                Sort(arr, 0, n - 1);
            }
            private static void Sort(int[] arr, int l, int r)
            {
                if(r - l + 1 <=15 )
                {
                    InsertSort(arr, l, r);
                    return;
                }
                //if(l >= r)
                //{
                //    return;
                //}
                //标准元素
                int v = arr[l];
                int j = l; // arr[1+l,2+l,...,j] < v  arr[j+1....,i-l] >v
                for(int i = l + 1; i <= r; i++)
                {
                    if(arr[i] < v)
                    {
                        j++;
                        Swap(arr, i, j);
                    }
                }
                Swap(arr, l, j);
                Sort(arr, l, j - 1);
                Sort(arr, j + 1, r);
            }
            private static void Swap(int[] arr, int i, int j)
            {
                int e = arr[i];
                arr[i] = arr[j];
                arr[j] = e;
            }
    
            //插入排序
            public static void InsertSort(int[] arr, int l, int r)
            {
                for (int i = l + 1; i <= r; i++)
                {
                    int e = arr[i];
                    int j;
                    for (j = i; j > l; j--)
                    {
                        if (e < arr[j - 1])
                        {
                            arr[j] = arr[j - 1];
                        }
                        else
                        {
                            break;
                        }
                    }
                    arr[j] = e;
                }
            }
        }
    }

    上面的代码由于基准元素使用的是数组中的第一个,当数组近乎有序时,排序时造成栈的深度会很深(甚至当数组很大时可能会造成栈溢出),而且消耗时间会很多时间复杂度接近O(n^2)

    优化:首先基准元素由数组中第一个元素改为随机设定基准元素

    using System;
    namespace 排序算法
    {
        /*
         * 优化快速排序:
         *      基准元素由数组中第一个元素改为随机设定基准元素
         */
        class QuickSort2
        {
            private static Random rd = new Random();
            public static void Sort(int[] arr)
            {
                int n = arr.Length;
                Sort(arr, 0, n - 1);
            }
            private static void Sort(int[] arr, int l, int r)
            {
                if(r - l + 1 <=15 )
                {
                    InsertSort(arr, l, r);
                    return;
                }
                //if(l >= r)
                //{
                //    return;
                //}
                //基准元素
                int p = l + rd.Next(r - l + 1);
                Swap(arr, l, p);
                int v = arr[l];
                int j = l; // arr[1+l,2+l,...,j] < v  arr[j+1....,i-l] >v
                for(int i = l + 1; i <= r; i++)
                {
                    if(arr[i] < v)
                    {
                        j++;
                        Swap(arr, i, j);
                    }
                }
                Swap(arr, l, j);
                Sort(arr, l, j - 1);
                Sort(arr, j + 1, r);
            }
            private static void Swap(int[] arr, int i, int j)
            {
                int e = arr[i];
                arr[i] = arr[j];
                arr[j] = e;
            }
    
            //插入排序
            public static void InsertSort(int[] arr, int l, int r)
            {
                for (int i = l + 1; i <= r; i++)
                {
                    int e = arr[i];
                    int j;
                    for (j = i; j > l; j--)
                    {
                        if (e < arr[j - 1])
                        {
                            arr[j] = arr[j - 1];
                        }
                        else
                        {
                            break;
                        }
                    }
                    arr[j] = e;
                }
            }
        }
    }

    如果数组中含有大量重复元素的数组,还是会造成递归深度很深(甚至会造成栈溢出),时间复杂度也是接近O(n^2)

    解决方案:

      使用三向切分的快速排序:将数组切分成三个部分分别对应小于,等于,大于基准元素。

    using System;
    namespace 排序算法
    {
        /*
         * 优化快速排序:
         */
        class QuickSort3
        {
            private static Random rd = new Random();
            public static void Sort(int[] arr)
            {
                int n = arr.Length;
                Sort(arr, 0, n - 1);
            }
            private static void Sort(int[] arr, int l, int r)
            {
                if( r - 1 + 1 <=15)
                {
                    InsertSort(arr, l, r);
                    return;
                }
                int p = l + rd.Next(r - l + 1);
                Swap(arr, l, p);
                //基准元素
                int v = arr[l];
                int lt = l; // arr[l+1,...,lt] < v
                int gt = r + 1;// arr[gt, ..., r] > v;
                int i = l + 1; // arr[lt + 1,...,i-1] == v
                while( i < gt)
                {
                    if(arr[i] < v)
                    {
                        lt++;
                        Swap(arr, i, lt);
                        i++;
                    }else if( arr[i] > v)
                    {
                        gt--;
                        Swap(arr, i, gt);
                        i++;
                    }
                    else
                    {
    
                        i++;
                    }
                     
                }
                Swap(arr, l, lt);
                Sort(arr, l, lt - 1);
                Sort(arr, gt, r);
            }
            private static void Swap(int[] arr, int i, int j)
            {
                int e = arr[i];
                arr[i] = arr[j];
                arr[j] = e;
            }
    
            //插入排序
            public static void InsertSort(int[] arr, int l, int r)
            {
                for (int i = l + 1; i <= r; i++)
                {
                    int e = arr[i];
                    int j;
                    for (j = i; j > l; j--)
                    {
                        if (e < arr[j - 1])
                        {
                            arr[j] = arr[j - 1];
                        }
                        else
                        {
                            break;
                        }
                    }
                    arr[j] = e;
                }
            }
        }
    }

      

      

  • 相关阅读:
    Bootstrap 2.2.2 的新特性
    Apache POI 3.9 发布,性能显著提升
    SQL Relay 0.48 发布,数据库中继器
    ProjectForge 4.2.0 发布,项目管理系统
    红帽企业 Linux 发布 6.4 Beta 版本
    红薯 快速的 MySQL 本地和远程密码破解
    MariaDB 宣布成立基金会
    Percona XtraBackup 2.0.4 发布
    Rocks 6.1 发布,光盘机群解决方案
    精通Servlet研究,HttpServlet的实现追究
  • 原文地址:https://www.cnblogs.com/sy-liu/p/13278719.html
Copyright © 2011-2022 走看看