线性表(二)

       因为一篇文章着实塞不下,线性表的内容是如此的多,更进一步说明了线性表在数据结构这门学科中的地位。在此主要是对线性表的链式存储这个知识点作进一步的探究。微笑

      结点是线性表的组成单位,当结点中只有数据域的时候,多个结点构成的是顺序表,而当结点中还有指针域的时候,多个结点构成的是线性链表。在实际中,数据往往比我们想象的要更加复杂,前文讨论的指针域只有一个的情况,当指针域有多个的时候会发生什么样的化学反应呢?

      一、一个指针域

           结构特点:

       

           

          多个结点构成的结果:

           1、顺序链表


                  2、循环链表         

          当链表的最后一个指针域不为NULL,而是指向标头结点时,可构成循环链表

          

       

          注: 循环链表的运算与线性链表基本一致。但两者循环条件(判断是否到表尾的条件)不同:
             线性表:判断某结点的指针域是否为空。
             循环链表:判断某结点的指针域值是否等于头指针。
       
     关于算法:
         上文已有一定的介绍,在此不再赘述。

     二、两个指针域:
        结构特点:
                  
             
           多个结点构成的结果:
                  特点:1、 对双向循环链表中任一结点的指针有: p == p→prior→next == p→next→prior
             2、置空双向循环链表:p->prior=p;p->next=p;
   

           关于算法:

            1、双向链表的存储结构:

typedef   struct  DuLNode{
    ElemType                    data;
    struct   DuLNode         *prior;
    struct   DuLnode         *next;
 }DuLNode, * DuLinkList;


                   2、双向循环链表中得到元素:

DuLinkList GetElemP_DuL(DuLinkList va, int i) {
  // L为带头结点的单链表的头指针。
  // 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
  DuLinkList p;
  p = va->next;   
  int j = 1;  // 初始化,p指向第一个结点,j为计数器
  while (p!=va && j<i) {  //顺指针向后查找,直到p指向第i个元素或p为空
    p = p->next;
    ++j;
  }
  if (p==va || j<i) return NULL;  // 第i个元素不存在
  else return p;
} // GetElem_L

                   3、双向循环链表中插入元素:

Status ListInsert_DuL(DuLinkList &L, int i, ElemType e) { 
  // 在带头结点的双链循环线性表L的第i个元素之前插入元素e,
  // i的合法值为1≤i≤表长+1。
  DuLinkList p,s;
  if (!(p = GetElemP_DuL(L, i)))  // 在L中确定第i个元素的位置指针p
    return ERROR;                 // p=NULL, 即第i个元素不存在
  if (!(s = (DuLinkList)malloc(sizeof(DuLNode))))
    return ERROR;
  s->data = e;
  s->prior = p->prior;
  p->prior->next = s;
  s->next = p;
  p->prior = s;
  return OK;
} // ListInsert_DuL

          4、双向循环链表中删除元素:

Status ListDelete_DuL(DuLinkList &L, int i, ElemType &e) {//算法2.19
  // 删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i≤表长
  DuLinkList p;
  if (!(p = GetElemP_DuL(L, i)))  // 在L中确定第i个元素的位置指针p
    return ERROR;                 // p=NULL, 即第i个元素不存在
  e = p->data;
  p->prior->next = p->next;
  p->next->prior = p->prior;
  free(p);    
  return OK;
} // ListDelete_DuL
 

    具体代码实现(C)

 #include<string.h>
 #include<ctype.h>
 #include<malloc.h> /* malloc()等 */
 #include<limits.h> /* INT_MAX等 */
 #include<stdio.h> /* EOF(=^Z或F6),NULL */
 #include<process.h> /* exit() */
 typedef struct DuLNode
 {
   int data;
   struct DuLNode *prior,*next;
 }DuLNode,*DuLinkList;
 int InitList(DuLinkList *L)
 { /* 产生空的双向循环链表L */
   *L=(DuLinkList)malloc(sizeof(DuLNode));
   if(*L)
   {
     (*L)->next=(*L)->prior=*L;
     return 1;
   }
   else
     return -2;
 }
 int ListLength(DuLinkList L)
 { /* 初始条件:L已存在。操作结果:返回L中数据元素个数 */
   int i=0;
   DuLinkList p=L->next; /* p指向第一个结点 */
   while(p!=L) /* p没到表头 */
   {
     i++;
     p=p->next;
   }
   return i;
 }

 int GetElem(DuLinkList L,int i,int *e)
 { /* 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */
   int j=1; /* j为计数器 */
   DuLinkList p=L->next; /* p指向第一个结点 */
   while(p!=L&&j<i) /* 顺指针向后查找,直到p指向第i个元素或p指向头结点 */
   {
     p=p->next;
     j++;
   }
   if(p==L||j>i) /* 第i个元素不存在 */
     return 0;
   *e=p->data; /* 取第i个元素 */
   return 1;
 }

 int ListInsert(DuLinkList L,int i,int e) /* 改进算法2.18 */
 { /* 在带头结点的双链循环线性表L中第i个位置之前插入元素e,i的合法值为1≤i≤表长+1 */
   DuLinkList p,s;
   if(i<1||i>ListLength(L)+1) /* i值不合法 */
     return 0;
   s=(DuLinkList)malloc(sizeof(DuLNode));
   if(!s)
     return -2;
   s->data=e; /* 在第i-1个元素之后插入 */
   s->prior=p;
   s->next=p->next;
   p->next->prior=s;
   p->next=s;
   return 1;
 }

 int ListDelete(DuLinkList L,int i,int *e) /* 算法2.19 */
 { /* 删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i≤表长+1 */
   DuLinkList p;
   if(i<1||i>ListLength(L)) /* i值不合法 */
     return 0;
   p=GetElem(L,i);  /* 在L中确定第i个元素的位置指针p */
   if(!p) /* p=NULL,即第i个元素不存在 */
     return 0;
   *e=p->data;
   p->prior->next=p->next;
   p->next->prior=p->prior;
   free(p);
   return 1;
 }

 void ListTraverse(DuLinkList L,void(*visit)(int))
 { /* 由双链循环线性表L的头结点出发,正序对每个数据元素调用函数visit() */
   DuLinkList p=L->next; /* p指向头结点 */
   while(p!=L)
   {
     visit(p->data);
     p=p->next;
   }
   printf("\n");
 }

 void visit(int c)
 {
   printf("%d ",c);
 }

 void main()
 {
   LinkList L;
   int e;
   int j;
   int i;
   i=InitList(&L); /* 初始化单循环链表L */
   printf("初始化单循环链表L i=%d (1:初始化成功)\n",i);
   ListInsert(&L,1,3); /* 在L中依次插入3,5 */
   ListInsert(&L,2,5);
   i=GetElem(L,1,&e);
   j=ListLength(L);
   printf("L中数据元素个数=%d,第1个元素的值为%d。\n",j,e);
   printf("L中的数据元素依次为:");
   ListTraverse(L,visit);
   i=ListDelete(&L,2,&e);
   printf("删除L的第2个元素:\n");
   if(i)
   {
     printf("删除的元素值为%d,现在L中的数据元素依次为:",e);
     ListTraverse(L,visit);
   }
   else
     printf("删除不成功!\n");
 }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值