内部排序

参考资料:http://www.cnblogs.com/easonliu/archive/2012/10/19/2731358.html

常用的内部排序方法有:交换排序(冒泡排序、快速排序)、选择排序(简单选择排序、堆排序)、插入排序(直接插入排序、希尔排序)、归并排序、基数排序(一关键字、多关键字)。

===========================================================

时间复杂度 

排序方法                 最好情况                最坏情况             平均情况              稳定性 

冒泡排序                   O(n)                      O(n2)                 O(n2)                 稳定

快速排序                   O(nlogn)               O(n2)                  O(nlogn)            不稳定

简单选择排序                                                                   O(n2)               不稳定

堆排序                                                O(nlogn)                                      不稳定

直接插入排序            O(n)                      O(n2)                  O(n2)                  稳定

希尔排序                                                                       O(n1.3)              不稳定

归并排序                    O(nlogn)               O(nlogn)             O(nlogn)               稳定

基数排序                                                                       O(d(r+n))              稳定

=================================================================== 


冒泡排序:


1.基本思想:

两两比较待排序数据元素的大小,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止。

2.排序过程:

设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。

不多说了,上代码: 



01#include <iostream>
02 
03using namespace std;
04 
05void swap(int &a,int &b){
06    int temp = a;
07    a = b;
08    b = temp;
09}
10 
11void popSort(int *index,int len){
12    if(len <= 1){
13        return;
14    }
15    for(int i = 0 ; i < len ; ++i){
16        bool flag = false;
17        for(int j = 1 ; j < len - i ; ++j){
18            if(index[j-1] > index[j]){
19                swap(index[j-1],index[j]);
20                flag = true;
21            }
22        }
23        if(!flag){
24            return;
25        }
26    }
27}
28 
29int main()
30{
31    int index[] = {1,2,3,4,5,6,7,8,9,0};
32    popSort(index,sizeof(index)/sizeof(int));
33    for(int i = 0 ;i < 10 ; ++i){
34        cout << index[i] << " ";
35    }
36    cout << endl;
37    return 1;
38}



快速排序:


1.基本思想:

在 当前无序区R[1..H]中任取一个数据元素作为比较的"基准"(不妨记为X),用此基准将当前无序区划分为左右两个较小的无序区:R[1..I-1]和 R[I+1..H],且左边的无序子区中数据元素均小于等于基准元素,右边的无序子区中数据元素均大于等于基准元素,而基准X则位于最终排序的位置上,即 R[1..I-1]≤X.Key≤R[I+1..H](1≤I≤H),当R[1..I-1]和R[I+1..H]均非空时,分别对它们进行上述的划分过 程,直至所有无序子区中的数据元素均已排序为止。

    2.排序过程:

    【示例】:

    初始关键字 [49 38 65 97 76 13 27 49]

    第一次交换后 [27 38 65 97 76 13 49 49]

    第二次交换后 [27 38 49 97 76 13 65 49]

    J向左扫描,位置不变,第三次交换后 [27 38 13 97 76 49 65 49]

    I向右扫描,位置不变,第四次交换后 [27 38 13 49 76 97 65 49]

    J向左扫描 [27 38 13 49 76 97 65 49]

   (一次划分过程)

    初始关键字 [49 38 65 97 76 13 27 49]

    一趟排序之后 [27 38 13] 49 [76 97 65 49]

    二趟排序之后 [13] 27 [38] 49 [49 65]76 [97]

    三趟排序之后 13 27 38 49 49 [65]76 97

最后的排序结果 13 27 38 49 49 65 76 97

上代码: 
01#include <iostream>
02 
03using namespace std;
04 
05void swap(int &a,int &b){
06    int temp = a;
07    a = b;
08    b = temp;
09}
10 
11int partition(int *index,int begin,int end){
12    int i = begin;
13    int j = end;
14     
15    while(i<j){
16        while(index[i]<=index[j]&&i<j){
17            --j;
18        }
19        if(i<j){
20            swap(index[i],index[j]);
21        }
22        while(index[i]<=index[j]&&i<j){
23            ++i;
24        }
25        if(i<j){
26            swap(index[i],index[j]);
27        }
28    }
29    return i;
30     
31}
32 
33void quickSort(int *index,int begin,int end){
34    if(begin>=end){
35        return;
36    }
37    int q = partition(index,begin,end);
38    quickSort(index,begin,q-1);
39    quickSort(index,q+1,end);
40}
41 
42int main()
43{
44    int index[] = {2,6,2,3,6,7,8,3,1,2};
45    quickSort(index,0,9);
46    for(int i = 0 ;i < 10 ; ++i){
47        cout << index[i] << " ";
48    }
49    cout << endl;
50    return 1;
51}


