回 帖 发 新 帖 刷新版面

主题:线性表(链表)、栈与队列

线性表、栈与队列

一、结构定义
  线性表有两种方式表示,这里说的是存储方式,包括连续的数组表示和链表表示两种。仅以链表表示为例。

  首先要定义结点类型,总的来说一个结点应该包括两个部分,指针域和数据域。

  struct _DNode
  {
    LPVOID data;/*数据域*/
    LPVOID link;/*指针域*/
  };

  指针域很简单无非是前趋指针和后继指针,但数据域却是不定的,我们对这个链表的要求是要有高适应性,所以应该做一个开放的数据域,就用一个空指针表示吧。于是修改成:

  struct _DNode
  {
    LPVOID data;/*数据域*/
    LPVOID pre;
    LPVOID next;
  };

  这里我提倡一种习惯,就是善于使用宏。在C语言里宏是个非常好的工具,它帮助我们更好的书写代码。常用的方法就是用#define和typedef。

  严格来说只有#define是宏定义,但typedef我们可以看成是宏(别名),它可以更灵活的使用。

  在上面代码之前,添加

  typedef void far *LPVOID;
  typedef struct _DNode DNode;
  typedef DNode *LPDNode;

  于是结构体也可以再修改为

  struct _DNode
  {
    LPVOID data;/*数据域*/
    LPDNode pre;
    LPDNode next;
  };

  有了结点类型,就可以定义链表类型了。

  struct _DList
  {
    LPDNode head,tail;/*指向链表的头和尾,头表示第一个元素*/
    DWORD length;/*结点的个数*/
  };

  其中DWORD是双字,即32位长的数据类型,可以宏定义为typedef unsigned long DWORD;

  同样的在前面再加上它的宏名

  typedef struct _DList DList;
  typedef DList *LPDList;

  今后我们定义数据的时候都将直接使用这些宏名。用它的好处会在以后体会到的。

  OK,到这里顶点集定义完毕,我们要定义它们的边集,也就是常用操作。

二、常用操作
  线性表的操作想一想需要哪此,查找、插入、删除,另外还包括整个线性表的初始化和最后的销毁。全部操作列在下面

  BOOL InitList(LPDList *pl);/*初始化*/
  BOOL DestroyList(LPDList pl);/*销毁*/
  LPVOID GetElem(LPDList pl,int index,BOOL fromtail);/*查找*/
  BOOL ListInsert(LPVOID data,LPDList pl,int index,BOOL fromtail);/*插入*/
  BOOL ListDelete(LPDList pl,int index,BOOL fromtail);/*删除*/

  除了这些基本操作之外,还有一些很常用的

  BOOL ClearList(LPDList pl);/*清空链表*/
  DWORD ListLength(LPDList pl);/*返回链表长*/
  BOOL ListEmpty(LPDList pl);/*判断是否为空*/

  当然前面有宏名定义
  typedef int BOOL;
  #define TRUE 1
  #define FALSE 0

  以上这些定义和申明全部放在一个MyList.h文件中,然后在对应的MyList.c中写这些操作的实现代码。

  #include "MyList.h"
  #include "malloc.h"
  #include "assert.h"
  BOOL InitList(LPDList *pl)
  {
    (*pl)=(LPDList)malloc(sizeof(DList));
    if((*pl)==NULL)return FALSE;
    (*pl)->head=(*pl)->tail=NULL;
    (*pl)->length=0;
    return TRUE;
  }
  BOOL DestroyList(LPDList pl)
  {
    LPDNode p=pl->head,q;
    while(p!=NULL)
    {
       q=p;
       p=p->next;
       free(q);
    }
    free(pl);
  }
  LPVOID GetElem(LPDList pl,int index,BOOL fromtail)/*fromtail表示是否从尾部开始*/
  {
    LPDNode p;
    if(index<0||index>=pl->length)return NULL;
    if(fromtail)
    {
      p=pl->tail;
      while(index--)p=p->pre;
    }
    else
    {
      p=pl->head;
      while(index--)p=p->next;
    }
    return p->data;
  }
  BOOL ListInsert(LPVOID data,LPDList pl,DWORD index,BOOL fromtail)
  {
    LPDNode p,q;
    if(pl->length==0)
    {
      q=pl->head=pl->tail=(LPDNode)malloc(sizeof(DNode));
      q->next=q->pre=NULL;
      q->data=data;
      pl->length++;
      return TRUE;
    }
    if(index>=pl->length)return FALSE;
    q=(LPDNode)malloc(sizeof(DNode));
    q->data=data;
    if(fromtail)
    {
      p=pl->tail;
      while(index--)p=p->pre;
      q->pre=p;
      q->next=p->next;
      if(p->next)
        p->next->pre=q;
      else
        pl->tail=q;
      p->next=q;
    }
    else
    {
      p=pl->head;
      while(index--)p=p->next;
      q->next=p;
      q->pre=p->pre;
      if(p->pre!=NULL)
        p->pre->next=q;
      else
        pl->head=q;
      p->pre=q;
    }
    pl->length++;
    return TRUE;
  }
  BOOL ListDelete(LPDList pl,DWORD index,BOOL fromtail)
  {
    LPDNode p;
    if(index>=pl->length)return FALSE;
    if(fromtail)
    {
      p=pl->tail;
      while(index--)p=p->pre;
    }
    else
    {
      p=pl->head;
      while(index--)p=p->next;
    }
    if(p->pre)
      p->pre->next=p->next;
    else
      pl->head=p->next;
    if(p->next)
      p->next->pre=p->pre;
    else
      pl->tail=p->pre;
    free(p);
    pl->length--;
    return TRUE;
  }

  有了这些定义,就可以方便的操作链表了。

  其它操作
  BOOL ClearList(LPDList pl)
  {
    while(ListDelete(pl,0,FALSE));
    return pl->length==0;
  }
  最后两个完全用宏定义了:
  #define ListLength(pl) (pl->length)
  #define ListEmpty(pl) (pl->length==0)

  到这里就全部完成了。

