快速排序 C#实现

using System;
using System.Collections.Generic;

namespace quick_sort
{
    public static class Sort
    {//升序排列
        public static void Quick_Sort_low(int[] list, int left, int right)
        {//性能偏弱
            if (left < right)//注意递归退出条件
            {
                int p = list[left];//p是将list[left:right+1]分段的参考值,
                int l = left;//因为在之后的递归中还需要left和right作为入参
                int r = right;//所以不能改变left和right的原始值
                while (l < r)
                {
                    while (l < r && p <= list[r])
                        r--;
                    if (l < r)
                    {//运行到这里,必然有p>left[r]
                        list[r] = list[l] + list[r];
                        list[l] = list[r] - list[l];
                        list[r] = list[r] - list[l];//不使用中间变量进行值交换
                        l++;
                    }//实际上是p的值和left[r]交换,即if语句完成后参考值p=list[r]
                    while (l < r && p >= list[l])
                        l++;
                    if (l < r)
                    {//运行到这里,必然有p<left[l]
                        list[r] = list[l] + list[r];
                        list[l] = list[r] - list[l];
                        list[r] = list[r] - list[l];//不使用中间变量进行值交换
                        r--;
                    }//实际上是p的值和left[l]交换,即if语句完成后参考值p=list[l]
                }
                Quick_Sort_low(list, left, l - 1);
                Quick_Sort_low(list, r + 1, right);
                //此处,l必等于r,且p=list[l]=list[r]
                //同时p>=list[left:l],p<=list[r+1,right],所以p不必再参与之后的排序过程
            }
        }
        public static void Quick_Sort_low_2(int[] list, int left, int right)
        {//性能偏弱
            if (left < right)//注意递归退出条件
            {
                //此段代码隐藏了p=list[left]这个声明,但实质上仍然是这样的
                int l = left;//因为在之后的递归中还需要left和right作为入参
                int r = right;//所以不能改变left和right的原始值
                while (l < r)
                {
                    //此处list[l]必等于p
                    while (l < r && list[l] <= list[r])
                        r--;
                    if (l < r)
                    {
                        list[r] = list[l] + list[r];
                        list[l] = list[r] - list[l];
                        list[r] = list[r] - list[l];//不使用中间变量进行值交换
                        l++;
                    }
                    //此处list[r]必等于p
                    //也许有人想问会不会出现上一条的if语句为假,我的回答是:
                    //可能为假,但为假意味着l==r为真,即应该做的是循环结束,继续递归。
                    while (l < r && list[r] >= list[l])
                        l++;
                    if (l < r)
                    {
                        list[r] = list[l] + list[r];
                        list[l] = list[r] - list[l];
                        list[r] = list[r] - list[l];//不使用中间变量进行值交换
                        r--;
                    }
                    //此处list[l]必等于p
                    //然后进入下一个循环,下一个循环的初始条件与上一个循环结束时的条件恰好相等
                }
                Quick_Sort_low_2(list, left, l - 1);
                Quick_Sort_low_2(list, r + 1, right);
                //此处,l必等于r,且p=list[l]=list[r]
                //同时p>=list[left:l],p<=list[r+1,right],所以p不必再参与之后的排序过程
            }
        }
        public static void Quick_Sort_up(int[] list, int left, int right)
        {//性能优于Quick_Sort_low
            if (left < right)
            {
                int p = list[left];//取最左侧的值作为分段参考
                int l = left;
                int r = right;
                while (l < r)
                {
                    while (l < r && p <= list[r])
                        r--;
                    //从r开始向左找,直到找到一个比p大的数
                    while (l < r && p >= list[l])
                        l++;
                    //从l开始向右找,直到找到一个比p小的数
                    if (l < r)
                    {
                        list[r] = list[l] + list[r];
                        list[l] = list[r] - list[l];
                        list[r] = list[r] - list[l];//不使用中间变量进行值交换
                        //此处是将一个比p小的数和一个比p大的数进行交换
                    }
                }
                //执行到此处,必有l=r
                list[left] = list[l];
                list[r] = p;//想想为什么需要这两句代码,为什么没有p与list[l]的大小问题?
                //因为分段是以p作为参考进行分段的,而不是以list[l]作为的参考,所以list[l]不应该在这里
                //因为无论如何循环,最后都会回归到
                //当l+1=r时的list[l]与list[r]的大小与p的比较问题
                //一:若p>list[l],p<list[r],则r=r-1,r会等于l,此时list[l]必小于p
                //二:若p<list[l],p>list[r],则会将list[l]和list[r]的值交换,并跳到一
                //三:若p>list[l],p>list[r],条件不可能成立
                //四:若p<list[l],p<list[r],条件也不可能成立

                Quick_Sort_up(list, left, l - 1);
                Quick_Sort_up(list, r + 1, right);
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Random m = new Random();
            List<int> list = new List<int>();
            for (int i = 0; i < 20000000; i++)
            {
                list.Add(m.Next(10000));
            }
            Console.WriteLine("\n");
            DateTime test_time = DateTime.Now;//
            {
                int[] new_array = list.ToArray();//转为数组
                //因为链表是逻辑连续,数组是存储结构连续,所以数组适合排序
                DateTime b_time = DateTime.Now;
                Sort.Quick_Sort_low(new_array, 0, new_array.Length - 1);
                DateTime a_time = DateTime.Now;
                TimeSpan time = a_time.Subtract(b_time);
                Console.WriteLine(time);
            }
            {
                int[] new_array = list.ToArray();//转为数组
                //因为链表是逻辑连续,数组是存储结构连续,所以数组适合排序
                DateTime b_time = DateTime.Now;
                Sort.Quick_Sort_low_2(new_array, 0, new_array.Length - 1);
                DateTime a_time = DateTime.Now;
                TimeSpan time = a_time.Subtract(b_time);
                Console.WriteLine(time);
            }
            {
                int[] new_array = list.ToArray();//转为数组
                //因为链表是逻辑连续,数组是存储结构连续,所以数组适合排序
                DateTime b_time = DateTime.Now;
                Sort.Quick_Sort_up(new_array, 0, new_array.Length - 1);
                DateTime a_time = DateTime.Now;
                TimeSpan time = a_time.Subtract(b_time);
                Console.WriteLine(time);
            }
        }
    }
}

以2000万个0~9999的随机数进行测试:



00:00:53.3620840
00:00:59.9160950
00:00:50.0931710

Press any key to continue...
    快速排序,什么是快速排序?
    百度百科定义:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
    下面用通俗易懂的语言来描述快速排序的实现过程。根据定义,在每一趟排序要将所排序的内容分割成两个部分,且必须满足某一部分的所有数据都得不小于另一部分的所有数据(为什么与定义不符?因为完全可能存在要排序的数据是完全相等的)。所以可以这样更改定义,在每一趟排序结束后,左侧部分数据都不得大于右侧任一数据。
    根据前面的分析,每一趟排序结束后,左侧部分数据都不得大于右侧任一数据,并不会再每趟排序时使所排数据有序。而是以左段数据和右段数据有一个逻辑上的大小关系,这样,通过n趟排序之后,会出现这样的现象,分段到最后就是分两个数的大小顺序,即此时该段数据自动有序。排序函数运行结束之后,所有数据自动有序。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • 快速排序步骤: 首先,对于一个无序数组,开始时选取一个数(通常是首位)作为我们判断的依据。 从尾端往前遍历,找出一...
    曲谐_阅读 1,170评论 0 0
  • 每个在省外上学的遵义人,大概都对羊肉粉有一种执念,在学校想着它的味道,必定下决心放假回家一定要多来几碗。早...
    小辣狗阅读 961评论 0 0
  • 不是找到工作,就是可以做一辈子的。工作好找,好工作难找。 接下来该做什么,难道为了这点工资就心满意足,心满意足吗?...
    两个圆圈三种图阅读 341评论 0 0
  • 本次学习目标: 目标词汇:Drinks: milk, water, tea, coffee, juice, mil...
    TimmySHENX阅读 169评论 0 0
  • 回家的路即长,又短! 在这个寒冬,无论资本、温度、人心、岁月! 2月3号,大概用飞猪刷了30天的票,结果刷到个23...
    小宁静致远阅读 296评论 5 2