笔试题:C语言实现顺序栈与进制转换的实现 —— 十进制数转十六进制数
一、背景介绍
栈是一种特殊的线性表,特殊在栈的一端是封闭的,数据的插入与删除只能在栈的另一端进行,也就是栈遵循“后进先出”的原则。也被成为“LIFO”结构,意思是“last input first output”。

栈(stack),存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈(PUSH)、出栈(POP)的说法。
栈就像是一摞书,拿到新书时我们会把它放在书堆的最上面,取书时也只能从最上面的新书开始取。
闭合的一端被称为栈底(Stack Bottom),允许数据的插入与删除的一端被称为栈顶(Stack Top),不包含任何元素的栈被称为空栈。

- 把数据插入到栈空间的动作被称为入栈或者压栈

- 从栈空间中删除数据的动作被称为出栈或者弹栈

由于栈也是一种线性结构,所以可以以数组或者链表作为基础,在此基础上实现栈的操作。
以数组作为基础实现栈空间(顺序栈)

数组在内存中占用一块连续的空间,也就是数组元素的内存地址是连续的。为了实现栈,一般是把数组头作为栈底,数组头部到数组尾部作为栈的增长方向,也就是用户只在数组尾部对数据进行插入和删除。
以链表作为基础实现栈空间(链式栈)