三、栈与队列
  从本质上看,栈与队列都是线性表,所以没有必要再定义栈和队列,老规矩用宏。

  typedef DList DStack;
  typedef DList *LPDStack;
  typedef DList DQueue;
  typedef DList *LPDQueue;

  所谓栈,就是LIFO,后进先出,它的操作类似的有:
  #define InitStack(ps) InitList(ps)
  #define DestroyStack(ps) DestroyList(ps)
  #define GetTop(ps) GetItem(ps,0,FALSE)
  #define Push(ps) ListInsert(ps,0,FALSE)
  #define Pop(ps,e) ((e=GetItem(ps,0,FALSE)),ListDelete(ps,0,FALSE))

  此外还有
  #define StackLength(ps) ListLength(ps)
  #define StackEmpty(ps) ListEmpty(ps)
  #define ClearStack(ps) ClearList(ps)

  其中用得多的是Push(ps),压栈,和Pop(ps,e)弹栈。

  所谓队列,就是FIFO,先进先出,它的操作类似的有:
  #define InitQueue(pq) InitList(pq)
  #define DestroyQueue(pq) DestroyList(pq)
  #define GetHead(pq) GetItem(pq,0,FALSE)
  #define EnQueue(pq,e) ListInsert(e,pq,0,TRUE)
  #define DeQueue(pq,e) ((e=GetItem(pq,0,FALSE)),ListDelete(pq,0,FALSE))

  类似的还有
  #define QueueLength(pq) ListLength(pq)
  #define QueueEmpty(pq) ListEmpty(pq)
  #define ClearQueue(pq) ClearList(pq)

  其中用得多的是EnQueue(pq,e),入队,和DeQueue(pq,e)出队。

回复列表 (共49个回复)

11 楼

收藏了,谢谢楼主!

12 楼

也不是啊!
有人会看的!
版主辛苦了!

13 楼

要想技术掌握在自己手中,就要动自己的双手,走马观花是没有任何收获的!!!!

14 楼

支持,不过我想自己写.

15 楼

这些代码我已经试过了
但是好象都有些问题

16 楼

1楼的代码调试过,不过没有完全测试,可能会有问题,只当是示例,你要应用的话不如用系统提供的类库。

17 楼

需要基本算法的代码,到我的BLOG上去看啊,我原来也总结了很多的.
http://blog.programfan.com/blog.asp?blogid=96&columnid=2071

18 楼

辛苦了,顶一下.收藏了.

19 楼

有没有整个的程序啊
急需!!!!!!!!!!!!!!!!!
谢谢

20 楼


楼主强  以后生子当如楼主(没一点骂人的味道——真的很佩服) 
[img][/img]

我来回复

您尚未登录,请登录后再回复。点此登录或注册