c++ 常见排序算法汇总

1.快速排序算法
最坏时间复杂度为O(n*n), 这与基数的选择有关, 期望的运行时间为O(nlgn),且O(nlgn)记号中隐含的常数因子很小。另外,它还能够进行就地排序.

快速排序逻辑:
1、先从数组中取出一个数作为基数,基数的选择对排序效率的影响很大, 一般随机来选择.
2、分区,将比这个基数小的数全部放到它的左边,比基数大的数全部放到其右边
3、对左右两个区间重复第二步,直到每个区间只有一个数

#include 
#include 

void swap (int& a, int& b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

int partion(int a[], int f, int e)
{
    int i = f;
    for (int j = f; j < e; j++)
    {
        if (a[j] < a[f])
        {
            swap (a[++i], a[j]);
        }
    }
    swap (a[i], a[f]);
    return i;
}

void quickSort(int a[], int f, int e)
{
    if (f < e)
    {
        int i = f + rand() % (e - f);
        swap(a[f], a[i]);
        int mid = partion(a, f, e);
        quickSort(a, f, mid);
        quickSort(a, mid + 1, e);
    }
}

int main()
{
    int a[] = {6, 7, 0, 3, 2, 4, 5, 8, 9, 1};
    quickSort(a, 0, 10);
    for (int i = 0; i < 10; i++)
    {
        std::cout<" ";
    }
    std::cout<<std::endl;
    return 0;
}

2.归并排序
时间复杂度为O(n*lgn)
归并排序的思想是分而治之, 每个递归过程涉及三个步骤:
第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.
第二, 治理: 对每个子序列分别调用归并排序merge, 进行递归操作
第三, 合并: 合并两个排好序的子序列,生成排序结果.

#include 

void mergeArray(int a[], int f, int m, int e, int tmp[])
{
    int i = f, j = m + 1;
    int k = 0;
    while (i <= m && j <= e)
    {
        if (a[i] < a[j])
            tmp[k++] = a[i++];
        else
            tmp[k++] = a[j++];
    }
    while (i <= m)
        tmp[k++] = a[i++];
    while (j <= e)
        tmp[k++] = a[j++];

    for (i = 0; i < k; i++)
    {
        a[f + i] = tmp[i];
    }
}

void merge(int a[], int f, int e, int temp[])
{
    if (f < e)
    {
        int mid = f + (e - f) / 2;
        merge(a, f, mid, temp);          //左边有序
        merge(a, mid + 1, e, temp);      //右边有序
        mergeArray(a, f, mid, e, temp); //合并左右两个有序数组
    }
}

void mergeSort(int a[], int len)
{
    int *p = new int[len];
    merge(a, 0, len, p);
    delete[] p;
}

int main()
{
    int a[] = {6, 7, 0, 3, 2, 4, 5, 8, 9, 1};
    mergeSort(a, 9);
    for (int i = 0; i < 10; i++)
    {
        std::cout<" ";
    }
    std::cout<<std::endl;
    return 0;

3.选择排序
时间复杂度为O(n * n)
选择排序逻辑:
每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。选择排序不是稳定排序算法, 会破坏原来元素的顺序.

#include 

void selectSort(int a[], int n)
{
    for (int i = 0; i < n; i++)
    {
        int pos = i;
        for (int j = i + 1; j < n; j++)
        {
            if (a[j] < a[pos])
            {
                pos = j;
            }
        }
        if (pos != i)
        {
            int tmp = a[i];
            a[i] = a[pos];
            a[pos] = tmp;
        }
    }
}

int main()
{
    int a[] = {6, 7, 0, 3, 2, 4, 5, 8, 9, 1};
    selectSort(a, 10);
    for (int i = 0; i < 10; i++)
    {
        std::cout<" ";
    }
    std::cout<<std::endl;
    return 0;
}

4.插入排序
时间复杂度为O(n * n)
插入排序就是每一步都将一个待排数据按其大小插入到已经排序的数据中的适当位置,直到全部插入完毕。

#include 

void insertSort(int a[], int n)
{
    for (int i = 1; i < n; i++)
    {
        for (int j = i - 1; j >= 0 && a[j + 1] < a[j]; j--)
        {
            int tmp = a[j];
            a[j] = a[j+1];
            a[j+1] = tmp;
        }
    }
}

int main()
{
    int a[] = {6, 7, 0, 3, 2, 4, 5, 8, 9, 1};
    insertSort(a, 10);
    for (int i = 0; i < 10; i++)
    {
        std::cout<" ";
    }
    std::cout<<std::endl;
    return 0;
}

5.希尔排序
希尔排序是插入排序的一种.希尔排序的实质就是分组插入排序,该方法又称缩小增量排序.
该方法的基本思想是:
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的.

#include 

void shallSort(int a[], int len)
{
    for(int grap = len / 2; grap > 0; grap /= 2)
    {
        for(int i = grap; i < len; ++i)
        {
            for(int j = i - grap; j >=0 && a[j] > a[j + grap]; j -= grap)
                std::swap(a[j], a[j + grap]);
        }
    }
}

int main()
{
    int a[] = {6, 7, 0, 3, 2, 4, 5, 8, 9, 1};
    shallSort(a, 10);
    for (int i = 0; i < 10; i++)
    {
        std::cout<" ";
    }
    std::cout<<std::endl;
    return 0;
}

6.堆排序
时间复杂度为O(n*logn)
利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单。
堆排序为不稳定排序,不适合记录较少的排序

#include 

void heapation(int a[], int pos, int len)
{
    int left = pos * 2;
    int right = left + 1;
    int root = pos;
    if (left < len && a[left] > a[root])
        root = left;
    if (right < len && a[right] > a[root])
        root = right;
    if (root != pos)
    {
        std::swap(a[root], a[pos]);
        heapation(a, root, len);
    }
}

//创建最大堆
void createHeap(int a[], int len)
{
    for (int i = len / 2; i >= 0; i--)
    {
        heapation(a, i, len);
    }
}

void heapSort(int a[], int len)
{
    createHeap(a, len);
    for (int i = 0; i < len; i++)
    {
        std::swap(a[0], a[len - i - 1]);
        heapation(a, 0, len - i - 1);
    }
}

int main()
{
    int a[] = {6, 7, 0, 3, 2, 4, 5, 8, 9, 1};
    heapSort(a, 10);
    for (int i = 0; i < 10; i++)
    {
        std::cout<" ";
    }
    std::cout<<std::endl;
    return 0;
}

7.计数排序
使用此排序需要注意的是排序的数据符合正态分布,有很大的局限性,虽然时间复杂度为O(n),但是牺牲了空间。假设要排序的数为:4,5,9,2,3,1000那么我们需要分配1000个空间。

#include 

void countSort(int a[], int len)
{
    if (len <= 0 || a == NULL)
        return;
    int b[1024] = {0};
    int c[1024] = {0};
    int maxlen = a[0];
    for(int i = 0; i < len; ++i)
    {
        b[a[i]]++;
        if (maxlen < a[i])
            maxlen = a[i];
    }
    for(int i = 0; i < maxlen; ++i)
    {
        b[i + 1] += b[i];
    }

    for(int i = 0; i < len; ++i)
    {
        c[--b[a[i]] ] = a[i];
    }

    for(int i = 0; i < len; ++i)
    {
        a[i] = c[i];
    }
}

int main()
{
    int a[] = {6, 7, 0, 3, 2, 4, 5, 8, 9, 1};
    countSort(a, 10);
    for (int i = 0; i < 10; i++)
    {
        std::cout<" ";
    }
    std::cout<<std::endl;
    return 0;
}

你可能感兴趣的:(数据结构与算法,c/c++,c语言,快速排序,算法)