如果打算实现链式栈,一般是以链表作为基础,一般是把链表头部作为栈顶,方便数据的插入和删除(头插+头删),链式栈相当于是一个单向不循环的链表。
本篇博客将展示如何使用顺序栈实现以下功能:
- 顺序栈的实现:创建栈、判断栈满与栈空、栈的入栈与出栈操作等。
- 进制转换:通过栈来实现将十进制数转换为十六进制数。
二、顺序栈的实现
顺序栈使用数组来实现,它包含以下基本操作:
- 入栈:将元素压入栈顶。
- 出栈:从栈顶弹出元素。
- 判断栈是否为空:栈空时返回
true,否则返回false。 - 判断栈是否满:栈满时返回
true,否则返回false。
首先,我们来看看顺序栈的结构和各个操作的实现。
版本:
/**
* @file name : SequenceStack.c
* @brief : C语言实现顺序栈与进制转换的实现 —— 十进制数转十六进制数
* @author : qrshxc@163.com
* @date : 2025/04/24
* @version : 1.0
* @note :
* CopyRight (c) 2025-2026 qrshxc@163.com All Right Reseverd
*/
1. 顺序栈的结构体定义
顺序栈通过一个结构体 SeqStack_t 来表示,其中包含栈底指针 bottom,栈的容量 size,以及栈顶指针 top。
// 顺序栈的数据类型
typedef char DataType_t;
// 构造顺序栈各项参数
typedef struct SequenceStack
{
DataType_t *bottom; // 记录顺序栈栈底地址
unsigned int size; // 记录顺序栈栈容量大小
int top; // 记录顺序栈栈顶元素的下标
} SeqStack_t;
其中,DataType_t 是栈元素的数据类型,在这个例子中我们使用 char 类型。bottom 用于存储栈底的指针,size 存储栈的容量,top 用于记录栈顶元素的位置。
2. 创建顺序栈
/**
* @name SeqStack_create
* @brief 创建顺序栈并对顺序栈进行初始化
* @param size 顺序栈的大小
* @return
* @retval manager 顺序栈的管理结构体
* @date 2025/04/24
* @version 1.0
* @note Manager->Addr ---> [Size*sizeof(DataType_t)]
*/
SeqStack_t *SeqStack_create(unsigned size)
{
// 1.利用calloc给管理结构体manager申请一块堆内存
SeqStack_t *manager = (SeqStack_t *)calloc(1, sizeof(SeqStack_t));
// 错误处理
if (manager == NULL) {
perror("calloc memory for manager is failed!");
exit(-1); // 程序异常终止
}
// 利用calloc给顺序栈栈底申请一块堆内存
manager->bottom = (DataType_t *)calloc(size, sizeof(DataType_t));
// 错误处理
if (manager->bottom == NULL) {
perror("calloc memory for bottom is failed!");
free(manager);
exit(-1);
}
// 2.对栈容量大小进行初始化
manager->size = size;
// 3.顺序栈的栈顶,初始为-1
manager->top = -1;
return manager;
}
函数解析:
- 功能:该函数用于创建顺序栈并初始化。
- 参数:
size表示栈的容量,传入的size用来分配栈底空间。 - 返回值:返回一个顺序栈的管理结构体
manager,其中包含栈底指针、栈容量、栈顶指针。
通过 calloc 动态分配内存,我们确保了栈的管理结构体和栈底空间能够被正确分配。
3. 判断栈是否已满
/**
* @name SeqStack_IsFull
* @brief 判断顺序栈是否已满
* @param manager 顺序栈的管理结构体
* @return
* @retval true 顺序栈已满
* @retval false 顺序栈未满
* @date 2025/04/24
* @version 1.0
* @note
*/
bool SeqStack_IsFull(SeqStack_t *manager)
{
return manager->top + 1 == manager->size ? true : false;
}
函数解析:
- 功能:判断栈是否已满。
- 逻辑:当栈顶指针
top等于栈的容量减1时,栈即为满。
4. 判断栈是否为空
/**
* @name SeqStack_IsEmpty
* @brief 判断顺序栈是否为空
* @param manager 顺序栈的管理结构体
* @return
* @retval true 顺序栈空
* @retval false 顺序栈不为空
* @date 2025/04/24
* @version 1.0
* @note
*/
bool SeqStack_IsEmpty(SeqStack_t *manager)
{
return (manager->top == -1) ? true : false;
}
函数解析:
- 功能:判断栈是否为空。
- 逻辑:当栈顶指针
top为 -1 时,栈为空。
5. 入栈操作
/**
* @name SeqStack_Push
* @brief 入栈
* @param data 插入的元素
* @return
* @retval true 入栈成功
* @retval false 入栈失败
* @date 2025/04/24
* @version 1.0
* @note
*/
bool SeqStack_Push(SeqStack_t *manager, DataType_t data)
{
if (SeqStack_IsFull(manager)) {
printf("SequenceStack is full!\n");
return false;
}
manager->bottom[++manager->top] = data;
return true;
}
函数解析:
- 功能:将数据元素压入栈顶。
- 逻辑:如果栈已满,返回
false;否则,将数据元素压入栈顶,并更新栈顶指针。
6. 出栈操作
/**
* @name SeqStack_Pop
* @brief 出栈
* @param manager 顺序栈的管理结构体
* @return
* @retval temp 出栈值
* @date 2025/04/24
* @version 1.0
* @note
*/
DataType_t SeqStack_Pop(SeqStack_t *manager)
{
DataType_t temp = 0; // 用于管理出栈元素
if (SeqStack_IsEmpty(manager)) {
printf("SequenceStack is empty!\n");
return -1; // 栈空时返回特殊错误值
}
temp = manager->bottom[manager->top--]; // 把栈顶元素赋值给temp并让top-1
return temp;
}
函数解析:
- 功能:从栈顶弹出元素。
- 逻辑:如果栈为空,返回
-1;否则,弹出栈顶元素,并更新栈顶指针。
修改顺序表中指定位置的元素
三、进制转换:十进制转十六进制
通过栈来实现进制转换。在这个程序中,我们将十进制数转换为十六进制数,栈会存储每次除以16得到的余数。通过不断地将余数入栈,最后从栈中出栈即可得到最终的十六进制结果。
/**
* @name SeqStack_Dec2Hex
* @brief 设计一个进制转换程序,使用顺序栈设计一个把十进制数转换为十六进制数的接口,实现当通过键盘输入一个非负的十进制数,可以在终端输出对应的十六进制数。
* @param manager 顺序栈的管理结构体
* @param data 十进制数
* @return
* @retval
* @date 2025/04/24
* @version 1.0
* @note
*/
void SeqStack_Dec2Hex(SeqStack_t *manager, unsigned int data)
{
int raminder; // 用于存储求余之后的余数
do {
raminder = data % 16; // 获取余数
if (raminder < 10) {
SeqStack_Push(manager, raminder + '0'); // 余数小于10,直接转换为字符 '0'-'9'
} else {
SeqStack_Push(manager, raminder + 'A' - 10); // 余数大于等于10,转换为字符 'A'-'F'
}
data /= 16; // 更新商
} while (data != 0); // 循环直到商为0
printf("0x");
while (!SeqStack_IsEmpty(manager)) {
printf("%c", SeqStack_Pop(manager)); // 依次弹出栈中的元素并打印
}
printf("\n");
}
函数解析:
- 功能:该函数将十进制数
data转换为十六进制数并输出。 - 逻辑:通过不断除以16得到每一位的余数,余数入栈,直到商为0。最后通过出栈输出十六进制表示。
四、测试及结果
int main(int argc, char const *argv[])
{
// 创建一个顺序栈,栈大小为5
SeqStack_t *stack = SeqStack_create(5);
// 入栈操作
SeqStack_Push(stack, 10); // 入栈10
SeqStack_Push(stack, 20); // 入栈20
SeqStack_Push(stack, 30); // 入栈30
SeqStack_Push(stack, 40); // 入栈40
SeqStack_Push(stack, 50); // 入栈50
// 此时栈已满,无法继续入栈
if (!SeqStack_Push(stack, 60)) {
printf("无法入栈60,栈已满!\n");
}
// 打印当前栈中的元素
printf("栈内元素如下:\n");
SeqStack_Print(stack);
// 出栈操作
printf("\n出栈元素:%d\n", SeqStack_Pop(stack)); // 出栈
printf("\n出栈元素:%d\n", SeqStack_Pop(stack)); // 出栈
// 打印当前栈中的元素
printf("栈内元素如下:\n");
SeqStack_Print(stack);
printf("进制转换如下:\n");
SeqStack_Dec2Hex(stack, 100);
// 清理栈的内存
free(stack->bottom); // 释放栈底的内存
free(stack); // 释放管理结构体内存
return 0;
}
结果
SequenceStack is full!
无法入栈60,栈已满!
栈内元素如下:
Stack Element[0] = 10
Stack Element[1] = 20
Stack Element[2] = 30
Stack Element[3] = 40
Stack Element[4] = 50
出栈元素:50
出栈元素:40
栈内元素如下:
Stack Element[0] = 10
Stack Element[1] = 20
Stack Element[2] = 30
进制转换如下:
0x64
通过顺序栈的实现,我们成功地将十进制数转换为十六进制数,并且展示了顺序栈的常见操作,如入栈、出栈、栈空和栈满的判断等。栈是一种非常重要的数据结构,广泛应用于编程中。
通过本文的实现,我们不仅学习了顺序栈的基本操作,还通过栈来实现了实际的进制转换功能。希望这个博客能够帮助你理解顺序栈的应用及其实现原理。如果你有任何问题,欢迎留言讨论!

浙公网安备 33010602011771号