cv_gordon

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::

关于C++各类排序算法与std::sort性能的比较

https://blog.csdn.net/qq_24625045/article/details/49964173

 

堆排序

堆排序分为初始构建堆和重建堆两部分内容。

构建堆。

从顺序表构建堆,时间复杂度O(n)。每个非终端节点最多进行2次比较和互换。

重建堆。

重建堆需要取 n-1 次堆顶记录。第i次取堆顶记录重建堆,需要进行 logi 次比较和互换,耗时O(logi)(完全二叉树的某个节点到根节点的距离是 [logi]+1)。因此重建堆的时间复杂度为O(nlogn)。

总体来看,堆排序的时间复杂度为O(nlogn)。堆排序对原始记录不敏感,所以最好、最坏情况都是O(nlogn)。

#include <iostream>
#include <vector>

using namespace std;

typedef struct
{
    vector<int> r = {0};
    int length;
} SqList;

void swap(SqList *L, int i, int j) {
    int temp = L->r[i];
    L->r[i] = L->r[j];
    L->r[j] = temp;
}

void HeapAdjust(SqList *L, int index, int len) {
    
    int temp = L->r[index];
    
    for(int i = index*2; i <= len; i*2) {
        if(i < len && L->r[i] < L->r[i+1])
            i++;
        
        if(temp >= L->r[i])
            break;
        else {
            swap(L, index, i);            
            index = i;
        }
    }
    
}

void HeapSort(SqList *L) {
    if(L ==NULL)
        return;
    
    int len = L->length;
    
    for(int i = (len/2); i > 0; --i) {
        HeapAdjust(L, i, len);
    }
    
    for(int j = len; j > 1; --j) {
        swap(L, 1, j);
        HeapAdjust(L, 1, j-1);
    }
}

int main (int argc, char** argv) {
    SqList *sl = new SqList;
    
    int m, n;
    cin >> n;
    
    sl->length = n;
    
    for(int i = 1; i <= n; ++i) {
        cin >> m;
        sl->r.push_back(m);
    }
    
    HeapSort(sl);
    
    for (int i = 0; i <= n; ++i) {
        cout << sl->r[i] << endl;
    }
    
    return 0;
}

 

 

 

快速排序

平均时间复杂度O(nlogn);

最好情况时间复杂度O(nlogn),pivotkey基本处于顺序表中间;

最坏情况时间复杂度O(n^2),顺序表处于正序和倒序;

 

最好情况空间复杂度O(logn),要执行logn次递归调用;

最坏情况空间复杂度O(n),要执行n-1次递归调用;

#include <iostream>
#include <vector>

using namespace std;

typedef struct {
    vector<int> r = {0};
    int length;
} SqList;

void swap(SqList * L, int i, int j) {
    int temp = L->r[i];
    L->r[i] = L->r[j];
    L->r[j] = temp;
}

int getPivot(SqList *L, int low, int high) {
    int pivot = L->r[low];
   
    while(low < high) {
        while(low < high && pivot <= L->r[high]) {
            high --;
        }
        swap (L, low, high);
        
        while(low < high && pivot > L->r[low]) {
            low ++;
        }
        swap (L, low, high);        
    }
    return low;
}

void QSort(SqList *L, int low, int high) {    
    if(low < high) {
        int pivot = getPivot(L, low, high);
        QSort(L, low, pivot-1);
        QSort(L, pivot+1, high);
    }
}

void QuickSort (SqList *L) {
    QSort(L, 1, L->length-1);
}

int main (int argc, char** argv) {
    SqList *sl = new SqList;
    
    int num = 0, temp = 0;
    
    cout << "cin the number of sqlist(include flag)" << endl;
    cin >> num;
    sl->length = num;
    
    for(int i = 0; i < num-1; ++i) {
        cin >> temp;
        sl->r.push_back(temp);
    }

    QuickSort(sl);
    
    for(int i = 0; i < num; ++i)
        cout << sl->r[i] << endl;
    
    return 0;
}

 

对上述快速排序的改进:

1)优化选取pivotkey。采用三数取中法获取pivotkey,而不是取左边界的数。

2)优化不必要的交换。选取pivotkey后,将序列分成左右端序列,去除对pivotkey的移位操作。

3)优化小数组的排序方案。当需要排序的数组长度小于某个阈值后,采用直接插入排序。因为快速排序用到了递归操作,在大量数据排序时,这点性能影响对整体算法优势而言可以忽略不计。直接插入排序适用于小量数据的排序,最好情况下时间复杂度为O(n)。

4)优化递归操作。在下列代码中还未实施。

#include <iostream>
#include <vector>
#include <ctime>

using namespace std;

clock_t start1, end1;

#define MAX_LENGTH_INSERT_SORT 7

typedef struct {
    vector<int> r = {0};
    int length;
} SqList;

void swap(SqList * sq, int left, int right) { // avoid to use the swap func in Partition func.
    int temp = sq->r[left];
    sq->r[left] = sq->r[right];
    sq->r[right] = temp;
}

int Partition(SqList * sq, int low, int high) {
    int mid = 0.5*(low+high);  // choose pivotkey in 3 data, low-mid-high
    
    if(sq->r[low] > sq->r[high])
        swap(sq, low, high);
    if(sq->r[mid] > sq->r[high])
        swap(sq, mid, high);
    if(sq->r[mid] > sq->r[low])
        swap(sq, low, mid);
    
    sq->r[0] = sq->r[low];
    
    while(low < high) {
        
        while(low < high && sq->r[0] <= sq->r[high])
            high --;
        sq->r[low] = sq->r[high];
        
        while(low < high && sq->r[0] >= sq->r[low])
            low ++;
        sq->r[high] = sq->r[low];
        
    }
    sq->r[low] = sq->r[0];
    return low;
}

void InsertSort(SqList * sq, int low, int high) {
    int temp;
    
    for(int i = low+1; i <= high; ++i) {
        if( sq->r[i] < sq->r[i-1] ) {
            temp = sq->r[i];
            
            int j;
            for(j = i-1; (sq->r[j] > temp) && (j>=low); --j ) {
                sq->r[j+1] = sq->r[j];
            }
            
            sq->r[j+1] = temp;
        }
    }
}

void Sort(SqList * sq, int low, int high) {    
    int pivotkey;
    
    if( (high-low) > MAX_LENGTH_INSERT_SORT ) {
        pivotkey = Partition(sq, low, high);
        
        Sort(sq, low, pivotkey-1);
        Sort(sq, pivotkey+1, high);
    }
    else  // length is too small, use insert sort
        InsertSort(sq, low, high);
}

void QuickSort(SqList * sq) {
    Sort(sq, 1, sq->length);
}


int main (int argc, char** argv) {
    SqList *sl = new SqList;
    
    int num = 0, temp = 0;
    
    cout << "cin the number of SqList" << endl;
    cin >> num;
    sl->length = num;
    
    for(int i = 0; i < num; ++i) {       
        cin >> temp;
        sl->r.push_back(temp);
    }

    start1 = clock();
    QuickSort(sl);
    end1 = clock();
    
    cout << "cost time = " << (double)(end1 - start1) / CLOCKS_PER_SEC << endl;
    
    cout << "*************" << endl;
    
    for(int i = 1; i <= num; ++i)
        cout << sl->r[i] << endl;
    
    return 0;
}

 

posted on 2019-09-11 14:58  cv_gordon  阅读(252)  评论(0编辑  收藏  举报