当前位置: 首页 > news >正文

【数据结构】堆、计数、桶、基数排序的实现 - 实践

1. 堆排序

1.1 算法思想

堆排序(Heap Sort)是一种基于堆数据结构的排序算法。其核心思想是将待排序的元素构建成一个最大堆或最小堆,然后依次将堆顶元素与堆中最后一个元素交换,并重新调整堆,使得剩余元素重新满足堆的性质。重复这个过程直到所有元素都被取出,就得到了一个有序的序列。

1.2 算法步骤

  1. 建立一个大根堆(升序)。
  2. 将堆顶元素与堆底末尾元素交换,这时待排序中最大元素成功放到正确的位置,并且将堆中待排序的元素个数 size --。
  3. 然后对堆顶元素进行向下调整,使剩余待排序元素重新形成一个大根堆。
  4. 重复步骤2,3直至待排序元素个数 size = 1,排序完成。

1.3 动画演示

1.4 代码实现

void AdjustDown(int* arr, int n, int parent)
{int child = 2 * parent + 1;while (child < n){if (child + 1 < n && arr[child] < arr[child + 1]){child++;}if (arr[child] > arr[parent]){swap(&arr[child], &arr[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}
void HeapSort(int* arr, int n)
{//向下调整建堆for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(arr, n, i);}int end = n - 1;while (end > 0){swap(&arr[0], &arr[end]);AdjustDown(arr, end, 0);end--;}
}

2. 计数排序

2.1 算法思想

计数排序(Counting Sort)是一种非比较性的排序算法,适用于一定范围内的整数排序。其核心思想是统计每个元素出现的次数,然后根据这个统计信息,将元素放置到正确的位置上。

2.2 算法步骤

1. 找出待排序数组中的最大值max和最小值min。
2. 创建一个长度为max - min + 1的计数数组count,用于存储每个元素出现的次数。
3. 遍历待排序数组,统计每个元素出现的次数,将其存储在计数数组中相应的位置上。
4. 根据计数数组中的统计信息,将待排序数组重新排列。
5. 将排好序的元素从计数数组中放回待排序数组中。

2.3 动画演示

2.4 代码实现

void CountSort(int* arr, int n)
{//找出最大与最小元素int max = arr[0];int min = arr[0];for (int i = 0; i < n; i++){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}int range = max - min + 1;int* countArray = (int*)malloc(sizeof(int) * range);if (countArray == NULL){perror("malloc fail:");return;}//初始化memset(countArray, 0, sizeof(int) * range);//统计各元素出现次数for (int i = 0; i < n; i++){countArray[arr[i] - min]++;}int j = 0;for (int i = 0; i < range; i++){while (countArray[i]--){arr[j++] = i + min;}}
}

3. 桶排序

3.1 算法思想

桶排序(Bucket Sort) 是一种适用于一定范围内的元素排序的算法。其核心思想是将待排序的元素分配到有限数量的桶中,然后分别对每个桶中的元素进行排序,最后按照顺序将各个桶中的元素依次取出,得到有序序列。

3.2 算法步骤

1. 确定桶的每个桶的元素个数和桶的数量,将待排序数组中的元素分配到对应的桶中。
每个桶的元素个数:bucketsize=(max-min)/n+1,max,min,n分别为数组最大元素,最小元素,以及元素个数。每个桶的范围就是:[min,bucketsize),[min+bucketsize,min+2*bucketsize)…
桶的数量:bucketnum=(max-min)/bucketsize+1,bucketsize为每个桶的元素个数。
2. 对每个桶中的元素进行排序,可以选择其他排序算法。
3. 将各个桶中的元素按照顺序取出,组成最终的有序序列。

为什么 bucketnum 与 bucketsize 的计算最后要加1

1. 首先是因为除法运算的结果是可以等于0的,而桶的数量与桶最大容纳个数是不可能为0,所以需要加1。

2. 其次我们默认每个桶的范围是左闭右开区间,如果不加1最大的元素可能无法进入桶内。

3.3 动画演示

3.4 代码实现

void BucketSort(int* arr, int n)
{//找出最大与最小元素int max = arr[0];int min = arr[0];for (int i = 0; i < n; i++){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}//每个桶的元素最大个数int bucketsize = (max - min) / n + 1;//桶的个数int bucketnum = (max - min) / bucketsize + 1;int bucket[bucketnum][bucketsize];int bucketcount[bucketnum];//每个桶当前元素个数计数器memset(bucket, 0, sizeof(bucket));memset(bucketcount, 0, sizeof(bucketcount));//将元素放入桶中for (int i = 0; i < n; i++){int index = (arr[i] - min) / bucketsize;//第几个桶bucket[index][bucketcount[index]] = arr[i];bucketcount[index]++;//第几个桶的个数++}for (int i = 0; i < bucketnum; i++){QuickSort(bucket[i], 0, bucketcount[i] - 1);}for (int i = 0; i < bucketnum; i++){int t = 0;for (int j = 0; j < bucketcount[i]; j++){arr[t++] = bucket[i][j];}}
}

4. 基数排序

4.1 算法思想

基数排序(Radix Sort)是一种非比较性的排序算法,适用于对整数或字符串等元素进行排序。其核心思想是将待排序的元素按照位数进行分组,然后依次对每个位数进行稳定的排序,最终得到有序序列。

4.2 算法步骤

1. 确定待排序元素的最大位数,通常通过计算最大元素的位数或者最高位数来确定。
2. 从最低位开始,依次对元素按照当前位上的数值进行分组,并且统计每个数组出现次数记录在counter数组中。(十进制的位范围为 0~9 ,因此需要长度为 10 的统计数组)
3. 利用前缀和counter[i] = counter[i - 1] + counter[i]求出每个对应数值的最后一个元素的下标索引。
4. 倒序遍历,通过每个元素arr[i]的当前位上的值求出下标索引j=counter[i]-1,并将该元素存入新的数组ret[j]=arr[i]中,最后以ret数组覆盖原数组达到排序该位数的目的。

5. 重复步骤2,3,4直至达到最大元素的位数,排序完毕。

1. 按个位排序

2. 按十位排序

4.3 动画演示

4.4 代码实现

//获取当前位数的值
int digit(int num, int exp)
{return (num / exp) % 10;
}
//对当前位数进行排序
void CountSortDigit(int arr[], int n, int exp) {// 十进制的位范围为 0~9 ,因此需要长度为 10 的统计数组int* counter = (int*)malloc((sizeof(int) * 10));if (counter == NULL){perror("malloc fail:");return;}//初始化memset(counter, 0, sizeof(int) * n);// 统计 0~9 各数字的出现次数for (int i = 0; i < n; i++){int d = digit(arr[i], exp);counter[d]++;}// 求前缀和,将“出现个数”转换为“数组索引”for (int i = 1; i < 10; i++){counter[i] += counter[i - 1];}// 倒序遍历,根据统计数组内统计结果,将各元素填入 retint* ret = (int)malloc(sizeof(int) * n);if (ret == NULL){perror("malloc fail:");return;}memset(ret, 0, sizeof(int) * n);for (int i = n - 1; i >= 0; i--){int d = digit(arr[i], exp);int j = counter[d] - 1; // 获取 d 在数组中的索引 jret[j] = arr[i]; // 将当前元素填入索引 jcounter[d]--;}// 覆盖原数组for (int i = 0; i < n; i++){arr[i] = ret[i];}
}
void RadixSort(int*arr, int n)
{// 获取数组的最大元素,用于判断最大位数int max = arr[0];for (int  i = 0; i < n ; i++){if (arr[i] > max){max = arr[i];}}// 按照从低位到高位的顺序遍历for (int exp = 1; max >= exp; exp *= 10){CountSortDigit(arr, n, exp);}
}

http://www.gsyq.cn/news/32905.html

相关文章:

  • 2025年光伏支架钢管品牌排行榜
  • Zotero说明
  • 今天的实习可以把新出的中小厂的岗位都投一遍
  • error 找不到模块“../views/Login.vue”或其相应的类型声明
  • java学习(自用)
  • 脑电数据PCA处理及SVM分类
  • 2025 年盐城异常处理,盐城行业资质,盐城财务代账,盐城会计代账公司最新推荐,聚焦资质、案例、售后的五家公司深度解读
  • 如何在Windows下开发输入法:Mini How to
  • 2025 年 10 月盐城公司变更,盐城地址挂靠,盐城商标注册公司最新推荐,聚焦资质、案例、售后的五家公司深度解读
  • 第一天学习
  • K3s + Sysbox:让容器拥有“虚拟机的灵魂”
  • 题解:AT_abc200_e [ABC200E] Patisserie ABC 2
  • CF1996G Penacony
  • 远程命令执行漏洞、SSRF、XXE、tomcat弱口令漏洞
  • Ollama API 交互
  • 项目冷场?用禅道协作白板激活团队的创新思维!
  • 2025年桥洞力学板市场趋势与选购指南:江苏同芯木业江苏行业领先
  • 吴恩达深度学习课程二: 改善深层神经网络 第一周:深度学习的实践(一)
  • Ollama 运行模型
  • 2025 年矿井轴流通风机,矿井抽出式轴流对旋通风机,矿井压入式对旋轴流通风机,FKD 系列矿井压入式对旋轴流通风机厂家最新推荐,实力品牌深度解析采购无忧之选
  • 2025 年矿用隔爆型压入式轴流通风机,FKZ 系列矿井轴流通风机,FKCDZ 系列矿井抽出式轴流对旋通风机厂家最新推荐,聚焦资质、案例、售后的五家机构深度解读
  • 第一次编程作业完结撒花!!!
  • 2025年沈阳/北京/东三省制造业企业商业秘密保护权威推荐榜单:高新技术企业与上市公司数据安全解决方案精选
  • 2025沈阳/北京/东三省制造业企业商业秘密保护厂家推荐大宸商业,专业合规护航企业发展
  • LangGraph MCP - 使用LangGraph构建多智能体工作流(六)
  • 告别卡顿与等待,Rancher Vai 让集群操作“秒响应”
  • 2025 年铝型材框架、铝型材围栏、6063 铝型材、重型铝型材厂家最新推荐 —— 产能、专利、环保三维数据透视
  • 2025 年碳化硅金刚线切割机,石墨金刚线切割机,陶瓷金刚线切割机厂家最新推荐,产能、专利、适配性三维数据透视
  • 2025 年 10 月油石、保温材料、玉石、石英金刚线切割机厂家最新推荐,产能、专利、环保三维数据透视
  • 2025 年 10 月瓦楞纸、蜂窝铝、硬质合金金刚线切割机厂家最新推荐,实力品牌深度解析采购无忧之选!