选择排序

 1.基本思想:

每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

    2.排序过程:

【示例】:

    初始关键字 [49 38 65 97 76 13 27 49]

    第一趟排序后 13 [38 65 97 76 49 27 49]

    第二趟排序后 13 27 [65 97 76 49 38 49]

    第三趟排序后 13 27 38 [97 76 49 65 49]

    第四趟排序后 13 27 38 49 [49 97 65 76]

    第五趟排序后 13 27 38 49 49 [97 97 76]

    第六趟排序后 13 27 38 49 49 76 [76 97]

    第七趟排序后 13 27 38 49 49 76 76 [ 97]

最后排序结果 13 27 38 49 49 76 76 97

上代码: 

01#include <iostream>
02 
03using namespace std;
04 
05void swap(int &a,int &b){
06    int temp = a;
07    a = b;
08    b = temp;
09}
10 
11void selectSort(int *index,int len){
12    for(int i = 0 ; i < len ; ++i){
13        int pMin = i;
14        for(int j = i ; j < len ; ++j){
15            if(index[j]<index[pMin]){
16                pMin = j;
17            }
18        }
19        if(pMin != i){
20            swap(index[i],index[pMin]);
21        }
22    }
23}
24 
25int main(){
26    int index[] = {2,6,2,3,6,7,8,3,1,2};
27    selectSort(index,sizeof(index)/sizeof(int));
28    for(int i = 0 ;i < 10 ; ++i){
29        cout << index[i] << " ";
30    }
31    cout << endl;
32    return 1;
33}

堆排序

 1.基本思想:

    堆排序是一树形选择排序,在排序过程中,将R[1..N]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。

    2.堆的定义: N个元素的序列K1,K2,K3,...,Kn.称为堆,当且仅当该序列满足特性:

        Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2])

    堆实质上是满足如下性质的完全二叉树:树中任一非叶子结点的关键字均大于等于其孩子结点的关键字。例如序列10,15,56,25,30,70就是一个 堆,它对应的完全二叉树如上图所示。这种堆中根结点(称为堆顶)的关键字最小,我们把它称为小根堆。反之,若完全二叉树中任一非叶子结点的关键字均大于等 于其孩子的关键字,则称之为大根堆。

    3.排序过程:

    堆排序正是利用小根堆(或大根堆)来选取当前无序区中关键字小(或最大)的记录实现排序的。我们不妨利用大根堆来排序。每一趟排序的基本操作是:将当前无 序区调整为一个大根堆,选取关键字最大的堆顶记录,将它和无序区中的最后一个记录交换。这样,正好和直接选择排序相反,有序区是在原记录区的尾部形成并逐 步向前扩大到整个记录区。

【示例】:对关键字序列42,13,91,23,24,16,05,88建堆

上代码: 

01#include <iostream>
02 
03using namespace std;
04 
05void swap(int &a,int &b){
06    int temp = a;
07    a = b;
08    b = temp;
09}
10 
11//堆中的元素在数组中从索引1开始,索引0中存储的是
12//堆中当前的元素个数。
13void heapAdjust(int *index,int pIndex,int end){
14    for(int j = 2*pIndex ; j <= end ; j = 2*pIndex){
15        if(j<end && index[j]<index[j+1]){
16            ++j;
17        }
18        if(index[pIndex]>=index[j]){
19            break;
20        }
21        swap(index[pIndex],index[j]);
22        pIndex = j;
23    }
24     
25}
26 
27void heapSort(int *index,int len){
28    for(int i = len/2 ; i > 0 ; --i){
29        heapAdjust(index,i,len);
30    }
31    for(int i = len ; i > 1 ; --i){
32        swap(index[1],index[i]);
33        heapAdjust(index,1,i-1);
34    }
35}
36 
37int main(){
38    int index[] = {10,2,6,2,3,6,7,8,3,1,2};//10表示有十个元素
39    heapSort(index,sizeof(index)/sizeof(int)-1);
40    for(int i = 1 ;i <= 10 ; ++i){
41        cout << index[i] << " ";
42    }
43    cout << endl;
44    return 1;
45}
直接插入排序

