【五】双向链表

来源:互联网 发布:芗里芗亲app软件下载 编辑:程序博客网 时间:2024/05/22 14:58

1、双向链表的定义
在单链表的结点中增加一个指向其前驱的p r e指针!

这里写图片描述

2、数据结构的定义

//dlinklist.h/*  对外做数据封装,屏蔽线性表的实现*/typedef void DLinklist;typedef struct _struct_linklistNode DLinklistNode;struct _struct_linklistNode{  DLinklistNode *pre;  DLinklistNode *next;};
//dlinklist.c//内部头结点的真实定义typedef struct _struct_dlinklist{  DLinklistNode header;  //游标成员  DLinklistNode *silder;  int length;}TDLinklist;
//main.c//被插入元素的定义typedef struct _struct_value{  DLinklistNode node;  int v;}Value;

3、创建操作

/*该方法用于创建并且返回一个空的线性表*/DLinklist* List_Create(){  TDLinklist *tlist = NULL;  tlist = (TDLinklist*)malloc(sizeof(TDLinklist));  if(tlist != NULL)  {    tlist->header.pre = NULL;    tlist->header.next = NULL;    tlist->silder = NULL;    tlist->length = 0;  }  return tlist;}

4、插入操作

示意图:
这里写图片描述

/*该方法用于向一个线性表list的pos位置处插入新元素node返回值为1表示插入成功,0表示插入失败*/int List_Insert(DLinklist* list, DLinklistNode* node, int pos){  int iret = 1;  TDLinklist *tlist = (TDLinklist*)list;  iret = iret && (tlist != NULL) && (node != NULL) && (pos >= 0);  if(iret)  {    DLinklistNode *current = (DLinklistNode*)tlist;    DLinklistNode *next = NULL;    for(int i = 0; (i<pos) && (current->next != NULL); i++)    {      current = current->next;    }    next = current->next;    current->next = node;    node->next = next;    if(next != NULL)    {      next->pre = node;    }    node->pre = current;    if(tlist->length == 0)    {      //如果插入的是第一个元素,则默认让游标指向它      //游标默认指向第一个插入的元素      tlist->silder = tlist->header.next;    }    //如果插入的位置是第一个元素,则修正新的第一个元素的pre指针    if(current == (DLinklistNode*)tlist)    {      //让第一个元素的pre指向NULL      node->pre = NULL;      //添加如下的代码,可让游标始终指向链表的第一个元素      //tlist->silder = tlist->header.next;    }    tlist->length++;  }  return iret;}

5、删除操作

示意图:
这里写图片描述

/*该方法用于删除一个线性表list的pos位置处的元素返回值为被删除的元素,NULL表示删除失败*/DLinklistNode* List_Delete(DLinklist* list, int pos){  DLinklistNode *ret = NULL;  TDLinklist *tlist = (TDLinklist*)list;  if(tlist != NULL)  {    //要保证被删除的元素存在, && (tlist->length > 0)    if((pos >= 0)&&(pos < tlist->length))    {      DLinklistNode *current = (DLinklistNode*)tlist;      DLinklistNode *next = NULL;      for(int i = 0;i<pos;i++)      {        current = current->next;      }      ret = current->next;      next = ret->next;      current->next = ret->next;      if(next != NULL)      {        next->pre = current;        //以下条件等价于:current == (DLinklistNode*)tlist        if(pos == 0)        {          next->pre = NULL;        }      }      //如果游标当前指向了要删除的元素,则让游标指向它的下一个元素      if(ret == tlist->silder)      {        tlist->silder = ret->next;      }      ret->pre = NULL;      ret->next = NULL;      tlist->length--;    }  }  return ret;}

6、增加游标后的新操作

  • 获取当前游标指向的数据元素
  • 将游标重置指向链表中的第一个数据元素
  • 将游标移动指向到链表中的下一个数据元素
  • 将游标移动指向到链表中的上一个数据元素
  • 直接指定删除链表中的某个数据元素

相关定义:

/*  删除指定结点  如果成功,返回被删除的结点,否则返回NULL*/DLinklistNode* List_DeleteNode(DLinklist *list,DLinklistNode *node);/*  重置游标  如果成功,返回重置后的元素,否则返回NULL*/DLinklistNode* List_Reset(DLinklist *list);/*  获取当前游标指向的元素  如果成功,返回当前游标指向的元素,否则返回NULL*/DLinklistNode* List_Current(DLinklist *list);/*  让游标指向下一个元素  如果成功,返回下一个元素,否则返回NULL  特殊情况:链表最后一个元素的下一个元素也为NULL*/DLinklistNode* List_Next(DLinklist *list);/*  让游标指向前一个元素  如果成功,返回前一个元素,否则返回NULL  特殊情况:链表的第一个元素的前一个元素也为NULL*/DLinklistNode* List_Pre(DLinklist *list);

相关实现:

/*  删除指定结点  如果成功,返回被删除的结点,否则返回NULL*/DLinklistNode* List_DeleteNode(DLinklist *list,DLinklistNode *node){  DLinklistNode *ret = NULL;  TDLinklist *tlist = (TDLinklist*)list;  if((tlist != NULL) && (node != NULL))  {    int i = 0;    DLinklistNode *current = (DLinklistNode*)tlist;    for(i = 0;i < tlist->length;i++)    {      current = current->next;      if(current == node)      {        ret = current;        break;      }    }    //判断是否找到要删除的元素    if(ret != NULL)    {        List_Delete(list,i);    }  }  return ret;}/*  重置游标  如果成功,返回重置后的元素,否则返回NULL*/DLinklistNode* List_Reset(DLinklist *list){  DLinklistNode *ret = NULL;  TDLinklist *tlist = (TDLinklist*)list;  if(tlist != NULL)  {    tlist->silder = tlist->header.next;    ret = tlist->silder;  }  return ret;}/*  获取当前游标指向的元素  如果成功,返回当前游标指向的元素,否则返回NULL*/DLinklistNode* List_Current(DLinklist *list){  DLinklistNode *ret = NULL;  TDLinklist *tlist = (TDLinklist*)list;  if(tlist != NULL)  {    ret = tlist->silder;  }  return ret;}/*  让游标指向下一个元素  如果成功,返回下一个元素,否则返回NULL  特殊情况:链表最后一个元素的下一个元素也为NULL*/DLinklistNode* List_Next(DLinklist *list){  DLinklistNode *ret = NULL;  TDLinklist *tlist = (TDLinklist*)list;  if(tlist != NULL)  {    tlist->silder =  tlist->silder->next;    ret = tlist->silder;  }  return ret;}/*  让游标指向前一个元素  如果成功,返回前一个元素,否则返回NULL  特殊情况:链表的第一个元素的前一个元素也为NULL*/DLinklistNode* List_Pre(DLinklist *list){  DLinklistNode *ret = NULL;  TDLinklist *tlist = (TDLinklist*)list;  if(tlist != NULL)  {    tlist->silder = tlist->silder->pre;    ret = tlist->silder;  }  return ret;}

7、小结

  • 双向链表在单链表的基础上增加了指向前驱的指针
  • 功能上双向链表可以完全取代单链表的使用
  • 循环链表的N e xt,Pre和C u rre nt操作可以高效遍历链表中的所有元素

8、完整源码下载

文件名称:dlinklist-1.0.tar.gz
链接: http://pan.baidu.com/s/1c0bFUda 密码: 2asr

编译步骤:
0.1 解压缩:tar -zxvf dlinklist-1.0.tar.gz
0.2 进入目录:./configure
0.3 生成Seqlist:make
0.4 运行程序:./Dlinklist

0 0