栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。
栈是允许在同一端进行插入和删除操作的特殊线性表。允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(PUSH),删除则称为退栈(POP)。栈也称为后进先出表。
栈可以用来在函数调用的时候存储断点,做递归时要用到栈!
栈的多态性即指栈可以存储任意类型的数据,并且不会在使用过程中丢失该数据结构。这个时候很多人应该想到下面这种栈的基本格式。
typedef struct list
{
struct list *next;
void *data;
}List_head;
typedef struct
{
List_head *top;
};
在存储数据的时候将data指针指向所要存储的数据结构的地址,这样可以通过data来找到具体的数据,从而实现了用一个栈可以存储不同类型的数据的作用,我们成这种特性为多态。
但是我总是觉得这个基本结构很拖拉,因为这个栈里面有一个*data指针,每次push之前都要把具体的数据地址赋值给data从而来构造一个List_head,如果这个栈很长的话,维护这个栈本身就要有很多的开销。
我们学习linux内核可以发现,linux内核代码就像是一根根的链表和一坨坨的数据结构组成的(这句话出自我的老师,我这里暂时想不出其他形容词)。这个优秀的内核对链表的处理可谓是出神入化,那么下面我就介绍一中采用了linux内核组织链表的思想的一种简单而又实用的栈。
栈的基本结构
typedef struct list
{
struct list *next;
}List_head;
typedef struct
{
List_head *top;
}Stack;
和上面的比较少了一个data指针,这样的栈非常的精简。维护起来也很容易。
下面看它的相关操作的实现。
// 初始化栈
void initStack(Stack * s)
{
s->top=NULL;
}
// 入栈
void push(Stack *s, List_head *p)
{
p->next=s->top;
s->top=p;
}
// 出栈
List_head *pop(Stack *s)
{
List_head *p=s->top;
s->top=p->next;
return p;
}
// 判断栈是否为空
int isEmpty(Stack *s)
{
return s->top==NULL;
}
可以想见,这样的栈里只存了List_head这样的一个结构,而List_head里面仅仅存放了比它先push进栈的List_head结构体。这样的栈好像没什么用。
这种栈的特点是占用空间特别的小,仅仅由List_head这样的结构形成一根链表,维护这个栈的开销也特别小,但是它却可以存储并管理各种各样的数据结构。
在linux内核中,需要加入链表的数据结构中都有一个“没用的”成员类型List_head,就是这个看似没用的成员,实现了链表的管理。
所以,我们只需要在我们需要进行入栈等操作的数据结构中加入一个List_head类型的成员就能实现了。下面是两个自定义数据结构。
// here, you can define any struct that include the type List_head
typedef struct
{
List_head member;
int data;
}MY;
typedef struct
{
List_head member;
double data;
}You;
我们只需要对这两个数据的member成员进行入栈和出栈,此时这个栈就好比一个晾衣绳,上面晾着各种各样的衣服,但是到这里还缺了一个最重要的一步,那就是通过member成员来获取其所在的结构,在linux内核中这个实现是通过一个名为CONTAINER_OF的宏来实现的。这里我们要自己实现,用一个名为list_entry的宏。
#define list_entry(type,pos,member) \
(type*)((char*)pos-(int)(&((type*)0)->member))
int main()
{
Stack s;
MY p1,p2,p3,*h;
You q1,q2,q3,*w;
List_head *p;
initStack(&s);
p1.data = 1;
p2.data = 2;
p3.data = 3;
push(&s,&p1.member);
push(&s,&p2.member);
push(&s,&p3.member);
while(!isEmpty(&s))
{
p=pop(&s);
// 这里实现了多态
h=list_entry(MY,p,member);
printf("%d\n",h->data);
}
return 0;
}
结果就不给大家贴出来了。