1. 基本思想:

每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,使数列依然有序;直到待排序数据元素全部插入完为止。

2. 排序过程:

【示例】:

[初始关键字] [49] 38 65 97 76 13 27 49

     J=2(38) [38 49] 65 97 76 13 27 49

     J=3(65) [38 49 65] 97 76 13 27 49

     J=4(97) [38 49 65 97] 76 13 27 49

     J=5(76) [38 49 65 76 97] 13 27 49

     J=6(13) [13 38 49 65 76 97] 27 49

     J=7(27) [13 27 38 49 65 76 97] 49

     J=8(49) [13 27 38 49 49 65 76 97]

代码: 

01#include <iostream>
02 
03using namespace std;
04 
05void swap(int &a,int &b){
06    int temp = a;
07    a = b;
08    b = temp;
09}
10 
11void insertSort(int *index,int len){
12    if(len <= 1){
13        return;
14    }
15    for(int i = 1 ; i < len ; ++i){
16        int temp = index[i];
17        int j = i-1;
18        for(;j>=0 && temp<index[j];--j){
19            index[j+1] = index[j];
20        }
21        index[j+1] = temp;
22    }
23}
24 
25int main(){
26    int index[] = {2,6,2,3,6,7,8,3,1,2};
27    insertSort(index,sizeof(index)/sizeof(int));
28    for(int i = 0 ;i < 10 ; ++i){
29        cout << index[i] << " ";
30    }
31    cout << endl;
32    return 1;
33}
归并排序

1.排序思想:

设两个有序的子文件(相当于输入堆)放在同一向量中相邻的位置上:R[low..m],R[m+1..high],先将它们合并到一个局部的暂存向量R1(相当于输出堆)中,待合并完成后将R1复制回R[low..high]中。

       2.排序过程:

【示例】:

初始关键字    [46][38][56][30][88][80][38]

第一趟归并后[38 46][30 56][80 88][38]

第二趟归并后[30 38 46 56][38 80 88]

最终归并结果[30 38 38 46 56 80 88]

代码: 

01#include <iostream>
02 
03using namespace std;
04 
05//index为合并后的队列,
06//indexA为合并数组A,lenA为其长度
07//indexB为合并数组B,lenB为其长度
08void merge(int *index,int *indexA,int lenA,int *indexB,int lenB){
09    int *left = new int[lenA];
10    int *right = new int[lenB];
11    int i=0,j=0,k=0;
12 
13    memcpy(left,indexA,lenA*sizeof(int));
14    memcpy(right,indexB,lenB*sizeof(int));
15 
16    for(k = 0;k<lenA+lenB;k++){
17        if(i<lenA && j<lenB && left[i]<right[j]){
18            index[k] = left[i];
19            i++;
20        }else if(i<lenA && j<lenB){
21            index[k] = right[j];
22            j++;
23        }else if(j<lenB && i==lenA){
24            index[k] = right[j];
25            j++;
26        }else if(j==lenB && i<lenA){
27            index[k] = left[i];
28            i++;
29        }
30    }
31 
32    delete[] left;
33    delete[] right;
34}
35 
36void mergeSort(int *index,int begin,int end){
37    if(begin>=end){
38        return;
39    }
40    int pMid = begin + ((end-begin)>>1);
41    mergeSort(index,begin,pMid);
42    mergeSort(index,pMid+1,end);
43    merge(&index[begin],&index[begin],pMid-begin+1,&index[pMid+1],end-pMid);
44 
45}
46 
47int main(){
48    int index[] = {2,6,2,3,6,7,8,3,1,2};
49    mergeSort(index,0,9);
50    for(int i = 0 ;i < 10 ; ++i){
51        cout << index[i] << " ";
52    }
53    cout << endl;
54    return 1;
55}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值