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;
                }
            }
        }
    }

      

      

  • 相关阅读:
    C#获取HTML文件指定DIV内容
    剔除editor编辑器中的HTML标签
    ASP.NET MVC 在WebService中Token的使用方法
    MVC如何在单独的类库中添加区域
    原来写插件还可以选MEF
    EF CodeFirst学习
    .Net EF 学习之model first
    sql分页存储过程,带求和、排序
    软实力
    微软的XML可视化编辑器:XML Notepad 2007
  • 原文地址:https://www.cnblogs.com/sy-liu/p/13278719.html
Copyright © 2011-2022 走看看