c语言实现的多态栈——短小精悍

1、数据结构——栈

栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。

栈是允许在同一端进行插入和删除操作的特殊线性表。允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(PUSH),删除则称为退栈(POP)。栈也称为后进先出表。

栈可以用来在函数调用的时候存储断点,做递归时要用到栈!

2、栈的多态性

栈的多态性即指栈可以存储任意类型的数据,并且不会在使用过程中丢失该数据结构。这个时候很多人应该想到下面这种栈的基本格式。

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内核组织链表的思想的一种简单而又实用的栈。

3、简单而又实用的栈

栈的基本结构

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))

这个宏用的很巧妙,我就不深入讲解了,读者可以仔细阅读一下这个宏。利用这个宏,我们就可以通过member来获取其所在的结构变量的地址。

4、测试用例

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;
}
结果就不给大家贴出来了。




你可能感兴趣的:(linuxC语言编程基础,栈,指针,数据结构,c语言)