本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。
一、 基本概念
堆栈这种数据结构最鲜明的特点就是后进先出(Last-In First-Out, LIFO)的方式。
二、接口实现
基本的堆栈操作通常被称为push 和 pop。push就是把一个新值压入到堆栈的顶部,pop就是把这个堆栈顶部的值移出堆栈并返回这个值。堆栈只是提供对它顶部值的访问。
在传统的堆栈接口中,访问顶部元素的唯一方法就是把它移除。另一类堆栈接口提供三种基本的操作:push, pop 和 top。push操作和前面描述的一样,pop只把顶部元素从堆栈中移除,它并不返回这个值。top返回顶部元素的值,但它并不把顶部元素从堆栈中移除。
三、实现方式
1. 静态数组堆栈:这种实现方式简单明了,但是堆栈的大小是固定的。
2. 动态数组堆栈:这种实现方式,堆栈的大小由调用者决定;确定大小之后,由 malloc 动态的去创建堆栈。但是这种方式还是要依赖于数组。
3. 链式堆栈:
由于只有堆栈的顶部元素才可以被访问,所以使用单链表就可以很好地实现链式堆栈。把一个新元素压入到堆栈只是通过在链表的起始位置添加一个元素实现的。从堆栈中弹出一个元素是通过从链表中移除第一个元素实现的。位于链表头部的元素总是很容易被访问的。( 如果对链表使用有不熟悉的地方,请参考C语言:链表这一节)由于存储元素的内存是动态分配的,它必须予以释放以避免内存泄露。
四、代码实现(链式堆栈的实现方式)
1. 定义一个结构以存储堆栈元素,其中next字段将指向堆栈的下一个元素。
typedef struct STACK_NODE {
STACK_TYPE value;
struct STACK_NODE *next;
} StackNode;
// 指向堆栈的第一个节点
static StackNode *stack;
2. push元素进入堆栈,每push一个值,就创建一个对应的StackNode节点来标识。最后一句stack = new_node, 就是让这个指针一直指向新push进来的StackNode。
void push(STACK_TYPE value) {
StackNode *new_node;
new_node = malloc(sizeof(StackNode));
assert(new_node == NULL) ;
new_node->value = value;
new_node->next = stack;
stack = new_node;
}
3. pop顶部的元素,普通的堆栈是删除掉顶部的元素,而链式堆栈是释放掉stack这个指针变量所指向的节点。
void pop(void) {
assert(stack == NULL);
StackNode *first_node;
first_node = stack;
stack = first_node->next;
free(first_node);
}
4. top:获取堆栈顶部的值
STACK_TYPE top(void) {
assert(!is_empty());
return stack->value;
}
5. is_empty: 判断堆栈是否为空
int is_empty(void) {
return stack == NULL;
}
6. is_full: 判断堆栈是否已满,链式堆栈永远不会满,因为它可以一直动态分配下去。
int is_full(void) {
return 0;
}
7. 释放整个堆栈
void destroy_stack(void) {
if (!is_empty()) {
pop();
}
}
五、大致实现流程图