zoukankan      html  css  js  c++  java
  • 排序算法总结----比较类排序

    概述:排序算法可分为比较性的排序,以及运算性的排序;这里详细介绍这些排序的原理,性能,实现,以及应用场合。

    前面是维基百科的介绍,这里介绍几个比较典型的算法。

    理论

    交换排序

    选择排序

    插入排序

    归并排序

    分布排序

    并发排序

    混合排序

    其他

    以下介绍典型的算法:::::----》》》》

    比较排序

    一:快速排序(交换排序2号)

    1:原理

    采用了分治思想,在序列A[p...r]中选取一个元素,当然这里是用了p或者r处的元素(规格一致);找到该元素的,满足前面的值都比它小,后面的都比它大;同理让子序列递归下去。

    2:性能

    最坏时间复杂度:θ(n²)---出现在序列是顺序的,导致极度不平衡划分,1:0效果划分。

    最好时间复杂度:θ(nlog2(n))---出现在每次划分都是在中间处;

    中间状态:比如划分比例是a:b;则复杂度就是a/(b+a);b/(b+a)取大的(假设为a/(b+a)),则复杂度为θ(nlog(b+a)/a(n))其实也可以是θ(nlog(n))

    平均复杂度也就是θ(nlog(n));

    空间复杂度为:O(logn)----递归引起;

    3:应用

    实际排序中比较好,适合对平均时间复杂度有要求,要求原址排序,且隐含因子比较小;应用场景多。百万数量级以下合适

    4:实现----c++代码实现如下

    void exchang(int * sort,int i,int j)
    {
        int temp=0;
        temp=sort[i];
        sort[i]=sort[j];
        sort[j]=temp;
    }
    int partition(int *sort ,int p,int r)
    {
        int x=sort[r];
        int i=p-1;
        for(int j=p;j<r;j++)//p--->r-1
        if(sort[j]<=x)
        {
            i++;
            if(i!=j)
                exchang(sort,i,j);
        }
        if((i+1)<r)
            exchang(sort,i+1,r);    
        return i+1;
    }
    //栈溢出,原因是它递归太深了
    void QuickSort(int *sort ,int sn,int en)
    {
        if(sn<en)
        {
            int q=partition(sort,sn,en);
            QuickSort(sort,sn,q-1);
            QuickSort(sort,q+1,en);
        }
    }

    第二:插入排序

     4:实现

            /// <summary>
            /// 插入排序
            /// </summary>
            /// <param name="unsorted"></param>
            static void insertion_sort(int[] unsorted)
            {
                for (int i = 1; i < unsorted.Length; i++)
                {
                    if (unsorted[i - 1] > unsorted[i])
                    {
                        int temp = unsorted[i];
                        int j = i;
                        while (j > 0 && unsorted[j - 1] > temp)
                        {
                            unsorted[j] = unsorted[j - 1];
                            j--;
                        }
                        unsorted[j] = temp;
                    }
                }
            }

    第三:归并排序

     4:实现

    void merge(int * a,int p,int q,int r)
    {
        int n1=q-p+1;
        int n2=r-q;
        int * left=new int[n1+1];
        int * right=new int[n2+1];
        for(int i=0;i<=n1;i++)
            left[i]=a[p+i];
        for(int i=0;i<=n2;i++)
            right[i]=a[q+i+1];
        left[n1]=INT_MAX;
        right[n2]=INT_MAX;
        int n=0,m=0;
        for(int k=p;k<=r;k++)
        {
            if(left[n]<=right[m])
            {
                a[k]=left[n];
                n++;
            }
            else
            {
                a[k]=right[m];
                m++;
            }
        }
        delete [] left;
        delete [] right;
    }
    void mergesort(int * a,int p,int r)
    {
        if(p<r)
        {
            int q=(p+r)/2;
            mergesort(a,p,q);
            mergesort(a,q+1,r);
            merge(a,p,q,r);
        }
    }
      

    第四:堆排序

    1:原理

    2:性能

    3:应用

    4:实现

    //数据交换 
    void Exchang(int * sort,int i,int j)
    {
        int temp=0;
        temp=sort[i];
        sort[i]=sort[j];
        sort[j]=temp;
    }
    //修改堆
    void MaxHeapIfy(int *ops,int i,int heapsize)
    {
        int l=2*i+1;//left
        int r=2*(i+1);
    
        int max;
        if((l<=heapsize-1)&&ops[l]>ops[i])
            max=l;
        else
            max=i;
        if((r<=heapsize-1)&&ops[r]>ops[max])
            max=r;
        if(max!=i)
        {
            exchang(ops,i,max);
            maxheapify(ops,max,heapsize);
        }
    
    }
    //构建堆
    void BuildMaxHeap(int *ops,int length)
    {
        for(int i=(length-2)/2;i>=0;i--)
            maxheapify(ops,i,length);
    }
    //树也有递归,但是树本身不会那么深。
    void HeapSort(int *ops,int length)
    {
        buildmaxheap(ops,length);
        for(int i=length-1;i>=1;i--)
        {
            exchang(ops,0,i);
            length--;
            maxheapify(ops,0,length);
        }
    }

    第五:选择排序

    1:原理

    通过比较,先找出最大值或者最小值,找到后就将其放到队首,这样下来就是顺序的了。

    2:性能

    最差时间复杂度О(n²)

    最优时间复杂度О(n²)

    平均时间复杂度О(n²)

    空间复杂度:1

    3:应用

    n小时比较合适,算法简单,是比较后排序;使用场合少

    4:c++实现

    void SelectionSort(int* unsorted,int length)
    {
        for (int i = 0; i < length; i++)
        {
            int min = unsorted[i], min_index = i;
            for (int j = i; j < length; j++)
            {
                if (unsorted[j] < min)//选择最小值处
                {
                    min = unsorted[j];
                    min_index = j;
                }
            }
            if (min_index != i)//选出后交换
            {
                int temp = unsorted[i];
                unsorted[i] = unsorted[min_index];
                unsorted[min_index] = temp;
            }
        }
    }

    第六:冒泡排序(交换排序1号)

    1:原理

    通过比较,不断冒充最大值或者最小值,它和选择排序相似,选择排序是先找最小值,再交换;而冒泡是比较一次就会交换,从效率上将,冒泡排序不如选择排序。

    2:性能

    最差时间复杂度O(n^2)

    最优时间复杂度O(n)为什么是这个值,因为可以往后冒泡,产生的结果就可以达到这个效果。。。。

    平均时间复杂度O(n^2)

    3:应用

    应用类似插入算法

    4:实现

    1)往前冒泡

    void BubbleSort(int *unsorted,int length)
    {
        for (int i = 0; i <length ; i++)
        {
            for (int j = i; j < length; j++)
            {
                if (unsorted[i] > unsorted[j])
                {
                    int temp = unsorted[i];
                    unsorted[i] = unsorted[j];
                    unsorted[j] = temp;
                }
            }
        }
    }

    2)往后冒泡(C#)

    public void bubbleSort(int arr[]) {
        boolean didSwap;
        for(int i = 0, len = arr.length; i < len - 1; i++) {
            didSwap = false;
            for(int j = 0; j < len - i - 1; j++) {
                if(arr[j + 1] < arr[j]) {
                    swap(arr, j, j + 1);
                    didSwap = true;
                }
            }
            if(didSwap == false)
                return;
        }    
    }

    第七:希尔排序

    1:原理

    通过分组排序,比如以某个增量d,也就是分成d组,在d组内中进行插入排序;不断让d减小,使的最后为1,也就是到达了直接排序效果;和插入比较有何体现呢?插入最坏是O(n²),最好是O(n)。但是在n小时相差不大,这就是用分组减小n,而后期的组数少了,但是排序好了,则会走向好的情况,故而总体是效率高了。

    2:性能

    最坏时间复杂度:O(ns),s大致是1~2;

    平均时间复杂度:O(nlog(n));

    最好时间复杂度:O(n)

    注:n较大时目前一般是n1.25到1.6n1.25之间。

    3:应用

    它优于插入算法,不稳定。

    4:实现

    //
    //采取2的k次幂-1是最佳的,k表示第几趟
    //最后一个步长是1
    //k是趟数,这个可以自己设定。。。。
    //
    
    //通俗版本,比较简单
    void ShellSort(int* a, int length)  
    {  
        int gap; //增量,,组 
        for(gap = 3; gap >0; gap--)  //3组。。。自己也可以设定大一点组,
        {  
            for(int i=0; i<gap; i++)  //显然这种分组的步长是1
            {  
                for(int j = i+gap; j<length; j=j+gap)  //
                {  
                    if(a[j]<a[j-gap])  
                    {  
                        int temp = a[j];  
                        int k = j-gap;  
                        while(k>=0&&a[k]>temp)  
                        {  
                            a[k+gap] = a[k];  
                            k = k-gap;  
                        }  
                        a[k+gap] = temp;  
                    }  
                }  
            }  
        }  
    }
    //通用版本,,比较灵活
    void ShellSort(int a[], int n , int d[] ,int numOfD)
    {
    
        int i,j,k;
        int val;
        int span;    //增量
        for(int m=0; m<numOfD; m++)        //m趟
        {
            span=d[m];
            for(k=0; k<span; k++) //span个小组 
            {
                //组内进行直接插入排序 ,区别在于每次不是增加1,而是增加span
                for(i=k; i<n-span; i+=span)
                {
                    val=a[j+span];
                    j=i;
                    while(j>-1 && val<a[j])
                    {
                        a[j+span]=a[j];
                        j=j-span;
                    }
    
                    a[j+span]=val;
                }
            }
        }
    }

    第八:鸡尾酒排序

    1:原理

    在冒泡基础上改进,让单向冒泡变成双向冒泡;结束时是两个冒泡起点重合时。

    2:性能

    最坏情况还是和冒泡一致;n的2次方

    但是好的和插入相似了。为n;它比直接冒泡要好;

    空间复杂度:1

    3:应用

    性能和直接插入算法相似,故而和插入算法应用相似。

    4:实现

    void CocktailSort(int * list, int list_length) 
    {
        int bottom = 0;
        int top = list_length - 1;
        int bound = 0; //优化循环次数,记录已经排序的边界,减少循环次数
        while(bottom!=top) //表示已全部冒泡完了,就是已经成为顺序了
        {
            for(int i = bottom; i < top; i = i + 1)
            {//顺冒泡
                if(list[i] > list[i+1]) 
                {
                    swap(list[i], list[i+1]); 
               
                    bound = i;
                }
            }
            top = bound;
            for(int i = top; i > bottom; i = i - 1)
            {//反顺冒泡
                if(list[i] < list[i-1])
                {
                    swap(list[i], list[i-1]);
                    bound = i;
                }
            }
            bottom = bound;
        }
    }

    第九:地精排序

    1:原理

    在冒泡基础上改进的,它的效果和插入排序相似,号称是简单的排序算法,算法实现非常短。

    2:性能

    性能和插入排序一样

    3:应用

    应用和插入排序一样

    4:实现

    void GnomeSort(int* unsorted,int length)
    {
        int i = 0;
        while (i < length)//到达最后一个表示完成了
        {
            if (i == 0 || unsorted[i - 1] <= unsorted[i])
            {//表示能前进的条件,i=0或者是没有交换
                i++;
            }
            else
            {//发生交换了
                int tmp = unsorted[i];
                unsorted[i] = unsorted[i - 1];
                unsorted[i - 1] = tmp;
                i--;
            }
        }
    }

    第十:奇偶排序

    1:原理

    选取奇数,和它相邻比较,排序;同样对偶数也这样,最后达到没有交换了,此时就是顺序的了

    2:性能

    平均时间复杂度:O(n2);

    最好时间复杂度:O(n);

    最差时间复杂度:O(n2);

    可以看到有点像插入排序了;不稳定

    3:应用

    和插入排序应用相似。。。

    4:实现

    void OddEvenSort(int * szArray,int length)
    {  
        bool sorted = false;  
        while (!sorted)  
        {  
            sorted = true;  
            for (int i = 1; i < length - 1; i += 2)  
            {  //偶数排
                if (szArray[i]>szArray[i + 1])  
                {  
                    int tmp = szArray[i];  
                    szArray[i] = szArray[i+1];  
                    szArray[i+1] = tmp;    
                    sorted = false;  
                }  
            }   
            for (int i = 0; i < length - 1; i+= 2)  
            {  //奇数排
                if (szArray[i]>szArray[i + 1])  
                {  
                    int tmp = szArray[i];  
                    szArray[i] = szArray[i+1];  
                    szArray[i+1] = tmp;    
                    sorted = false;   
                } 
            }  
        }  
    }

    第十一:梳排序

    1:原理

    它是基于冒泡和插入排序的结合品,选取了适合的比率,进行冒泡。

    2:性能

    最差时间复杂度Omega(n^2)
          最优时间复杂度O(n)

    平均时间复杂度Omega(n^2/2^p),p是比率;

    空间复杂度:1。。。。不稳定

    3:应用

    类似插入算法应用

    4:实现

    void CombSort(int *arr, int size) 
    {
     
      double shrink_factor = 1.247330950103979;//1.3比率
      int gap = size;
      int swapped = 1;
      int swap;
      int i;
     
      while ((gap > 1) || swapped) 
      {
        if (gap > 1) 
        {
            gap = gap / shrink_factor;//计算间距
        }
     //直到gap为1时表示已经再距离上已经是到达了
        //此时就和冒泡一致了,外循环加内循环了,直到不再交换为止。。。
        swapped = 0; 
        i = 0;
     
        while ((gap + i) < size) 
        {
          if(arr[i]-arr[i+gap] > 0) 
          {
            swap = arr[i];
            arr[i] = arr[i+gap];
            arr[i+gap] = swap;
            swapped = 1;
          }
          ++i;
        }
      }
    }

    下一遍----->运算类的排序<-------下一篇

  • 相关阅读:
    FirstAFNetWorking
    JSONModel 简单例子
    KVO
    KVC
    关于UITableView的性能优化(历上最全面的优化分析)
    浅拷贝和深拷贝
    UI2_异步下载
    UI2_同步下载
    算法图解学习笔记02:递归和栈
    算法图解学习笔记01:二分查找&大O表示法
  • 原文地址:https://www.cnblogs.com/miner007/p/3793549.html
Copyright © 2011-2022 走看看