算法基础 排序(一)

作者: 比沉默寡言话多 | 来源:发表于2016-09-22 13:06 被阅读83次

    桶排序
    冒泡排序
    快速排序

    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).

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


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

    相关文章

      网友评论

        本文标题:算法基础 排序(一)

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