笔试题:C语言实现顺序栈与进制转换的实现 —— 十进制数转十六进制数

一、背景介绍

栈是一种特殊的线性表,特殊在栈的一端是封闭的,数据的插入与删除只能在栈的另一端进行,也就是栈遵循“后进先出”的原则。也被成为“LIFO”结构,意思是“last input first output”。

栈介绍

栈(stack),存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈(PUSH)、出栈(POP)的说法。

栈就像是一摞书,拿到新书时我们会把它放在书堆的最上面,取书时也只能从最上面的新书开始取。

闭合的一端被称为栈底(Stack Bottom),允许数据的插入与删除的一端被称为栈顶(Stack Top),不包含任何元素的栈被称为空栈。

栈步骤分解

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

入栈

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

出栈

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

以数组作为基础实现栈空间(顺序栈)

顺序栈

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

以链表作为基础实现栈空间(链式栈)

链式栈

如果打算实现链式栈,一般是以链表作为基础,一般是把链表头部作为栈顶,方便数据的插入和删除(头插+头删),链式栈相当于是一个单向不循环的链表。

本篇博客将展示如何使用顺序栈实现以下功能:

  1. 顺序栈的实现:创建栈、判断栈满与栈空、栈的入栈与出栈操作等。
  2. 进制转换:通过栈来实现将十进制数转换为十六进制数。

二、顺序栈的实现

顺序栈使用数组来实现,它包含以下基本操作:

  • 入栈:将元素压入栈顶。
  • 出栈:从栈顶弹出元素。
  • 判断栈是否为空:栈空时返回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

通过顺序栈的实现,我们成功地将十进制数转换为十六进制数,并且展示了顺序栈的常见操作,如入栈、出栈、栈空和栈满的判断等。栈是一种非常重要的数据结构,广泛应用于编程中。

通过本文的实现,我们不仅学习了顺序栈的基本操作,还通过栈来实现了实际的进制转换功能。希望这个博客能够帮助你理解顺序栈的应用及其实现原理。如果你有任何问题,欢迎留言讨论!

posted @ 2025-04-25 22:35  九思0404  阅读(19)  评论(0)    收藏  举报