• C复习-堆栈和队列


    参考: 里科《C和指针》- 经典抽象数据类型

    本章涉及堆栈、队列、二叉搜索树、泛型等,代码太多,应该参考leetcode题目。本文只包含栈的数组实现(静态数组和动态数组)和链表实现,以及队列的数组实现。


    堆栈 stack

    1)使用静态数组实现堆栈

    • 把不属于外部接口的内容都声明为static,可以防止用户越界访问。
    • 使用assert防止非法操作,针对的是用户可以自己检查的内容
    • 使用is_full和is_empty是为了之后可以修改测试空堆栈和满堆栈的情况
    /*
    * 堆栈的接口 stack.h
    */
    #define STACK_TYPE int
    
    /* 把一个新值压到堆栈中 */
    void push(STACK_TYPE value);
    
    /* 从堆栈中弹出一个值,并将其丢弃 */
    void pop(void);
    
    /* 返回栈顶元素,但不对堆栈进行修改*/
    STACK_TYPE top(void);
    
    /* 如果堆栈为空,返回TRUE,否则FALSE */
    int is_empty(void);
    
    /* 如果堆栈已满,返回TRUE,否则FALSE */
    int is_full(void);
    
    /* ************************** */
    /* 用一个静态数组实现堆栈,数组的长度只能通过修改#define定义,并重新编译实现 */
    #include "stack.h"
    #include 
    
    /* 堆栈中值数量的最大限制 */
    #define STACK_SIZE 100
    
    /* 存储堆栈中值的数组和一个指向堆栈顶部元素的指针 */
    static STACK_TYPE stack[ STACK_SIZE ];
    static int top_element = -1;
    
    /* 把一个新值压到堆栈中 */
    void push(STACK_TYPE value) {
    	assert( !is_full() );
    	top_element += 1;
    	stack[top_element] = value;
    }
    
    /* 从堆栈中弹出一个值,并将其丢弃 */
    void pop(void) {
    	assert( !is_empty() );
    	top_element -= 1;
    }
    
    /* 返回栈顶元素,但不对堆栈进行修改*/
    STACK_TYPE top(void) {
    	assert( !is_empty() );
    	return stack[top_element];
    }
    
    /* 如果堆栈为空,返回TRUE,否则FALSE */
    int is_empty(void) {
    	return top_element == -1;
    }
    
    /* 如果堆栈已满,返回TRUE,否则FALSE */
    int is_full(void) {
    	return top_element == ( STACK_SIZE - 1 );
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    2)使用动态数组实现堆栈

    • 内存有限的环境中,使用assert检查内存是否分配成功不合适,因为失败的话直接停止了。可以让create_stack返回一个值,提示内存是否分配成功,如果失败的话,用户可以换小一点的值再试。
    
    /* 创建堆栈,size指定可以保存多少个元素 */
    void create_stack( size_t size);
    /* 销毁堆栈,释放内存 */
    void destroy_stack( void );
    
    /* 相比静态数组实现,需要添加和修改的地方如下,其他函数不变 */
    #include 
    
    /* 存储堆栈中值的数组和一个指向堆栈顶部元素的指针 */
    static STACK_TYPE *stack;
    static size_t stack_size;
    static int top_element = -1;
    
    void create_stack(size_t size) {
    	assert( stack_size == 0 );
    	stack_size = size;
    	stack = (STACK_TYPE *)malloc( stack_size * sizeof(STACK_TYPE) );
    	assert( stack != NULL );
    }
    
    void destroy_stack(void) {
    	assert( stack_size > 0 );
    	stack_size = 0; // 设置size
    	free(stack); // 释放空间
    	stack = NULL; // 指针设为NULL
    }
    
    /* 如果堆栈为空,返回TRUE,否则FALSE */
    int is_empty(void) {
    	assert( stack_size > 0 ); // 增加
    	return top_element == -1;
    }
    
    /* 如果堆栈已满,返回TRUE,否则FALSE */
    int is_full(void) {
    	assert(stack_size > 0); // 增加
    	return top_element == ( stack_size - 1 );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    3)链式堆栈

    • stack指针一直指向栈顶
    • 因为链式堆栈不会满,所以is_full始终是FALSE,且创建时不需要做工作
    • destroy_stack使用了is_empty和pop
    #define FALSE 0
    
    typedef struct STACK_NODE {
    	STACK_TYPE value;
    	struct STACK_NODE *next;
    } StackNode;
    
    /* 指向堆栈中第一个节点的指针 */
    static StackNode *stack;
    
    void create_stack(size_t size) {}
    
    void destroy_stack(void) {
    	while (!is_empty())
    		pop();
    }
    
    /* 把一个新值压到堆栈中 */
    void push(STACK_TYPE value) {
    	StackNode* new_node;
    	new_node = (StackNode*)malloc(sizeof(StackNode));
    	assert(new_node != NULL);
    	new_node->value = value;
    	new_node->next = stack;
    	stack = new_node;
    }
    
    /* 从堆栈中弹出一个值,并将其丢弃 */
    void pop(void) {
    	StackNode* first_node;
    	assert( !is_empty() );
    	first_node = stack; // 改指向
    	stack = first_node->next; 
    	free(first_node); // 释放
    }
    
    /* 返回栈顶元素,但不对堆栈进行修改*/
    STACK_TYPE top(void) {
    	assert( !is_empty() );
    	return stack->value;
    }
    
    /* 如果堆栈为空,返回TRUE,否则FALSE */
    int is_empty(void) {
    	return stack == NULL;
    }
    
    /* 如果堆栈已满,返回TRUE,否则FALSE */
    int is_full(void) {
    	return FALSE;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    队列

    队列的接口:

    /*
    * 队列的接口 queue.h
    */
    #define QUEUE_TYPE int
    
    /* 只适用于动态分配数组的队列 */
    void create_queue(size_t size);
    
    /* 只适用于链式和动态分配数组的队列 */
    void destroy_queue(void);
    
    void insert(QUEUE_TYPE value);
    
    void _delete(void);
    
    QUEUE_TYPE first(void);
    
    /* 如果堆栈为空,返回TRUE,否则FALSE */
    int is_empty(void);
    
    /* 如果堆栈已满,返回TRUE,否则FALSE */
    int is_full(void);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    为了尽可能利用空间,使用循环数组

    • 留一个空间不用,使得队列“满”时front和rear的值不同
    • front和rear可以用任何值初始化
    • 队列空的条件是(rear + 1) % QUEUE_SIZE == front
    • 队列满的条件是(rear + 2) % QUEUE_SIZE == front
    #define QUEUE_SIZE 100 /* 队列中元素的最大数量 */
    #define ARRAY_SIZE (QUEUE_SIZE + 1)
    
    static QUEUE_TYPE queue[ ARRAY_SIZE ];
    static size_t front = 1; // 从1开始.当只有1个元素时都指向1
    static size_t rear = 0;
    
    void insert(QUEUE_TYPE value) {
    	assert( !is_full() );
    	rear = (rear + 1) % ARRAY_SIZE;
    	queue[rear] = value;
    }
    
    /*
    * 删除元素时只要移动front即可
    */
    void _delete(void) {
    	assert( !is_empty() );
    	front = (front + 1) % ARRAY_SIZE; 
    }
    
    QUEUE_TYPE first(void) {
    	assert( !is_empty() );
    	return queue[front];
    }
    
    int is_empty(void) {
    	return (rear + 1) % ARRAY_SIZE == front;
    }
    
    int is_full(void) {
    	return (rear + 2) % ARRAY_SIZE == front;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    401、基于51单片机的电压源(2挡,LCD1602,36V)(程序+Proteus仿真+原理图+流程图+元器件清单+硬件系统框图+配套资料等)
    关闭bitlocker加密
    【pytest-html】深度探索pytest-html测试报告的自定义使用
    【VR开发】【Unity】0-课程简介和概述
    FindMy网络帮助您找到电动车
    使用SSH ,让windows和linux互通
    大模型技术实践(四)|参数高效微调技术解析及AdaLoRA的应用
    第63篇 QML 之 JS中的代码块、条件语句
    成都理工大学_Python程序设计_第4章
    Dom操作指南
  • 原文地址:https://blog.csdn.net/pxy7896/article/details/134523785