详解堆栈的几种实现方法——C语言版基本的抽象数据类型(ADT)是编写C程序必要的过程,这类ADT有链表、堆栈、队列和树等,本文主要讲解下堆栈的几种实现方法以及他们的优缺点。
堆栈(stack)的显著特点是后进先出(Last-In First-Out, LIFO),其实现的方法有三种可选方案:静态数组、动态分配的数组、动态分配的链式结构。
静态数组:特点是要求结构的长度固定,而且长度在编译时候就得确定。
其优点是结构简单,实现起来方便而不容易出错。
而缺点就是不够灵活以及固定长度不容易控制,适用于知道明确长度的场合。
动态数组:特点是长度可以在运行时候才确定以及可以更改原来数组的长度。
优点是灵活,缺点是由此会增加程序的复杂性。
链式结构:特点是无长度上线,需要的时候再申请分配内存空间,可最大程度上实现灵活性。
缺点是链式结构的链接字段需要消耗一定的内存,在链式结构中访问一个特定元素的效率不如数组。
首先先确定一个堆栈接口的头文件,里面包含了各个方案下的函数原型,放在一起是为了实现程序的模块化以及便于修改。
然后再接着分别介绍各个方案的具体实施方法。
堆栈接口stack.h文件代码:[cpp]view plaincopy1./*2.** 堆栈模块的接口 stack.h3.*/4.#include<stdlib.h>5.6.#define STACK_TYPE int /* 堆栈所存储的值的数据类型 */7.8./*9.** 函数原型:create_stack10.** 创建堆栈,参数指定堆栈可以保存多少个元素。
11.** 注意:此函数只适用于动态分配数组形式的堆栈。
12.*/13.void create_stack(size_t size);14.15./*16.** 函数原型:destroy_stack17.** 销毁一个堆栈,释放堆栈所适用的内存。
18.** 注意:此函数只适用于动态分配数组和链式结构的堆栈。
19.*/20.void destroy_stack(void);21.22./*23.** 函数原型:push24.** 将一个新值压入堆栈中,参数是被压入的值。
25.*/26.void push(STACK_TYPE value);27.28./*29.** 函数原型:pop30.** 弹出堆栈中栈顶的一个值,并丢弃。
31.*/32.void pop(void);33.34./*35.** 函数原型:top36.** 返回堆栈顶部元素的值,但不改变堆栈结构。
37.*/38.STACK_TYPE top(void);39.40./*41.** 函数原型:is_empty42.** 如果堆栈为空,返回TRUE,否则返回FALSE。
43.*/44.int is_empty(void);45.46./*47.** 函数原型:is_full48.** 如果堆栈为满,返回TRUE,否则返回FALSE。
49.*/50.int is_full(void);一、静态数组堆栈在静态数组堆栈中,STACK_SIZE表示堆栈所能存储的元素的最大值,用top_element 作为数组下标来表示堆栈里面的元素,当top_element == -1的时候表示堆栈为空;当top_element == STACK_SIZE - 1的时候表示堆栈为满。
push的时候top_element加1,top_element == 0时表示第一个堆栈元素;pop的时候top_element减1。
a_stack.c 源代码如下:[cpp]view plaincopy1./*2.**3.** 静态数组实现堆栈程序 a_stack.c ,数组长度由#define确定4.*/5.6.#include"stack.h"7.#include<assert.h>8.#include<stdio.h>9.10.#define STACK_SIZE 100 /* 堆栈最大容纳元素数量 */11.12./*13.** 存储堆栈中的数组和一个指向堆栈顶部元素的指针14.*/15.static STACK_TYPE stack[STACK_SIZE];16.static int top_element = -1;17.18./* push */19.void push(STACK_TYPE value)20.{21. assert(!is_full()); /* 压入堆栈之前先判断是否堆栈已满*/22. top_element += 1;23. stack[top_element] = value;24.}25.26./* pop */27.void pop(void)28.{29. assert(!is_empty()); /* 弹出堆栈之前先判断是否堆栈已空 */30. top_element -= 1;31.}32.33./* top */34.STACK_TYPE top(void)35.{36. assert(!is_empty());37.return stack[top_element];38.}39.40./* is_empty */41.int is_empty(void)42.{43.return top_element == -1;44.}45.46./* is_full */47.int is_full(void)48.{49.return top_element == STACK_SIZE - 1;50.}51.52./*53.** 定义一个print函数,用来打印堆栈里面的元素。
54.*/55.void print(void)56.{57.int i;58. i = top_element;59. printf("打印出静态数组堆栈里面的值: ");60.if(i == -1)61. printf("这是个空堆栈\n");62.while(i!= -1)63. printf("%d ",stack[i--]);64. printf("\n");65.}66.int main(void)67.{68. print();69. push(10); push(9); push(7); push(6); push(5);70. push(4); push(3); push(2); push(1); push(0);71. printf("push压入数值后:\n");72. print();73. printf("\n");74. pop();75. pop();76. printf("经过pop弹出几个元素后的堆栈元素:\n");77. print();78. printf("\n");79. printf("top()调用出来的值: %d\n",top());80.return 1;81.}结果如下图:二、动态数组堆栈头文件还是用stack.h,改动的并不是很多,增加了stack_size变量取代STACK_SIZE 来保存堆栈的长度,数组由一个指针来代替,在全局变量下缺省为0。
create_stack函数首先检查堆栈是否已经创建,然后才分配所需数量的内存并检查分配是否成功。
destroy_stack函数首先检查堆栈是否存在,已经释放内存之后把长度和指针变量重新设置为零。
is_empty 和is_full 函数中添加了一条断言,防止任何堆栈函数在堆栈被创建之前就被调用。
d_stack.c源代码如下:[cpp]view plaincopy1./*2.** 动态分配数组实现的堆栈程序 d_stack.c3.** 堆栈的长度在创建堆栈的函数被调用时候给出,该函数必须在任何其他操作堆栈的函数被调用之前条用。
4.*/5.#include"stack.h"6.#include<stdio.h>7.#include<malloc.h>8.#include<assert.h>9.10./*11.** 用于存储堆栈元素的数组和指向堆栈顶部元素的指针12.*/13.static STACK_TYPE *stack;14.static int stack_size;15.static int top_element = -1;16.17./* create_stack */18.void create_stack(size_t size)19.{20. assert(stack_size == 0);21. stack_size = size;22. stack = (STACK_TYPE *)malloc(stack_size * sizeof(STACK_TYPE));23.if(stack == NULL)24. perror("malloc分配失败");25.}26.27./* destroy */28.void destroy_stack(void)29.{30. assert(stack_size > 0);31. stack_size = 0;32. free(stack);33. stack = NULL;34.}35.36./* push */37.void push(STACK_TYPE value)38.{39. assert(!is_full());40. top_element += 1;41. stack[top_element] = value;42.}43.44./* pop */45.void pop(void)46.{47. assert(!is_empty());48. top_element -= 1;49.}50.51./* top */52.STACK_TYPE top(void)53.{54. assert(!is_empty());55.return stack[top_element];56.}57.58./* is_empty */59.int is_empty(void)60.{61. assert(stack_size > 0);62.return top_element == -1;63.}64.65./* is_full */66.int is_full(void)67.{68. assert(stack_size > 0);69.return top_element == stack_size - 1;70.}71.72.73./*74.** 定义一个print函数,用来打印堆栈里面的元素。