算法-7 十大排序

概括

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
  • 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
  • 内排序:所有排序操作都在内存中完成;
  • 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
  • 时间复杂度: 一个算法执行所耗费的时间。
  • 空间复杂度:运行完一个程序所需内存的大小。

image

image

冒泡排序

一点一点移动,最大的放在最后

vector<int> insertionSort(vector<int> arr){
    if(arr.size() == 0) return arr;
    for(int i = 0; i < arr.size(); i++){
        bool flag = false;
        for(int j = 0; j < n - i - 1; j++){
            if(arr[j] > arr[j+1]){
                swap(arr[j], arr[j + 1]);
                flag = true;
            }
        }
        if(flag == false) break;
    }
    return arr;
}

优化:一次遍历之后没有元素交换提前终止

选择排序

每次选择最小的放在最前面

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

插入排序

把每个向前元素放到该放的位置

vector<int> insertionSort(vector<int> arr){
    if(arr.size() == 0) return arr;
    for(int i = 1; i < arr.size(); i++){
        int cru = arr[i];
        int pre = i - 1;
        while(pre >= 0 && arr[pre] > cru){
            arr[pre + 1] = arr[pre]; //向后挪动
            pre--;
        }
        arr[pre+1] = cru;//放到该放的位置,pre注定多减了一次,所以+1
    }
    return arr;
}

希尔排序

分组进行插入排序

vector<int> sheelSort(vector<int> arr){
    if(arr.size() == 0) return arr;
    int gap = arr.size() / 2;
    while(gap > 0){
        for(int i = gap; i < arr.size(); i++){
            int cru = arr[i];
            int pre = i - gap;
            while(pre >= 0 && arr[pre] > cru){
                arr[pre + gap] = arr[pre];
                pre -= gap;
            }
            arr[pre + gap] = cru;
        }
        gap /= 2;
    }
    return arr;
}

归并排序

分治

一直向下分到最小,然后每一组进行排序(开辟新数组,挑选左右两区间内最小的放到新数组里,一直到两个数组都放完,再复制回去)

void merge_sort(int q[], int l, int r)
{
    if (l >= r) return;//退出条件

    //分治向下分
    int mid = l + r >> 1;
    merge_sort(q, l, mid); 
    merge_sort(q, mid + 1, r);

    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
        if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
        else tmp[k ++ ] = q[j ++ ];
    }//挑选左右两个数组中最小的元素不断放入tmp
    while (i <= mid) tmp[k ++ ] = q[i ++ ];
    while (j <= r) tmp[k ++ ] = q[j ++ ];

    //再装回原数组中
    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

快速排序

  • 判断退出条件
  • 确定分界点 mid
  • 指针移动+交换
  • 递归
void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[(l + r ) / 2];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j), quick_sort(q, j + 1, r);
}

堆排序

堆就是用数组储存的,左儿子2x, 右儿子2x+1

堆排序思想:把数组想成堆,排成堆,然后再从堆顶一个一个换

vector<int> heapSort(vector<int> arr){
    if(arr.size() == 0) return arr;
    buildHeap(arr);
    int i = arr.size() - 1;
    while(i > 0){
        swap(arr[0], arr[i]);
        i--;
        adjustHeap(arr,0);
    }
    return arr;
}

void buildHeap(vector<int> arr){
    //从最后一个非叶子节点开始向上构造最大堆
    for(int i = (2 * arr.size() - 1); i >= 0; i--){
        adjustHeap(arr, i);
    }
}

//其实就是down操作
void adjustHeap(vector<int> arr, int i){
    int maxIndex = i;
    //如果有左子树并且大于父节点,最大指针指向左子树
    if(i * 2 < arr.size() && arr[i * 2] > arr[i]) maxIndex = i * 2;
    //如果有右子树并且大于父节点,最大指针指向右子树
    if(i * 2 + 1 < arr.size() && arr[i * 2 + 1] > arr[i]) maxIndex = i * 2 + 1;
    if(maxIndex != i){
        swap(arr[maxIndex], arr[i]);
        adjustHeap(arr,maxIndex);
    }
}

计数排序

统计每个元素出现的个数存到新数组中,遍历储存数组进行排列

vector<int> countingSort(vector<int> arr){
    if(arr.size() == 0) return arr;
    //bias偏移值
    int bias, min = arr[0], max = arr[0];
    for(int i = 1; i < arr.size(); i++){
        if(arr[i] > max) max = arr[i];
        if(arr[i] < min) min = arr[i];
    }
    bias = 0 - min;
    vector<int> bucket(max - min + 1, 0);
    for(int i = 0; i < arr.size(); i++){
        bucket[arr[i] + bias]++;
    }
    int k = 0;
    for(int i = 0; i < bucket.size(); i++){
        while(bucket[i] > 0){
            arr[k++] = i;
            bucket[i]--;
        }
    }
}

桶排序

计数排序的变化版

分区间作为桶,把每个元素放进桶里,每个桶排序,再放原数组;

vector<int> bucektSort(vector<int> arr){
    if(arr.size() == 0) return arr;
    int min = arr[0];
    int max = arr[0];
    
    for(int i = 1; i < arr.size(); i++){
        if(arr[i] > max) max = arr[i];
        if(arr[i] < min) min = arr[i];
    }
    //创建d/5+1个桶,每个桶存放5*i ~ 5*i + 5-1范围的数
    int bucketNum = max - min / 5 + 1;
    //初始化桶
    vector<vector<int>> bucket(bucketNum, vector<int>(0,0));
    //放入桶中
    for(int i = 0; i < arr.size(); i++){
        bucket[(arr[i] - min) / d].push_back(arr[i] - min);
    }
    //每个桶内排序
    for(int i = 0; i < bucketNum; i++){
        sort(bucket[i].begin(), bucket[i].end());
    }
    //存放结果
    int k = 0;
    for(int i = 0; i < bucketNum; i++){
        for(int j = 0; j < bucket[i].size(); j++){
            arr[k++] = bucket[i][j] + min;
        }
    }
    return arr;
}

基数排序

从个位开始排,然后排十位…

vector<int> radixSort(vector<int> arr){
    if(arr.size() == 0) return arr;
    int max = arr[0];
    for(int i = 1; i < arr.size(); i++){
        if(arr[i] > max) max = arr[i];
    }
    
    int maxDigit = 0;
    while(max != 0){
        max /= 10;
        maxDigit++;
    }
    
    int mod = 10, div = 1;
    
    vector<vector<int>> bucket(10, vector<int>(0,0));
    for(int i = 1; i <= maxDigit; i++){
        int mod = pow(10, i);
        int div = pow(10, i - 1);
        for(int j = 0; j < arr.size(); j++){
            int num = (arr[j] % pow) / 10;
            bucket[num].push_back(arr[j]);
        }
        int k = 0;
        for(int j = 0; j < 10; j++){
            for(int k = 0; k < bucket[j].size(); k++){
                arr[k++] = bucket[i][j];
            }
            bucket[j].clear();
        }
    }
    return arr;
}

题目

  • 179.最大数(从结果出发进行比较)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Prince_H_23

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值