十大排序算法代码总览(C++)

十大排序算法代码总览(C++)_第1张图片
注:
算法稳定性
定义:待排序序列中的相同关键字记录经过排序后相对次序保持不变。比如Xm=xn,原本Xm在Xn之前,排序后依然Xm在Xn之前。
条件:算法的稳定性由具体算法决定,且在一定条件下算法稳定性也会发生转变。
稳定性意义:只有在排序一个复杂对象的多个数字属性且初始顺序存在意义时,才需要注意算法的稳定性,即需要尽量保持原有排序序列的意义。比如原本商品按价格高低排序,想着想要按销量排序,且使得同销量的商品依然保持价格高低的排序,这是可以使用稳定性算法。

1冒泡排序(Bubble Sort)

简述:

重复进行相邻数组元素的两两比较,并按规则进行交换,直到没有元素再需要交换。最终使得大的元素逐渐沉到数列底部,相较小的元素浮现到数列前端。

算法描述:

1 比较相邻两个元素,如果第一个比第二个大,就交换位置。
2 从第一对开始,对数组中的每一对相邻的两个元素重复步骤1,使得最大的元素沉到数组底部。
3 重复步骤2,除了底部已经排序好的元素。(每一趟都会多一个以排序好的元素)
4 重复以上步骤直到排序完成。

算法分析:

最好:T(n)=O(n);数据全部正序
最差:T(n)=O(n^2);数据全部反序
平均:T(n)=O(n^2);

