数据结构和算法——桶排序和基数排序(图示、伪代码、多关键字排序,基数排序代码)

news2025/5/21 21:00:14

目录

桶排序

图示

伪代码

时间复杂度

基数排序

多关键字排序

代码(C语言)

次位优先

主位优先


桶排序

假设有N个学生,他们的成绩是0到100之间的整数(于是有M=101个不同的成绩值)。如何在线性时间内将学生按成绩排序?

桶排序的处理方法是: 

建立M个桶,一开始初始化为空链表;插入成绩值时,找到对应的桶,链接到对应的桶里面。

图示

 

伪代码

void Bucket_Sort(ElementType A[], int N)
{
    count[]初始化;
    while(读入1个学生的成绩grade)
    {
        将该生插入count[grade]链表;
    }
    for(i = 0; i < M; i++)
    {
        if(count[i])
            输出整个count[i]链表;
    }
}

时间复杂度

这个桶排序的时间复杂度很好分析,从伪代码上看是两个循环,一个读入N个学生的成绩,一个输出链表里的M个元素,所以:

T(N,M)=O(M+N)

如果M\gg N,例如有101个不同的成绩值,但是要排序的学生只有5个,那么再用桶排序去建立101个桶就显得很浪费了,这个时候就引进我们的基数排序~

基数排序

事实上,基数排序是桶排序的升级版。我们先看一个例子:

假设我们有N = 10个整数,每个整数的值在0到999之间(于是有M=1000个不同的值)。还有可能在线性时间内排序吗?

输入序列:64,8,216,512,27,729,0,1,343,125。

这里用“次位优先”(Least Significant Digit) ,简称LSD。

次位优先的意思是说:从个位开始往高位比较。例如:一个三位数就是先比较个位,再比较十位,最后比较百位;与之相反的则是先比较百位,再比较十位,最后比较个位,即

“主位优先”(Most Significant Digit),简称MSD。


据题意可知,我们需要排序十个整数,故而建立十个桶,然后第一趟依据个位数进行排序:

第二趟依据十位数进行排序:

将排序结果收集起来: 

最后一趟依据百位数来进行排序:

最后再收集结果,就得到我们的有序序列了:

 如此,就完成了一次次位优先的基数排序。

时间复杂度T=O(P(N+B))

N为需要收集排序的整数个数,B为桶的个数,P为排序的趟次。

多关键字排序

类似于扑克牌,一副扑克牌是按2种关键字排序的:

K^0[花色]

K^1[面值] ​​​​​​​

有序结果: 

用“主位优先”MSD排序:先为花色建4个桶,在每个桶内分别排序,最后合并结果。

用“次位优先”LSD排序:先为面值建13个桶,将结果合并,然后再为花色建4个桶。

 

代码(C语言)

代码链接:数据结构_浙江大学_中国大学MOOC(慕课)

次位优先

/* 基数排序 - 次位优先 */

/* 假设元素最多有MaxDigit个关键字,基数全是同样的Radix */
#define MaxDigit 4
#define Radix 10

/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node {
    int key;
    PtrToNode next;
};

