栈 stack
栈的特点是先入后出 和链表的共同点是插入/删除节点容易
相较之下栈还更简洁一些 因为栈不需要遍历 插入和删除节点都以栈顶节点为基准
不需要像链表那样实现随机访问.
侵入式结构
前面讨论过链表的侵入式实现,实现通用的数据结构
http:
栈也同样可以用侵入式的结构实现:
struct stack {
struct statck *next;
};
首先栈需要一个栈顶节点
struct stack top;
初始化栈 #define INIT_STACK(top) {top->next = NULL;}
从栈顶插入节点
static inline void stack_push(struct stack *top, struct stack *new_node) {
assert(top != NULL);
assert(new_node != NULL);
new_node->next = top->next;
top->next = new_node;
}
从栈顶获取节点并删除
static inline struct statck * _stack_pop(struct stack *top) {
assert(top != NULL);
struct stack *tmp = top->next;
if (top->next != NULL) {
top->next = tmp->next;
} else {
return NULL;
}
return tmp;
}
有一个问题在于返回的是struct stack节点的地址
但侵入式的数据结构 需要包在stack外的数据的地址
所以还需要一个宏来返回真正的包装结构的节点
#define list_entry(ptr,type,member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define stack_pop(top,type,member) list_entry(_stack_pop(top),type,member)
list_entry在链表中已经分析过了 根据偏移量获取包装结构的地址
stack_pop则根据此返回包装结构
判断栈是否为空 = 判断栈顶的next节点是否存在
static inline int stack_empty(struct stack *top) {
return top->next == NULL;
}
示例代码
#ifndef CODINGUTILS_STACK_H
#define CODINGUTILS_STACK_H
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct stack {
struct stack *next;
};
#define INIT_STACK(top) {(top)->next = NULL;}
#define list_entry(ptr,type,member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
static inline void stack_push(struct stack *top, struct stack *new_node) {
assert(top != NULL);
assert(new_node != NULL);
new_node->next = top->next;
top->next = new_node;
}
static inline struct statck * _stack_pop(struct stack *top) {
assert(top != NULL);
struct stack *tmp = top->next;
if (top->next != NULL) {
top->next = tmp->next;
} else {
return NULL;
}
return tmp;
}
static inline int stack_empty(struct stack *top) {
return top->next == NULL;
}
#define stack_pop(top,type,member) list_entry(_stack_pop(top),type,member)
#endif
#include "stack.h"
#define log(fmt,...)\
do {\
printf(fmt,##__VA_ARGS__);\
printf("\n");\
} while (0)
struct stack_node {
struct stack node;
int val;
};
int main() {
log("stack test");
struct stack top;
INIT_STACK(&top);
int i = 0;
for (i = 0; i < 5; i++) {
struct stack_node *tmp = NULL;
tmp = malloc(sizeof(struct stack_node));
if (!tmp) {
log("failed to malloc stack node");
return -1;
}
tmp->val = i;
stack_push(&top, &tmp->node);
log("push node to stack val:%d", tmp->val);
}
while (!stack_empty(&top)) {
struct stack_node *val = NULL;
val = stack_pop(&top, struct stack_node, node);
log("val:%d", val->val);
free(val);
}
return 0;
}
github repo路径
https: