线性表的链式存储结构--双链表

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pfl_327/article/details/81540382
                            双链表

对于双链表,采用类似于单链表的类型定义,其DLinkList类型的定义如下:

   typedef struct DNode       //声明双链表节点类型
   {    ElemType data;
      struct DNode *prior;    //指向前驱节点
    struct DNode *next;     //指向后继节点
   } DLinkList;


1. 建立双链表
  建立双链表也有两种方法。和头插法建立单链表的过程相似,采用头插法建立双链表的算法。

void CreateListF(DLinkList *&L,ElemType a[],int n)
//头插法建立双链表:由含有n个元素的数组a创建带头节点的双链表L
{ DLinkList *s; int i;
   L=(DLinkList *)malloc(sizeof(DLinkList));//创建头节点
   L->prior=L->next=NULL;   //前后指针域置为NULL
   for (i=0;i<n;i++)        //循环建立数据节点
   {    s=(DLinkList *)malloc(sizeof(DLinkList));
    s->data=a[i];       //创建数据节点*s
    s->next=L->next;        //将*s插入到头节点之后
    if (L->next!=NULL)      //若L存在数据节点,修改前驱指针
       L->next->prior=s;
    L->next=s;
    s->prior=L;
   }
} 
void CreateListR(DLinkList *&L,ElemType a[],int n)
//尾插法建立双链表:由含有n个元素的数组a创建带头节点的双链表L
{  DLinkList *s,*r;
   int i;
   L=(DLinkList *)malloc(sizeof(DLinkList));//创建头节点
   r=L;         //r始终指向尾节点,开始时指向头节点
   for (i=0;i<n;i++)        //循环建立数据节点
   {  s=(DLinkList *)malloc(sizeof(DLinkList));
    s->data=a[i];       //创建数据节点*s
    r->next=s;s->prior=r;   //将*s插入*r之后
    r=s;                //r指向尾节点
   }
   r->next=NULL;            //尾节点next域置为NULL
}
  1. 线性表基本运算在双链表中的实现
    和单链表相比,主要是插入和删除运算不同。
bool ListInsert(DLinkList *&L,int i,ElemType e)
{ int j=0;
  DLinkList *p=L,*s;          //p指向头节点,j设置为0
   while (j<i-1 && p!=NULL) //查找第i-1个节点
   {    j++;
    p=p->next;
   }
   if (p==NULL) //未找到第i-1个节点,返回false
    return false;
   else     //找到第i-1个节点*p,在其后插入新节点*s
   {    s=(DLinkList *)malloc(sizeof(DLinkList));
    s->data=e;          //创建新节点*s
    s->next=p->next;        //在*p之后插入*s节点
    if (p->next!=NULL)//若存在后继节点,修改其前驱指针
       p->next->prior=s;
    s->prior=p;
    p->next=s;
    return true;
   }
}

(2)删除*p节点之后的一个节点

bool ListDelete(DLinkList *&L,int i,ElemType &e)
{  int j=0; DLinkList *p=L,*q;  //p指向头节点,j设置为0
   while (j<i-1 && p!=NULL)   //查找第i-1个节点
   {    j++;
    p=p->next;
   }
   if (p==NULL)        //未找到第i-1个节点
    return false;
   else            //找到第i-1个节点*p
   {    q=p->next;         //q指向第i个节点
    if (q==NULL)       //当不存在第i个节点时返回false
       return false;
    e=q->data;
    p->next=q->next;        //从单链表中删除*q节点
    if (p->next!=NULL)    //修改其前驱指针
         p->next->prior=p;
    free(q);            //释放*q节点
    return true;
   }
}

3.循环链表
循环链表是另一种形式的链式存储结构。它的特点是表中最后一个节点的指针域不再是空,而是指向表头节点,整个链表形成一个环。由此从表中任一节点出发均可找到链表中其他节点。

例:编写出判断带头节点的双向循环链表L是否对称相等的算法。
解:p从左向右扫描L,q从右向左扫描L,若对应数据节点的data域不相等,则退出循环,否则继续比较,直到p与q相等或p的下一个节点为*q为止。

int Equeal(DLinkList *L)              双向循环链表
{  int same=1;
   DLinkList *p=L->next;    //p指向第一个数据节点
   DLinkList *q=L->prior;     //q指向最后数据节点
   while (same==1)
      if (p->data!=q->data)
         same=0;
     else  
       {        
        if (p==q) break;    //数据节点为奇数的情况
        q= q->prior;
        if (p==q) break;    //数据节点为偶数的情况
          p=p->next;
     }
   return same;
}

4.静态链表
静态链表借用一维数组来描述线性链表。数组中的一个分量表示一个节点,同时使用游标(指示器cur即为伪指针)代替指针以指示节点在数组中的相对位置。数组中的第0个分量可以看成头节点,其指针域指示静态链表的第一个节点。
这种存储结构仍然需要预先分配一个较大空间,但是在进行线性表的插入和删除操作时不需要移动元素,仅需要修改“指针”,因此仍然具有链式存储结构的主要优点。
下图给出了一个静态链表的示例。图(a)是一个修改之前的静态链表,图(b)是删除数据元素“陈华”之后的静态链表,图(c)插入数据元素“王华”之后的静态链表,图中用阴影表示修改的游标。

猜你喜欢

转载自blog.csdn.net/pfl_327/article/details/81540382
今日推荐