/* 桶头结点 */
struct HeadNode {
    PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
 
int GetDigit ( int X, int D )
{ /* 默认次位D=1, 主位D<=MaxDigit */
    int d, i;
    
    for (i=1; i<=D; i++) {
        d = X % Radix;
        X /= Radix;
    }
    return d;
}

void LSDRadixSort( ElementType A[], int N )
{ /* 基数排序 - 次位优先 */
     int D, Di, i;
     Bucket B;
     PtrToNode tmp, p, List = NULL; 
     
     for (i=0; i<Radix; i++) /* 初始化每个桶为空链表 */
         B[i].head = B[i].tail = NULL;
     for (i=0; i<N; i++) { /* 将原始序列逆序存入初始链表List */
         tmp = (PtrToNode)malloc(sizeof(struct Node));
         tmp->key = A[i];
         tmp->next = List;
         List = tmp;
     }
     /* 下面开始排序 */ 
     for (D=1; D<=MaxDigit; D++) { /* 对数据的每一位循环处理 */
         /* 下面是分配的过程 */
         p = List;
         while (p) {
             Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 */
             /* 从List中摘除 */
             tmp = p; p = p->next;
             /* 插入B[Di]号桶尾 */
             tmp->next = NULL;
             if (B[Di].head == NULL)
                 B[Di].head = B[Di].tail = tmp;
             else {
                 B[Di].tail->next = tmp;
                 B[Di].tail = tmp;
             }
         }
         /* 下面是收集的过程 */
         List = NULL; 
         for (Di=Radix-1; Di>=0; Di--) { /* 将每个桶的元素顺序收集入List */
             if (B[Di].head) { /* 如果桶不为空 */
                 /* 整桶插入List表头 */
                 B[Di].tail->next = List;
                 List = B[Di].head;
                 B[Di].head = B[Di].tail = NULL; /* 清空桶 */
             }
         }
     }
     /* 将List倒入A[]并释放空间 */
     for (i=0; i<N; i++) {
        tmp = List;
        List = List->next;
        A[i] = tmp->key;
        free(tmp);
     } 
}

主位优先

/* 基数排序 - 主位优先 */

/* 假设元素最多有MaxDigit个关键字,基数全是同样的Radix */

#define MaxDigit 4
#define Radix 10

/* 桶元素结点 */
typedef struct Node *PtrToNode;
struct Node{
    int key;
    PtrToNode next;
};

/* 桶头结点 */
struct HeadNode {
    PtrToNode head, tail;
};
typedef struct HeadNode Bucket[Radix];
 
int GetDigit ( int X, int D )
{ /* 默认次位D=1, 主位D<=MaxDigit */
    int d, i;
    
    for (i=1; i<=D; i++) {
        d = X%Radix;
        X /= Radix;
    }
    return d;
}

void MSD( ElementType A[], int L, int R, int D )
{ /* 核心递归函数: 对A[L]...A[R]的第D位数进行排序 */
     int Di, i, j;
     Bucket B;
     PtrToNode tmp, p, List = NULL; 
     if (D==0) return; /* 递归终止条件 */
     
     for (i=0; i<Radix; i++) /* 初始化每个桶为空链表 */
         B[i].head = B[i].tail = NULL;
     for (i=L; i<=R; i++) { /* 将原始序列逆序存入初始链表List */
         tmp = (PtrToNode)malloc(sizeof(struct Node));
         tmp->key = A[i];
         tmp->next = List;
         List = tmp;
     }
     /* 下面是分配的过程 */
     p = List;
     while (p) {
         Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 */
         /* 从List中摘除 */
         tmp = p; p = p->next;
         /* 插入B[Di]号桶 */
         if (B[Di].head == NULL) B[Di].tail = tmp;
         tmp->next = B[Di].head;
         B[Di].head = tmp;
     }
     /* 下面是收集的过程 */
     i = j = L; /* i, j记录当前要处理的A[]的左右端下标 */
     for (Di=0; Di<Radix; Di++) { /* 对于每个桶 */
         if (B[Di].head) { /* 将非空的桶整桶倒入A[], 递归排序 */
             p = B[Di].head;
             while (p) {
                 tmp = p;
                 p = p->next;
                 A[j++] = tmp->key;
                 free(tmp);
             }
             /* 递归对该桶数据排序, 位数减1 */
             MSD(A, i, j-1, D-1);
             i = j; /* 为下一个桶对应的A[]左端 */
         } 
     } 
}

void MSDRadixSort( ElementType A[], int N )
{ /* 统一接口 */
    MSD(A, 0, N-1, MaxDigit); 
}

end 


学习自:MOOC数据结构——陈越、何钦铭

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/790431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是在线帮助中心?

随着企业越来越注重客户体验和服务质量&#xff0c;建立一个完善的在线帮助中心已经成为企业不可或缺的一部分。在线帮助中心可以帮助客户解决各种问题&#xff0c;从而提升客户满意度和忠诚度。而Baklib作为一款优雅的云知识库构建平台&#xff0c;提供了一种简单高效的方式来…

网页聊天室项目性能测试报告

文章目录 一 概述二 测试环境三 测试内容及方法四 GUI测试步骤五 简单数据写入器 HTML报告DashBoard六 结果分析七 性能优化方案 一 概述 1.1 目的 本测试报告为网页聊天室的性能测试报告&#xff0c;目的在于总结性能测试阶段的学习以及分析测试结果&#xff0c;描述网站是否…

创建线程的两种方式

一、线程相关概念 程序&#xff1a;完成特定任务&#xff0c;用某种语言编写的一组指令的集合。进程&#xff1a;运行起来的程序就是进程。进程运行时&#xff0c;操作系统需要为该进程分配内存空间。进程是一个动态过程&#xff0c;有产生、存在和消亡的过程。线程&#xff1…

osg earth中加载标签并设置文字 以及使用注意事项

osgearth中加载标签并设置文字 //头文件 #include <osgEarthAnnotation/PlaceNode> #include <osgEarthSymbology/Style> #include <osgEarth/MapNode> osgEarth::GeoPoint position(m_mapnode->getMapSRS(), lon, lat, 0, osgEarth::AltitudeMode::ALTM…

数据驱动商业合作:企业联系方式查询API在市场中的角色与作用

摘要 在当今数字化商业环境中&#xff0c;企业间的商务合作和合作伙伴关系构建变得更加重要。为了有效推进商业拓展和建立持久合作&#xff0c;企业需要快速、准确地获取潜在合作伙伴的联系方式。本文将深入探讨企业联系方式查询 API 在市场中的角色与作用&#xff0c;以及它如…

JetBrains全家桶:如何自定义实现类TODO注释?

文章目录 效果图具体方法参考文献 效果图 TODO注释大家应该都用过&#xff0c;在注释开头打上TODO的话&#xff0c;软件下方的TODO选项卡里就可以自动筛选出你打了TODO的注释&#xff0c;你可以点击里面对应的注释来实现快速跳转。 jetbrains全家桶&#xff08;如Pycharm、Int…

LKT(LCS)系列IIC接口加密芯片

调试常见问题&#xff08;一&#xff09; 1.加密芯片的数据交互协议是什么格式&#xff1f; 发送时&#xff1a;地址两字节数据长度&#xff08;后续数据的长度&#xff09;后续数据内容。Eg.50 0005 0084000008。接收时&#xff1a;地址两字节数据长度&#xff08;后续数据的…

万字长文详解Webpack5高级优化

本文从 4 个角度对 webpack 和代码进行了优化&#xff1a; 1.提升开发体验 使用 Source Map 让开发或上线时代码报错能有更加准确的错误提示。 2.提升打包构建速度 使用 HotModuleReplacement 让开发时只重新编译打包更新变化了的代码&#xff0c;不变的代码使用缓存&#xff…

Github Flow工作流简单介绍(以部署为中心的开发模式)

前言 这篇文章主要介绍Github Flow的理念&#xff0c;以下内容来源于《Github入门与实践》。 Github Flow是以部署为中心的开发模式&#xff0c;通过简单的规则&#xff0c;持续高速且安全地进行部署。而Gitflow则是以发布为中心的分支管理模型&#xff0c;它提供了一种更灵活…

【Docker】Docker容器编排

目录 一、Docker Compose1.2Docker Compose 环境安装1.3 YAML 文件格式及编写注意事项2.3 Docker Compose配置常用字段2.4 Docker Compose 常用命令 二、Docker Compose实验2.1编写Nginx的Dockerfile脚本2.2编写MySQL&#xff0c;Dockerfile脚本2.3编写PHP&#xff0c;Dockerfi…

QT样式表qss中的长度单位px/pt/%/em/ex/mm/in等

以下是从CSS里抄来的。QSS只能支持其中一部分。 1、px&#xff1a;像素(Pixel),相对于设备的长度单位&#xff0c;像素是相对于显示器屏幕分辨率而言的。譬如&#xff0c;WONDOWS的用户所使用的分辨率一般是96像素/英寸。而MAC的用户所使用的分辨率一般是72像素/英寸。 像素&a…

在培训班里学IT技术是否有用?和大家分享相关IT培训班里五大常见宣传手法、相关优势与实际效果

目录 Introduction 引言IT培训班常见宣传手法培训班的优势如何评判IT培训班的效果与质量除IT培训班之外的学习渠道总结其它资料下载 Introduction 引言 随着信息技术的飞速发展&#xff0c;学习IT技术成为许多人追求职业发展和个人兴趣的重要途径。从软件开发、数据科学到人工…

OpenAI Code Interpreter 的开源实现:GPT Code UI

本篇文章聊聊 OpenAI Code Interpreter 的一众开源实现方案中&#xff0c;获得较多支持者&#xff0c;但暂时还比较早期的项目&#xff1a;GPT Code UI。 写在前面 这篇文章本该更早的时候发布&#xff0c;但是 LLaMA2 发布后实在心痒难忍&#xff0c;于是就拖了一阵。结合 L…

插件使用权限管理软件(一)框架选择和Furion框架搭建

项目背景 软件主要服务于传统设计院&#xff0c;用于管理和监控设计院内部插件的使用权限和使用情况。可根据使用的频率来对插件使用情况的分析。后续可以加上错误报告等提测报告&#xff0c;使整个监控插件使用情况更加流程化。由于博主主要做CAD和Revit的二次开发工作&#x…

【力扣每日一题】2023.7.25 将数组和减半的最少操作次数

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一个数组&#xff0c;我们每次可以将任意一个元素减半&#xff0c;问我们操作几次之后才可以将整个数组的和减半&…

实例025 带分隔栏的窗体

实例说明 在软件开发中&#xff0c;经常需要将界面分成几个部分&#xff0c;而且这几个部分又可以自由调整大小。运行本例&#xff0c;实例效果如图1.25所示。 技术要点 在.NET 2.0框架中可以非常轻松的实现这一功能&#xff0c;只要在窗体中加入SplitContainer控件即可。Sp…

2023年深圳杯数学建模A题影响城市居民身体健康的因素分析

2023年深圳杯数学建模 A题 影响城市居民身体健康的因素分析 原题再现&#xff1a; 以心脑血管疾病、糖尿病、恶性肿瘤以及慢性阻塞性肺病为代表的慢性非传染性疾病&#xff08;以下简称慢性病&#xff09;已经成为影响我国居民身体健康的重要问题。随着人们生活方式的改变&am…

Cesium态势标绘专题-自由多边形(标绘)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

红外雨量计(光学雨量传感器)调试

红外雨量计&#xff08;光学雨量传感器&#xff09;调试 红外雨量计是一种用来测量雨量的传感器&#xff0c;它通过红外线的反射来检测雨滴的落下。为了调试红外雨量计&#xff0c;你需要参考以下步骤&#xff1a; 1. 确认传感器的电源接线正确。检查传感器的接线是否正确&…

软工导论知识框架(二)结构化的需求分析

本章节涉及很多重要图表的制作&#xff0c;如ER图、数据流图、状态转换图、数据字典的书写等&#xff0c;对初学者来说比较生僻&#xff0c;本贴只介绍基础的轮廓&#xff0c;后面会有单独的帖子详解各图表如何绘制。 一.结构化的软件开发方法&#xff1a;结构化的分析、设计、…