算法基础 排序(一)

桶排序
冒泡排序
快速排序

1.桶排序

所谓的桶排序就是列出所有的可能进行排序

        //9,4,2,7,5,2,9,10,1   用来排序的数组  并且确定这些数字的可能为0到10的整数
        int arr[] = {9,4,2,7,5,2,9,10,1};
        //声明11个桶,对应所有的可能
        int bucketArr[11] = {0};
        //用来打印的数组
        NSMutableString *reslutStr = [NSMutableString string];
        //确定用来排序的数组的个数
        int count = sizeof(arr)/4;
        //遍历要排序的数组,比如遍历到一个数是5,那么就在5(bucketArr[5])对应的那个桶加1
        int i;
        for (i = 0; i < count; i++) {
            bucketArr[arr[i]]++;
        }
        //遍历所有的桶,如果第6个桶(bucketArr[5])对应的数字是2,那就输出两个5
        int j;
        for (i = 0; i < 11; i++) {
            for (j = 0; j < bucketArr[i]; j++) {
                //结果加到可变字符串中
                [reslutStr appendFormat:@"%d ",i];
            }
        }
        //打印结果
        NSLog(@"%@",reslutStr);

桶排序结果.png

(可以忽略第一句话,只是说明程序可以换种输入方式)
上面的程序中,你可以放一个输入函数,直接确定输入n个数,然后每次输入直接加到对应的桶里面.
但是我们依然要执行n次的将数放入桶中,
再执行m次的遍历桶和n次的把数字加到可变数组中.m为桶的个数.
所以时间复杂度就是m+2n.我们在计算时间复杂度时会忽略较小的常数.所以最终的时间复杂度就是O(M+N)

小结:这里的桶排序只是简化版的.桶排序是所有排序中最快的,当然是大多数情况下.当然也有一些缺点,比如他很费内存.因为他要列出所有的可能.比如可能性必须是有限的,出现小数他就没辙了.

2.冒泡排序

冒泡排序就是比较相邻两个数进行排序

        //9,4,2,7,5,2,9,10,1,53,32,24  从大到小排序
        int arr[] = {9,4,2,7,5,2,9,10,1,53,32,24};
        //得到数组元素个数
        int count = sizeof(arr)/4;
        int i,j,sub;
        for (j = 0; j < count - 1; j++) {//比如{3,5,2,6} 如果你要把6移到第一个位置,你需要重复排序3遍 所以这里重复count-1次
            for (i = 0; i < count - 1; i++) {//重头到尾排一遍
                if (arr[i] < arr[i+1]) {
                    //交换位置
                    sub = arr[i];
                    arr[i] = arr[i+1];
                    arr[i+1] = sub;
                }
            }
        }
        //数组遍历打印
        for (i = 0; i < count; i++) {
            printf("%d ",arr[i]);
        }
        
冒泡排序结果.png

这里如果我们有n个数需要进行排序,那么我们一次排序需要进行n-1遍,然后需要重复排序n-1次才能保证完全排序.一共需要(n-1)²
所以这里我们的时间复杂度就是O(N²)

小结:冒泡排序除了逻辑简单以外,就没什么优点了.他的时间复杂度让人很失望.

3.快速排序

快速排序用的是分治合并的思想(不知道有没有这种思想,我觉得这么说挺通的,😈😈😈)


int arr[] = {9,4,2,7,5,2,9,10,1,53,32,24};
        int count = sizeof(arr)/4;
        //找一个基准数 为了方便就把第一个数当做基准数 然后将比基数小的放基数左边,比基数大的放基数右边
        int i = 1;
        int j = count - 1;
        int base = arr[0];
        int sub ;
        
        while(i!=j)
        {
            //让j先进行探测,能确保最后一次交换是将基数与比基数小的值交换
            while(arr[j]>=base && i<j)
                j--;
            //再从左往右找
            while(arr[i]<=base && i<j)
                i++;
            //交换两个数在数组中的位置
            if(i<j)//当i!=j
            {
                sub=arr[i];
                arr[i]=arr[j];
                arr[j]=sub;
            }
        }
        //相等交换基数
        
        arr[0]=arr[i];
        arr[i]=base;

这里是快速排序的一次排序,一次排序过后我们等到两个数组,基数左边和右边,然后我们需要对其进行再排序,于是就想到用递归.毕竟你不好用循环做.
当只有一个数的时候跳出递归
整理后得到

//9,4,2,7,5,2,9,10,1,53,32,24  从小到大排序
int arr[] = {9,4,2,7,5,2,9,10,1,53,32,24};

void quickSort(int left,int right){
    if (left >= right) {
        return;
    }
    int base = arr[left];
    int i = left;
    int j = right;
    int sub;
    while(i!=j)
    {
        //让j先进行探测,能确保最后一次交换是将基数与比基数小的值交换
        while(arr[j]>=base && i<j)
            j--;
        //再从左往右找
        while(arr[i]<=base && i<j)
            i++;
        //交换两个数在数组中的位置
        if(i<j)//当i!=j
        {
            sub=arr[i];
            arr[i]=arr[j];
            arr[j]=sub;
        }
    }
    //相等交换基数
    
    arr[left]=arr[i];
    arr[i]=base;
    quickSort(left, i-1);
    quickSort(i+1, right);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        
        int count = sizeof(arr)/4;
        quickSort(0, count-1);
        for (int i = 0; i < count; i++) {
            printf("%d ",arr[i]);
        }
        
    }
  
快速排序结果.png

接下来就谈谈他的时间复杂度
http://www.cnblogs.com/pugang/archive/2012/07/02/2573075.html
这篇博客里对其进行了一定的说明,他是用一个公式来说明的.

然后我想说的是,我换种方式,自己计算了一下他的时间复杂度,要是错了(反正我觉得不会有多少人来看),你说我就改.
首先第一次排序,最好的是分成平均分成两部分 那么第一次排序进行了n/2次 确定了1个数字的位子.
第二次排序 也是进行了n/2次 这里的是算上两部分一共的次数,确立的两个数字
第三次...
然后得到

第1次 运行n/2 确立2^0个数字
第2次 运行n/2 确立2^1个数字
第3次 运行n/2 确立2^2个数字
...
第x次 运行n/2 确立2^(x-1)个数字
此时满足 2^0 + 2^1 +2^2 + 2^ 3 +...+2^(x-1) = n;
解得 x = log(n+1) 这里2为默认底.
然后时间复杂度就是 x * n/2 = n/2 log(n+1)
计算时间复杂度时忽略较小的数字 所以就得到O(nlogn).

而最坏的结果是每一次选中的基数都是最大或者最小的数,然后相当于每次运行n-1 ,n-2,n-3,n-4,n-5..所以我们可以认为程序一共执行了(n^2 - n)/2 次 所以时间复杂度就是O(N^2).

小结:快速排序是一个好算法,比起桶排序省空间,比起冒泡则快了太多.所以这是一个用的非常多的算法.


总结:我也是刚开始学,有什么不对的,你说我就改!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容