您的位置:首页 > 理论基础 > 数据结构算法

关于排序的总结和部分实现(个人理解整理版)

2016-04-06 17:18 501 查看
因为找实习,很多公司都要看技术博客,大部分笔记,BUG修复之类的都写在印象笔记上,现在开始往上面搬。

不稳定排序:堆排,希尔,快排,选择排序

时间复杂度达到O(nlogn)的排序:堆排,快排,希尔,归并(神奇)
如果不考虑空间消耗,桶排是最快的
如果不考虑太多的空间消耗,堆排和归并一样快
如果考虑空间消耗,堆排更快一点。
如果实现有困难,比如不好建堆,不好划分归并,可以使用快排。
数组比较小的时候,会选择插入排序,数组比较大的时候快排。

快速排序(是冒泡排序的进化型)*因为快速排序和冒泡排序都是交换排序
冒泡排序的最好时间复杂度O(n),最坏O(n^2),因为冒泡排序是就地排序,所以它是稳定的。
冒泡排序:1.从无序区R[1...n]开始向上比较(从N开始)相邻两个气泡的重量,如果发现问题,交换两者的位置。这样置换之后,可以确定一个最轻的气泡,现在R【1】有序和R【2...n】无序
2.开始第二次扫描,扫描完毕时,倒数第二轻的气泡已经确定位置了。
3.最后经过n-1次扫描可以得到一个有序的排列。
4.如何确定排序是否已经有序:给一个布尔量Exchange,在每趟排序开始之前,将其设置为FLASE,如果发生交换设置为TRUE,如果已经有序,必然不会发生交换,最后检查一下设置是否为FLASE时就停止。
int i,j;
        for(i=0;i<n;i++)
            for(j=0;i+j<n-1;j++)
            {
            if(A[j]>A[j+1])
                {
                int temp=A[j];
                A[j]=A[j+1];
                A[j+1]=temp;
            }
        }
        return A;

快排平均情况下O(nlogn),最坏的情况下O(n^2),空间复杂度O(logn)
快速排序:分为两个部分,第一是快排的划分思想,第二是基准点的划分方法。
基准点的划分方法:1.设置指针i(开始指向下界)和指针j(开始指向上界),选取无序区的第一个记录R[i]作为基准记录。将它保存在pivot中
2.令j从高位开始扫描,直到扫描到比pivot小的记录A,交换A和pivot,此时R[i]等于A,R[j]等于pivot
然后从低位开始扫描,直到找到一个比pivot大的记录B,交换B和pivot,此时R[j]等于B,R[i]等于pivot
3.直到i=j时,R[i]=R[j],此时pivot的最终位置确定,讲pivot放在此位置上完成一次划分。
然后再进行快排,首先分治划分,然后求解,求解借书时,左右已经有序,不需要组合。

插入排序最差平均都是O(n^2),最好是O(n)
插排就是把没顺序的,和有顺序的进行比较,然后按顺序插入即可。
 int i,j;
        int temp=0;
        for(i=0;i<n;i++)
        {
        for(j=i;j>0;j--)
        {
        if(A[j]<A[j-1])
        {   temp=A[j];
            A[j]=A[j-1];
            A[j-1]=temp;
        }
        }
        }
        return A;

希尔排序(希尔排序是插入排序的一种),时间复杂度O(nlogn),空间复杂度1
成败在于步长的选择策略。
概念:增量序列,比如5,3,2,1,这里指的是吧步长,标示第一个数和第六个数比较后排序,第二个数和第7个数比较排列,这是第一轮
第二轮,第一个数和第四个数比较排列,第二个数和第五个数比较排列,这是第二轮
第三轮
第四轮以此类推。
有一种说法是步长需要一直进行比较。

桶排的时间复杂度O(n),空间O(K),典型的空间换时间
桶排序:桶排首先要有个桶,假设数据是23558,假设有10个空桶
对于这是个空桶,读入一个2,2号桶+1,读入3,三号桶+1,读入5,5,5号桶加1加1,读入8,八号桶+1,这样顺序输出即可。

时间复杂度O(dn),空间复杂度是O(n)
基数排序:和桶排有点相似,不过先排个位,排完重新组序,然后再排十位,排完从新组序号。先排的先输出是基本要领。

计数排序,就是桶排

归并排序时间复杂度最好最坏平均都O(nlogn),时间复杂度O(1)
堆排序:堆排开始的时候必须将堆调节成大根堆或者小根堆,将最大数或者最小数从堆顶取出。
取出后,剩下的堆再次进行调整。再从当前大根堆中取出堆顶,直到取完所有的值。

归并排序时间复杂度最好最坏平均都O(nlogn),时间复杂度O(n)
归并排序:@1.自底向上(效率高,但是可读性差)
自底向上的基本思想是:第1趟归并排序时,将待排序的文件R[1..n]看作是n个长度为1的有序子文件,将这些子文件两两归并,若n为偶数,则得到 个长度为2的有序子文件;若n为奇数,则最后一个子文件轮空(不参与归并)。故本趟归并完成后,前 个有序子文件长度为2,但最后一个子文件长度仍为1;第2趟归并则是将第1趟归并所得到的 个有序的子文件两两归并,如此反复,直到最后得到一个长度为n的有序文件为止。
     上述的每次归并操作,均是将两个有序的子文件合并成一个有序的子文件,故称其为"二路归并排序"。类似地有k(k>2)路归并排序。
@2.自顶向下
①分解:将当前区间一分为二,即求分裂点

                  
②求解:递归地对两个子区间R[low..mid]和R[mid+1..high]进行归并排序;
③组合:将已排序的两个子区间R[low..mid]和R[mid+1..high]归并为一个有序的区间R[low..high]。

  递归的终结条件:子区间长度为1(一个记录自然有序)。

选择排序:思想是遍历一遍,然后选择最小的或者最大的放到前面,故最坏或者平均都是O(n^2),主要用来评估排序算法。
class SelectionSort {
public:
    int* selectionSort(int* A, int n) {
        int max,i,j,m;
        m=n;
        int temp=0;
        for(i=0;i<n;i++)
        {  max=0;
            for(j=0;j<m;j++)
           {
            if(A[max]<A[j])
              max=j;
           }
              temp=A[m-1];
              A[m-1]=A[max];
              A[max]=temp;
              m--;
        }
        return A;
    }
};
需要笔记分享的,可以发邮件到我邮箱,sa515044@mail.ustc.edu.cn,写明需要哪一章,谢谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息