代码实现
#include
using namespace std;
void swap(int &a, int &b) {//交换函数
    int tmp = a;
    a = b;
    b = tmp;
}
void bubbleSort(int a[],int len) {
    for (int i = 0; i < len; ++i) {//排列len趟完成排序
        for (int j = 0; j < len - i - 1; ++j) {//每趟排序的元素都从第一个元素开始到尾部没有排序好的元素。第一趟为第一个元素到最后一个元素,排出了最大元素。第二趟为第一个元素到倒数第二个元素(排除以排序好的元素),排出第二大的元素。
            if (a[j] > a[j + 1]) {
                swap(a[j], a[j + 1]);
            }
        }
    }
}
int main() {
    int a[] = { 520,0,1,9,56,100,1,85,5,3,6 };
    int len = sizeof(a) / sizeof(a[0]);
    bubbleSort(a, len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}
//运行结果:
 0 1 1 3 5 6 9 56 85 100 520
算法改进

1**增加了反向冒泡。传统冒泡排序每一趟排序一次,找出一个最大值。改进后每一趟排序两次,正向冒泡,找出最大的元素;反向冒泡,找出最小元素,使得一次可以得到两个最终值。从而减少排序趟数。**
2**增加了标志点flag**。目的在于记录每一趟最后一次交换的元素位置,即表示标志点之后或者之前的位置已经排好,后续无需再排,缩小排序区间,减少排序次数。

#include
using namespace std;
void swap(int &a, int &b) {
    int tmp = a;
    a = b;
    b = tmp;
}
void bubbleSort(int a[],int len) {
    int low = 0, high = len - 1;
    while (low < high) {//排序趟数。排序区间[low,high]。
        int flag = 0;//标志点
        for (int i = low; i < high; ++i) {//第一次正向冒泡
            if (a[i] > a[i + 1]) {
                swap(a[i], a[i + 1]);
                flag = i;
            }
        }
        high = flag;//表示标志点之后的元素已经排好,区间右值缩小。
        for (int i = high; i > low; --i) {//第2次反向冒泡
            if (a[i] < a[i - 1]) {
                swap(a[i], a[i - 1]);
                flag = i;
            }
        }
        low = flag;//表示断点之前的元素已经排好,区间左值缩小。 
    }
}
int main() {
    int a[] = { 520,0,1,9,56,100,1,85,5,3,6 };
    int len = sizeof(a) / sizeof(a[0]);
    bubbleSort(a, len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}
//运行结果:
 0 1 1 3 5 6 9 56 85 100 520

2选择排序(Select Sort)

简述

将数组分为已排序和待排序两个区间,即有序区和无序区。每次从无序区中选出最小/最大的元素与无序区的第一个元素(即有序区尾部)交换位置,直到无序区只剩一个元素,排序完成。

算法描述

1 将数组划分为有序区和无序区。(开始有序区为空,无序区[0,n-1])
2 在无序区中找出最大的那个元素,与该区间第一个元素交换。(有序区元素个数加1,无序区减1)
3 重复步骤2 n-1次,排序完成。(排序趟数为n-1,最后一个元素无需排序)

算法分析

时间复杂度最稳定,无论什么时候都为:T(n)=0(n^2)

代码实例
#include
using namespace std;
void swap(int &a, int &b) {
    int tmp = a;
    a = b;
    b = tmp;
}
void selectSort(int a[], int len) {
    for (int i = 0; i < len - 1; ++i) {
        int minIndex = i;
        for (int j = i; j < len; ++j) {//找出无序区最小元素的下标
            if (a[j] < a[minIndex]) {
                minIndex = j;
            }
        }
        swap(a[i], a[minIndex]);//无序区第一个元素与最小值交换。
    }
}

int main() {
    int a[] = { 5,89,562,4,2,0,56512,4512,5 };
    int len = sizeof(a) / sizeof(a[0]);
    selectSort(a, len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}
//运行结果:
 0 2 4 5 5 89 562 4512 56512

3插入排序(Insert Sort)

简述

插入排序跟选择排序很像,都分为有序区和无序区。但是选择排序是每次都从无序区中选出最小元素插入到有序区末尾,而插入排序是直接将数组的第一个元素作为有序区的第一个元素,每次都拿出无序区第个一元素插入到有序区合适的位置上,直到无序区为空,排序完成。

算法描述

1 将数组分为有序区和无序区,有序区0,无序区[1,n-1];
2 取下无序区第一个元素,保存其值。
3有序区中元素从后往前与新元素比较,如果新元素更小,旧元素往后移。
3 重复步骤3,直到新元素大于或等于旧元素,将新元素插入该元素之后。
4 重复步骤234, n-1次,排序完成。

算法分析

最好:T(n)=o(n),数组元素正序排列
最坏:T(n)=o(n^2)数组元素反序排列
平均:T(n)=o(n^2)

代码实例
#include
using namespace std;
void sertSort(int a[], int len) {
    for (int i = 1; i < len; ++i) {
        int key = a[i];//保存无序区第一个元素为key
        int j = i - 1;
        while (!(j <0) && a[j] > key) {//新元素在有序区寻找位置
            a[j + 1] = a[j];
            j--;
        }
        a[j+1] = key;
    }
}

int main() {
    int a[] = {5,45,1,3,0,99,2,10 };
    int len = sizeof(a) / sizeof(a[0]);
    sertSort(a, len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}
//运行结果:
 0 1 2 3 5 10 45 99
算法改进

新元素在插入到有序区时,使用二分法查找位置而非一个一个依次查找。

#include
using namespace std;
void sertSort(int a[], int len) {
    for (int i = 1; i < len; ++i) {
        int key = a[i];
        int left = 0, right = i-1;
        while (!(left > right)) {//在区间内查找位置
            int middle = (left + right) / 2;
            if (a[middle] > key)
                right = middle-1;
            else left = middle+1;
        }
        for (int j = i - 1; !(j1] = a[j ];
        }
        a[left] = key;//left为新元素要插入的位置。
    }
}

int main() {
    int a[] = {5,45,1,3,0,99,2,10 };
    int len = sizeof(a) / sizeof(a[0]);
    sertSort(a, len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}
//运行结果:
 0 1 2 3 5 10 45 99

4希尔排序(Shell Sort)

简述

希尔排序是以某个增量h为步长跳跃分组进行插入排序,由于增量是一个从h逐渐缩小至1的过程,所以又称缩小增量排序。
其核心在于间隔序列设定,即增量的设定,这也是也插入排序的本质区别。插入排序始终增量为1。
最佳增量:k趟排序增量步长为(2^k)-1,即增量序列(2^k)-1,…15,7,3,1

算法描述

1确定增量序列(t1,t2…tk)ti>tj,tk=1;
2按增量序列个数k分成k趟排序
3每趟排序按对应增量ti,将序列分割成若干子序列,分别进行直接插入排序。

简述2

希尔排序实际上是将一维数组分成具有不同列数的二维数组(对应方式,a[i]->a[i/h][i%h])。在每一趟排序中对每一列进行插入排序。列宽也就是增量,增量减小也就是列数减小。
以排序数组a[]={10,8,4,3,1,5,7,9,2,6},增量分别为5,2,1为例:
十大排序算法代码总览(C++)_第2张图片

代码实例
#include
using namespace std;
void swap(int&a, int&b) {
    int tmp = a;
    a = b;
    b = tmp;
}
void shellSort(int a[], int len) {
    int gap = len ;
    while (gap = gap / 2) {//增量
        cout << "每列待排序元素:"<for (int i = gap; i < len; i++) {
            cout << i << " ";
            int key = a[i];//待排序元素
            int j = i - gap;
            for (; j+1>0&&a[j ] > key; j -= gap) {//插入排序
                a[j + gap] = a[j];
            }
            a[j + gap] = key;
        }cout << endl;
         cout << "增量" << gap << "的排序结果:" << endl;
        for (int i = 0; i < len; ++i) {
            cout << " " << a[i];
        }cout <int main() {
    int a[] = { 10,8,4,3,1,5,7,9,2,6};
    int len = sizeof(a) / sizeof(a[0]);
    shellSort(a, len);
    cout << "排序最终结果:";
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}

5归并排序(Merge Sort)

简述

采用递归和分治的思想,首先将数组二分成多个子序列,然后两两子序列进行比较与合并,使其合并为一个完全有序的序列。不断进行比较与合并,使子序列们最终合并为一个完整有序的序列。

算法描述

1将数组二分为多个子序列
2子序列进行排序(注:只有1个元素的序列本身就已经是排序好的序列)
3排序好的子序列间进行比较与合并。
3子序列完全合并为一个有序序列

算法分析

最佳:o(n)
最坏:o(nlogn)
平均:o(nlogn)

#include
using namespace std;

void merge(int a1[], int na1, int a2[], int na2) {
    int tmp[1000];
    int t = 0, i = 0, j = 0,k=0;
    while( i < na1&&j < na2){
        if (a1[i] > a2[j]) {
            tmp[t++] = a2[j++];
        }
        else tmp[t++] = a1[i++];
    }
    while (i < na1) {
        tmp[t++] = a1[i++];
    }
    while (j < na2) {
        tmp[t++] = a2[j++];
    }
    while(kint a[],int len) {
    if (len>1) {
        int mid = len / 2;
        int *a1 = a;
        int na1 = mid;
        int *a2 = a + mid ;
        int na2 = len - mid;
        mergeSort(a1, na1);
        mergeSort(a2, na2);
        merge(a1, na1, a2, na2);
    }
}

int main() {
    int a[] = {0,7,5,2,1,3,8,4,6,9 };
    int len = sizeof(a) / sizeof(a[0]);
    mergeSort(a,len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}

6快速排序(Quick Sort)

简述

分治和递归的应用。选取数组中一个元素为基准(pivot)P,对数组进行排序,使得比P大的元素都在P的右边,比P小的元素在P的左边。然后对以P为分界点的左右子串递归进行快排。

算法描述

1从数列中选取一个元素作为基准;
2进行分区操作(partition)。重新排列数列,使得比基准小的元素都在其左边,比基准小的元素都在它右边,即分为左子列,基准,右子列。
3对左右子列递归进行快排。

算法分析

最好:o(nlogn)
最坏:o(n^2)
平均:o(nlogn)

代码范例1
#include
using namespace std;
void swap(int &a, int &b) {
    int tmp = a;
    a = b;
    b = tmp;
}
void quickSort(int a[], int low, int high) {
    if (low < high) {
        int i = low - 1;
        int j = low;
        int key = a[high];//基准
        for (int j = low; j <= high; ++j) {//使比基准小或等于基准的元素前移。
            if (a[j] <=key) {
                ++i;
                swap(a[i], a[j]);
            }
        }
        quickSort(a, low, i - 1);
        quickSort(a, i + 1, high);
    }
}
int main() {
    int a[] = { 0,4,1,2,3,0,0,0 };
    int len = sizeof(a) / sizeof(a[0]);
    quickSort(a, 0, len - 1);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}
代码范例2
#include
using namespace std;

void quickSort(int a[], int low, int high) {
    if (low >= high)
        return;
    int i, j, key;
    i = low;
    j = high; 
    key = a[low];
    while (i < j) {
        while (i=key) {
            j--;
        }
        a[i] = a[j];
        while (i < j&&a[i] <=key) {
            i++;
        }
        a[j] = a[i];
    }
    a[i] = key;//基准到位
    quickSort(a, low, i - 1);
    quickSort(a, i + 1, high);
}
int main() {
    int a[] = { 0,4,1,2,3,0,0,0 };
    int len = sizeof(a) / sizeof(a[0]);
    quickSort(a, 0, len - 1);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}

7堆排序(Heap Sort)

简述

堆排序是将数组构建成大顶堆,即根节点是数组中最大元素,将根节点与堆底最后一个元素交换,使得最大值排到末尾,即已排序好。将剩下的n-1个元素重新调整为大顶堆,在堆顶/根节点处得到第二大的值,与堆底最后一个元素交换,便又排序好一个元素。

算法描述

1将数组构建成大顶堆
2交换堆顶元素和堆底元素
3调整堆,使其重新成为大顶堆
4重复步骤2和步骤3 n-1次,排序完成。n为数组长度。

算法分析

最好、最坏,平均都为o(nlogn)

代码示例
#include
using namespace std;
void swap(int &a, int &b) {
    int tmp = a;
    a = b;
    b = tmp;
}
void heap(int a[],int node,int len) {
    int nodecopy = a[node];
    for (int i = 2 * node + 1; i < len; i = 2 * i + 1) {//遍历node所有下属节点
        if(i + 1 < len&&a[i + 1] > a[i])//如果右子树节点存在且右子树节点大于左子树,那么将下标移到右子树位置
            i++;
        if (a[i] > a[node]) {
            a[node] = a[i];
            node = i;
        }
    }
    a[node] = nodecopy;//确定a[node]最终位置
}

void heapSort(int a[],int len) {
    for (int node = len / 2 - 1; node >= 0; --node) {
        heap(a, node, len);
    }
    for (int i = len-1;i>0; --i) {
        swap(a[0], a[i]);
        heap(a, 0, i);
    }   
}

int main() {
    int a[] = { 7,0,1,2,8,5,9, };
    int len = sizeof(a) / sizeof(a[0]);
    heapSort(a, len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
}

8计数排序(Count Sort)

简述

非比较排序。计数排序是利用哈希原理,记录元素出现的频次。在统计结束后可以直接遍历哈希表,将数据填回数据空间。由于是空间换时间,所以适合对数据范围集中的数据使用。而且由于用数组下标表示,只适合只有正整数,0的数据。

算法描述

1统计数组中元素出现的频次并找出极值。
2填充原数组。

算法分析

T(n)=O(n+k)
注:k为范围,即新开辟的数组大小

代码示例
#include
using namespace std;
void countSort(int a[], int len) {
    int low = a[0], high = a[0];
    for (int i = 0; i < len; ++i) {//找范围
        low = a[i] < low ? a[i] : low;
        high = a[i] > high ? a[i] : high;
    }
    int range = high - low+1;
    int *count = new int[range];
    memset(count, 0, sizeof(int)*(range));
    for(int i=0;i//统计频次
        count[a[i]-low]++;
    }
    for (int i = 0,j=0; i < range; ++i) {//赋值
        while (count[i]--) {
            a[j++] = i+low;
        }
    }
}
int main() {
    int a[] = { 2, 2, 3, 8, 7,0,4};
    int len = sizeof(a) / sizeof(a[0]);
    countSort(a, len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}

9基数排序(Radix Sort)

简述

非选择排序。将元素依次按低位到高位进行分类排序(个位,十位,百位…)与收集。即分别排序,分别收集。
注:适用范围,最好小于1000;数字为0或正整数。

算法描述

1取得数组中最大位数。
2从低位开始,对数组进行排序。
3将排序好的元素复制到原始数组。
4重复2、3步骤到最高位。排序完成。

算法分析

最好、最差、平均均为O(n*k)注:k为位数。

代码范例
#include
#include
using namespace std;
int getnum(int a[], int len) {

    int max = a[0];
    int num = 1;
    for (int i = 1; i < len; ++i) {
        max=a[i] > max ? a[i] : max;
    }
    while (max /= 10) {
        num++;
    }
    return num;
}
void radixSort(int a[], int len) {
    int num = getnum(a, len);//获得位数
    vector<vector<int>>radix(10);
    for(int k=0;kfor (int i = 0; i < len; ++i) {//存放元素
            int t = int(a[i] / pow(10, k))%10;
            radix[t].push_back(a[i]);
        }
            vector<vector<int> >::iterator p;
            vector<int>::iterator q;
            int i = 0;
            for (p = radix.begin(); p != radix.end(); ++p) {//取出元素
                for (q = (*p).begin(); q !=(*p).end(); ++q) {
                    a[i++] = *q;
                }
            }
            for (int i = 0; i < 10; ++i) {//清空容器中元素
                if(!radix[i].empty())
                        radix[i].clear();
            }

    }
}
int main() {
    int a[] = { 0,1,89,4,45,41,7,9,0,52,80,100 };
    int len = sizeof(a) / sizeof(a[0]);
    radixSort(a, len);
    for (int i = 0; i < len; ++i) {
        cout << " " << a[i];
    }
    getchar();
    return 0;
}

10桶排序(Bucket sort)

简述

顾名思义,桶排序就是把同类元素放在相同的桶里,然后又对桶内元素递归调用桶排序本身,是分治和递归的典型。
计数排序,基数排序以及桶排序的比较:
三者都出现了桶的概念。
计数排序是一个桶只存单一值,
基数排序是根据元素的位数来往桶里存放数据,
而桶排序是存储一定范围的数据。

算法描述

1确定桶的数量和桶区间
2遍历列表把元素放到对应桶里
3重复步骤2,即对桶中元素递归调用桶排序。
4把排序好的元素放回原列表,直到排序完成

算法分析

平均:T(n)=o(n^2)

#include
#include
using namespace std;
int getRange(vector<int> a, int begin, int end,int &min,int &max) {//获得数组元素范围和极值
    for (int i = begin + 1; i <= end; ++i) {
        min = a[i] < min ? a[i] : min;
        max = a[i] > max ? a[i] : max;
    }
    return max - min+1;
}
void bucketSort(vector<int>&a, int begin, int end) {//容器做参数时用引用传递来调换元素顺序,
    if (end - begin <1)
        return;//递归出口
    int min, max;min=max = a[0];
    int range = getRange(a, begin, end, min, max); //获得元素范围和极值
    int bucketNum = 5;//本次定义了5个桶
    int gap = range / 5+1;//设定桶区间
    vector <vector<int > > bucket(bucketNum);//用二维容器来装桶
    for (int i = begin; i <= end; ++i){
        cout << "桶编号: " << (a[i] - min) / gap << "放入元素:" << a[i] << endl;
        bucket[(a[i]-min )/ gap] .push_back( a[i]);//元素放在不同的桶里
    } 
    for (int i = 0; i < bucketNum; ++i) {
        bucketSort( bucket[i],0,bucket[i].size()-1);//对桶里的元素递归调用桶排序
    }
    for (int i = 0,j=0; i < bucketNum; ++i) {
        if (!bucket[i].empty()) {//桶非空判断
            for (vector<int>::iterator p = bucket[i].begin(); p!=bucket[i].end(); ++p) {//桶里排序好的元素放回原容器a
                a[j++] = *p;
            }
        }
    }
    cout << endl;
}
int main() {
    vector<int>a;
    for (int i = 0,j=100; i<20; ++i) {
        a.push_back(j--);
    }
    bucketSort(a, 0, a.size()-1);
    cout << "排序结果:" << endl;
    for (int i = 0; icout << " "<return 0;
}

你可能感兴趣的:(up,up,up)