2.几种排序算法

1.冒泡排序:

相邻两个数比较换位置;最终最后的元素会是最大值,重复…

#include <iostream>
using namespace std;
template<typename T> //整数或浮点数皆可使用,若要使用类(class)或结构体(struct)时必须重载大于(>)运算符
void bubble_sort(T arr[], int len) {
        int i, j;
        for (i = 0; i < len - 1; i++)
                for (j = 0; j < len - 1 - i; j++)
                        if (arr[j] > arr[j + 1])
                                swap(arr[j], arr[j + 1]);
}
int main() {
        int arr[] = { 61, 17, 29, 22, 34, 60, 72, 21, 50, 1, 62 };
        int len = (int) sizeof(arr) / sizeof(*arr);
        bubble_sort(arr, len);
        for (int i = 0; i < len; i++)
                cout << arr[i] << ' ';
        cout << endl;
        float arrf[] = { 17.5, 19.1, 0.6, 1.9, 10.5, 12.4, 3.8, 19.7, 1.5, 25.4, 28.6, 4.4, 23.8, 5.4 };
        len = (float) sizeof(arrf) / sizeof(*arrf);
        bubble_sort(arrf, len);
        for (int i = 0; i < len; i++)
                cout << arrf[i] << ' '<<endl;
        return 0;
}

2.选择排序:

首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置;再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾;重复第二步,直到所有元素均排序完毕。

void selection_sort(vector<int>& arr) {
        for (int i = 0; i < arr.size() - 1; i++) {
                int min = i;
                for (int j = i + 1; j < arr.size(); j++)
                        if (arr[j] < arr[min])
                                min = j;
                swap(arr[i], arr[min]);
        }
}

3.插入排序

将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

void insertion_sort(vector<int> &nums, int n) {
    for (int i = 0; i < n; ++i) {
        for (int j = i; j > 0 && nums[j] < nums[j-1]; --j) {
            swap(nums[j], nums[j-1]);
        }
    }
}

4.希尔排序

希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序。

void shell_sort(int array[], int length) {
    int h = 1;
    while (h < length / 3) {
        h = 3 * h + 1;
    }
    while (h >= 1) {
        for (int i = h; i < length; ++i) {
            for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {
                swap(array[j], array[j - h]);
            }
        }
        h = h / 3;
    }
}

5.归并排序

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法,归并排序对序列的元素进行逐层折半分组,然后从最小分组开始比较排序,合并成一个大的分组,逐层进行,最终所有的元素都是有序的。(对两个有序的小数组排序合并成一个大数组)

#include<iostream>
#include<string>
#include<vector>
#include<cmath>
using namespace std;

void MergeSort(vector <int>& nums, int l, int r, vector<int>& temp){
    if(l+1 >= r) return;
    int mid = l + (r - l)/2;
    MergeSort(nums, l, mid, temp);
    MergeSort(nums, mid, r, temp);
    //将两个有序的小数组合并成一个大数组;
    int p = l, q = mid, i = l;
    while (p < mid || q < r)
    {
        //当p<mid,并且nums[p]<nums[q],将p指针加1;或者q已经到达最后
        if(q >= r || p < mid && nums[p] < nums[q]){
            temp[i++] = nums[p++];
        }else{
            temp[i++] = nums[q++];
        }
        for(i = l; i < r; ++i){
            nums[i] = temp[i];
        }
    }
}

6.快速排序

从数列中挑出一个元素,称为 "基准"(pivot);   重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

void quickSort(vector<int>& nums,int l,int r){
    if(l >= r){
        return;
    }
    int first = l, last = r, key = nums[first];
    while(first < last){
        while(first < last && nums[last] >= key){
            --last;
        }
        nums[first] = nums[last];
        while(first < last && nums[first] <= key){
            ++first;
        }
        nums[last] = nums[first];
    }
    nums[first] = key;
    quickSort(nums, l ,first-1);
    quickSort(nums,first+1,r);
}

7.堆排序

堆排序(Heapsort)是利用二叉堆的概念来排序的选择排序的算法。

大根堆:每个节点的值都大于左右孩子的值,arr(i)>arr(2*i+1) && arr(i)>arr(2*i+2)

1、首先将无需数组构造成一个大根堆(新插入的数据与其父结点比较)

2、固定一个最大值,将剩余的数重新构造成一个大根堆,重复这样的过程

