首页 > 其他分享 >堆排序 桶排序 基数排序

堆排序 桶排序 基数排序

时间:2023-09-02 17:36:14浏览次数:33  
标签:index arr int 堆排序 基数排序 数组 排序 节点

堆排序

使用数组和表示堆大小的整数heapSize表示堆:

vector<int> arr{9, 5, 3, 7, 2};
int heapSize = 5;

heapSize = 5 表示数组从索引0开始的5个元素表示一个堆。

堆结构就是用数组实现的完全二叉树结构。

求数组中索引i位置节点的父子节点:

父节点: (i - 1) / 2

左子节点: 2 * i + 1

右子节点: 2 * i + 2

表示堆的完全二叉树还有一个性质:

完全二叉树中每棵子树的最大值都在堆顶。(对应大根堆)

优先级队列结构,就是堆结构。

堆排序:

1.依次把数组元素加入大根堆

2.依次取出堆顶元素放在数组最后,并调整大根堆。

时间复杂度:O(N * logN)   额外空间复杂度:O(1)

void swap(vector<int>& arr, int i, int j){
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

// 把数组index位置的元素加入大根堆
void heapInsert(vector<int>& arr, int index){
    // 如果父节点值更大
    while(arr[(index - 1) / 2] < arr[index]){
        // 父子节点交换
        swap(arr, (index - 1) / 2, index);
        // 循环来到原父节点处
        index = (index - 1) / 2;
    }
}

// 调整大根堆(因此时堆顶元素并非最大元素)
void heapify(vector<int>& arr, int index, int heapSize){
    // 计算左子节点
    int left = 2 * index + 1;
    // 如果左子节点在堆中存在
    while(left < heapSize){
        // large表示左子节点和右子节点中更大者
        int large = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
        // 如果父节点大于或等于左子节点更大者,large = 父节点
        large = arr[index] >= arr[large] ? index : large;
        // 如果large = 父节点 则堆已调整好,return
        if(large == index){
            return;
        }
        // 将父节点与左右子节点中更大者交换
        swap(arr, large, index);
        // 循环来到左右子节点中更大者处
        index = large;
        // 计算左子节点,继续while循环
        left = 2 * index + 1;
    }
}

void heapSort(vector<int>& arr){
    if(arr.empty() || arr.size() < 2){
        return;
    }
    // 把数组元素依次加入大根堆
    for(int i = 0; i < arr.size(); i++){
        heapInsert(arr, i);
    }
    int heapSize = arr.size();
    // 取出堆顶元素放在数组最后
    swap(arr, 0, --heapSize);
    // 只要堆不为空
    while(heapSize > 0){
        // 调整大根堆
        heapify(arr, 0, heapSize);
        // 取出堆顶元素放在数组最后
        swap(arr, 0, --heapSize);
    }
}

堆排序扩展题目

已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数组进行排序。

假设 k = 6,则:

取数组0~6位置的数放入小根堆里,取出堆顶元素放在数组0位置,再将数组7位置的数放入小根堆里,取出堆顶元素放在1位置

时间复杂度O(N * logk)

// 仿函数cmp<int>   等同于语言自带的greater<int>
// 如果是 return x < y 则等同于语言自带的less<int>
template<class T>
    struct cmp{
        bool operator()(T x, T y){
            return x > y;
        }
    };

void sortDistanceLessK(vector<int>& arr, int k){
    // 定义小根堆用greater<int> 大根堆用less<int> 刚好相反!!
    // 缺省情况下默认为less<>
    priority_queue<int, vector<int>, cmp<int>> q;
    // index表示把arr中第几个元素加入到小根堆
    int index = 0;
    for(; index <= k; index++){
        q.push(arr[index]);
    }
    // i表示把小根堆堆顶元素放到arr中i位置上
    int i = 0;
    for(; index < arr.size(); index++, i++){
        arr[i] = q.top();q.pop();
        q.push(arr[index]);
    }
    while(!q.empty()){
        arr[i++] = q.top();q.pop();
    }
}

int main(){
    vector<int> nums {1, 4, 3, 4, 2, 4, 6, 8, 9, 10, 12};
    sortDistanceLessK(nums, 3);
    for(int num : nums){
        cout << num;
    }
}

桶排序

与基于比较的排序不同,桶排序是基于数据特征对数据排序

假设数据范围都在0-99,对数据排序可以统计每一个数出现的频率

最后依次输出所有数据,时间复杂度O(N)

基数排序

先对所有数据在个位排序,再对十位排序,再对百位排序...

对所有数据的第d位排序时,使用10个桶,从左往右遍历数组,根据第d位的值将数放入相应桶中,最后从第1个桶开始,把桶里的数据倒出来。

最先放入桶的数据最先被倒出来。

int maxbits(vector<int>& arr){
    int max = INT_MIN;
    for(int i : arr){
        max = i > max ? i : max;
    }
    int res = 0;
    while(max != 0){
        res++;
        max /= 10;
    }
    return res;
}

// 获取数字x的从右往左第d位的值
int getDigit(int x, int d){
    while(d > 1){
        x /= 10;
        d--;
    }
    return x % 10;
}

void radixSort(vector<int>& arr, int l, int r, int digit){
    // 拷贝数组,存放每次桶排序的结果
    vector<int> bucket(r - l + 1, 0);
    // 数组的最大值有几位,就要进行几次桶排序
    for(int d = 1; d <= digit; d++){
        // count[i]表示arr数组中第d位小于等于i的数字有多少个
        vector<int> count(10, 0);
        // 先统计arr数组中第d位等于i的数字有多少个
        for(int i = l; i <= r; i++){
            count[getDigit(arr[i], d)]++;
        }
        // 累加得到 arr数组中第d位小于等于i的数字有多少个
        for(int i = 1; i < 10; i++){
            count[i] = count[i] + count[i - 1];
        }
        /*
        count[j]表示arr数组中第d位小于等于j的数有多少
        相当于count数组把整个l-r范围按第d位的值分为10片
        count[j]表示第j分片的右边界索引
        从右往左遍历,当前数第d位是j
        因此应将当前数拷贝到bucket数组从左往右第count[j]个位置(count[j]-1)
        将count[j]--:下次找到d位同样为j的数就可以拷贝到当前数的前一位置
        */
        for(int i = r; i >= l; i--){
            int j = getDigit(arr[i], d);
            bucket[count[j] - 1] = arr[i];
            count[j]--;
        }
        // 把本次排序结果从bucket数组拷贝到arr
        for(int i = l, j = 0; i <= r; i++, j++){
            arr[i] = bucket[j];
        }
    }
}

void radixSort(vector<int>& arr){
    if(arr.empty() || arr.size() < 2){
        return;
    }
    // maxbits(arr) 表示arr数组中最大值的位数
    radixSort(arr, 0, arr.size() - 1, maxbits(arr));
}

标签:index,arr,int,堆排序,基数排序,数组,排序,节点
From: https://blog.51cto.com/u_15724083/7333904

相关文章

  • qlist 对结构体排序
    结构体排序:写法一QList<test>s;testaa;testbb;testcc;aa.num="14";bb.num="2";cc.num="3";s.append(aa);s.append(bb);s.append(cc);qSort(s.begin(),s.end(),[](consttest&infoA......
  • 常用的七大排序算法
    1.七大排序算法简述1.1选择排序算法思想:进行n轮操作在某一轮中,选择未排序的一个最小数组元素,与右侧未排序的第一个数组元素交换交换完之后,相当于向右扩大已排序的数组范围。重复2,3.直至所有数组元素已排序稳定性:不稳定假设在某一轮数组状态为:1,2,3,8,8,4。已排序的元......
  • 基数排序
     基数排序,不是基于比较的排序。过程如下:处理过程:  桶排过程:1voidBucket_sort(inta[],intexp)//exp为1按个位排序,exp为10按十位排序,exp为100按个位排序,……2{3vector<int>Bucket[20];45//按位入桶,+10是为了对付负数6for(int......
  • 数据结构与——八大经典排序算法详解
    ......
  • 错位排序
    将1到n的自然数放到1到n的n个位置,其中元素i不放在位置i,求方案总数。状态:dp[i]表示前i个位置错位排序的方案数答案:dp[n]状态转移方程:\(dp[i]=(i-1)*(dp[i-1]+dp[i-2])\)情况1:前i-1个位置有0个位置是元素与下标相同的,将元素i与前i-1个位置的任一元素对调构成错位,贡......
  • C++ 数组排序 查找。数值排序、冒泡排序以及顺序查找的方法
    #include<iostream>#include<cstring>#include<algorithm>#include<ctime>#defineMAX8usingnamespacestd; intmain() {   inta[MAX]={1,5,9,6,3,1,4,6};  for(inti=0;i<MAX;i++)   cout<<a[i]<<"";    ......
  • js实现汉字中文排序
    js实现汉字中文排序的方法数组内的元素是对象,以对象某一个属性进行排序vararr=[{name:'南京',code:'09',info:{province:'江苏'}},{name:'北京',code:'01',info:{province:'北京'}},{name:'上海',code:'02&......
  • 选择排序输出多轮学号
    题目描述有n名学生从左往右排成一行站成队列,学号是1至n。给出这n名学生的身高,学号是i的学生的身高是h[i],所有学生的身高都不相同。现在进行n-1轮操作,第i轮操作由如下三个步骤构成:第一步:从当前学生队列排在第i个位置的学生至排在最后一个位置的学生当中,选出身高最矮的学生,不妨假......
  • vue sort 排序
    Vue.js提供了多种实现排序的方式。下面列举了几种常见的排序方法及示例代码。 1、使用JavaScript原生的Array.prototype.sort()方法进行排序。这种方法适用于简单的数组排序需求。//在Vue组件中的方法中使用sort方法进行排序data(){return{myArray:[3,1,2,4......
  • hive-四种排序
    数据准备200832.0200821.0200831.5200817.0201334.0201532.0201533.0201515.9201531.0201519.9201527.0201623.0201639.9201632.0建表createtableods_temperature(yearint,......