//构造大根堆
void max_heapify(int arr[], int start, int end){
    int parent = start;
    int child = parent*2 + 1;
    while (child <= end){
        //比较两个孩子的大小选择大的;
        if(child + 1 <= end && arr[child] < arr[child + 1]){
            ++child;
        }
        //比较孩子和父节点的大小
        if(arr[child] > arr[parent]){
            swap(arr[child], arr[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
    }
}
void heap_sort(int arr[],int len){
    //初始化,从最后一个节点开始调整;
    for(int i = len/2 - 1; i >= 0; --i){
        max_heapify(arr, i, len-1);
    }
    //将第一个元素和已经排好位置的第一个元素的前一个交换位置,并重新构建大根堆
    for(int i = len -1; i > 0; --i){
        swap(arr[0], arr[i]);
        max_heapify(arr, 0, i-1);
    }
}

8.计数排序

第一次遍历序列,找出序列中的最大值以及最小值,然后根据最大值MAX最小值MIN创建一个MAX-MIN+1长度的数组;第二次遍历,将该元素所对应的区间数组进行对应的位置进行+1操作;第三步,打印元素。

int* countSort(int arr[], int len){
    //找到最大和最小的元素
    int max = arr[0];
    int min = arr[0];
    for(int i = 0; i < len - 1; ++i){
        if(arr[i] > max){
            max = arr[i];
        }
        if(arr[i] < min){
            min = arr[i];
        }
    }
    //存储Max-Min+1的数列长度;
    int l = max - min + 1;
    int* couarr = new int[l];// 0~l,定义长度为l+1;
    for(int i = 0; i < l; ++i){
        couarr[arr[i] - min]++;//统计元素个数;
    }

    int sum = 0;
    for(int i = 0; i < l+1; ++i){
        //“统计数组”变形 后面是前面的和
        sum += couarr[i];
        couarr[i] = sum; 
    }
    int* sortarr = new int[len];
    for(int i = len - 1; i>=0; --i){
        //倒序遍历原始数组从统计数组中找到对应的位置,
        //创建一个新的数组来存储已经排序完成的结果
        sortarr[couarr[arr[i]-min] - 1] = arr[i];
        --couarr[arr[i] - min];
    }
	delete couarr;
	return sortarr;
}

9.桶排序

划分多个范围相同的区间,每个子区间自排序,最后合并。

桶排序是计数排序的扩展版本,计数排序可以看成每个桶只存储相同元素,而桶排序每个桶存储一定范围的元素,通过映射函数,将待排序数组中的元素映射到各个对应的桶中,对每个桶中的元素进行排序,最后将非空桶中的元素逐个放入原序列中。

/*
桶排序
*/
void insert(list<int>& bucket,int val)
{
    auto iter = bucket.begin();
    while(iter != bucket.end() && val >= *iter) ++iter;
    //insert会在iter之前插入数据,这样可以稳定排序
    bucket.insert(iter,val);
}


void BucketSort(vector<int>& arr)
{
    int len = arr.size();
    if(len <= 1) return;
    int min = INT_MAX,max = INT_MIN;
    for(int i = 1; i < len; ++i){
        if(min > arr[i]) min = arr[i];
        if(max < arr[i]) max = arr[i];
    }
    int k = 10;//k为数字之间的间隔
    //向上取整 除以10 后+1
    int bucketsNum = (max - min)/k + 1;
    vector<list<int> > buckets(bucketsNum);//构造一个长度为bucketsNum向量,每个由链表组成
    for(int i = 0; i < len; ++i){
        int value = arr[i];
        insert(buckets[(value - min)/k], value);
    }
    int index = 0;
    for( int i = 0; i < bucketsNum; ++i){
        if(buckets[i].size()){
            for(auto& value:buckets[i]){//value的值从bucket[i]的第一个值到最后一个
                arr[index ++] = value;
            }
        }
    }
}

10.基数排序

首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中

按个位数0~9从队列型先进先出

接着再进行一次分配,这次是根据十位数来分配,直至最高位

/*
基数排序
*/
//求最大位数,确定排序次数
int maxBit(int date[], int n)
{
    int maxBits = 1;
    int carryDate = 10;
    for(int i = 0; i < n; ++i){
        while(date[i] < carryDate){
            carryDate*=10;
            ++maxBits;
        }
    }
    return maxBits;
}
//基数排序
void redixSort(int arr[], int len)
{
    int maxBits = maxBit(arr, len);
    int count[10];//计数器
    int tmp[len];
    int redix = 1;
    for(int i = 1; i <= maxBits; ++i){//进行第i次排序
        for(int j = 0; j < 10; ++j){//每次分配前清空计数器
            count[j] = 0;
        }
        for(int j = 0; j < len; ++j){
            int k = (arr[j]/redix) % 10;//统计每个桶中的记录数
            ++count[k];
        }
        for(int j = 1; j < 10; ++j){
            count[j] = count[j - 1] + count[j];//将记录数变成和的形式,为了将tmp中的位置依次分配给每个桶
        }
        for(int j = len - 1; j >= 0; --j){//将所有桶中记录依次收集到tmp中
            int k = (arr[j]/redix) % 10;
            tmp[count[k] - 1] = arr[j]; //从桶中后进后出(排在后面)
            --count[k];
        }
        for(int j = 0; j < len; ++j){//从临时数组中恢复回来
            arr[j] = tmp[j];
        }
        redix = redix * 10;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值