双链表相关资料

转载自http://blog.sina.com.cn/s/blog_65380c300100ij1s.html

双链表

(2010-04-25 21:42:44)
标签:

杂谈

分类:C/C++
双向链表

双向链表中,每个结点都有两个指针域,一个指向其后继结点,另一个指针指向其前驱结点,如图1.1(a)所示,因此,可以从某个结点开始朝两个方向遍历整个链表。

如果循环链表中每个结点都采用双向指针就构成了双向循环链表。图1.1(c)所示就是一个带头结点的双向循环链表,其尾结点的后继指针指向表的头结点,而表头结点的前驱指针指向表的尾结点。空的双向循环链表的结构如图1.1(b)所示。




双向链表中结点的类型定义如下:

typedef int datatype;

typedef struct node *ptNode;

struct note{  
                           
      datatypedata;                                       
      ptNodeproir,next;                         
};

双链表是一种对称的结构,既有向前链又有向后链,这就使得双链表的前插和后插及自身删除操作都很方便,只需要修改几个结点的指针域,而不必进行大量的数据交换或遍历操作。下面给出双向链表的插入和删除运算的算法。

1 双向链表的前插运算

在双链表中某个给定的结点P之前插入一个新结点S,其操作步骤如下:

1)。将结点S的后继指向P本身;
2)。将结点S的前驱指向结点P的前驱所指向的结点;
3)。将结点P的前驱结点的后继修改为指向新结点S;
4)。将结点P的前驱修改为指向结点S本身;

插入新结点的过程如图1.2 (a)图所示。

双链表中在结点P之前插入一个新结点S的算法如下:

ptNode Insert_before(ptNode head,ptNode  p, intx)
{
              ptNode s;
              s=(ptNode)malloc(sizeof(node));//建立新结点
              s->data=x;                                                                        //将x的值赋给s->data
            s->next=p;                                                                        //1)将新结点S的后继指向结点P
              s->prior=p->prior;                                              //2)将新结点S的前驱指向原结点P的前驱
              p->prior->next=s;                                                //3)原结点P前驱结点的后继指向新结点S
              p->prior=s;                                                                      //4)原结点P的前驱指向新结点S
              return(head);                                                                //返回带头结点双链表的头指针
}

2 双向链表的后插运算

假设双链表中结点P的后继结点为Q,在结点P之后插入一个新结点S,其操作步骤如下:

1)。将结点S的前驱指向P本身;
2)。将结点S的后继指向结点P所指向的后继结点;
3)。将结点P的后继结点Q的前驱结点修改为新结点S本身;
4)。将结点P的后继结点修改为结点S本身;

插入新结点的过程如图1.2 (b)图所示。
双链表中在结点P之后插入一个新结点S的算法如下:

ptNode Insert_after(ptNode head,ptNode  p, intx)
{
              ptNode s;
              s=(ptNode)malloc(sizeof(node));//建立新结点
              s->data=x;                                                                        //将x的值赋给s->data
            s->next=p->next;                                                //1)将新结点S的后继指向结点P的后继
              s->prior=p;                                                                    //2)将新结点S的前驱指向原结点P
              p->next->prior=s;                                                //3)原结点P的后继结点的前驱指向新结点S
              p->next=s;                                                                      //4)原结点P的后继指向新结点S
              return(head);                                                                //返回带头结点双链表的头指针
}

3 双向链表的自身删除运算

假设双链表中某给定结点P的前驱结点为Q,其后继结点为S,则双链表中删除结点P的步骤如下:

1)。将结点P的前驱结点Q的后继结点指向结点P的后继结点S;
2)。将结点P的后继结点S的前驱结点指向结点Q;

插入新结点的过程如图1.2 (c)图所示。
在双链表中删除某个结点P自身的算法如下:

ptNode delete_node(ptNode head,ptNode p)
{
          if(p!=NULL)
          {
                  p->prior->next=p->next;
                  p->next->prior=p->prior;
                  free(p);
                  return(head);
          }
          else
          {
                return(NULL);
          }
}

由此可见,自身删除前后被删除的指针并没有改变,只是它后一个结点的向前指针和前一个结点的向后指针发生了变化,不再指向此结点。

这三种运算过程中,指针的变化情况分别如1.2 (a)、(b)、(c)图所示。






图1.2双向循环链表的前插、后插和自身删除操作示意图


完整的双向循环链表的操作:查询、删除、显示、插入 C程序在VC上验证通过:


#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define N 10
typedef struct node *ptNode;
structnode{     
      charname[20];     
      ptNodeprior,next;
};



ptNode Creat(int n)
   
      ptNodehead,ptr,newnode;   
      inti;     
      if((head=(ptNode)malloc(sizeof(node))) ==NULL)   
                 
            printf("分配内存失败!\n");             
            exit(0);     
         
      strcpy(head->name,"head");
      //head->name[0] ='\0';//头结点初始化 
      head->prior =NULL;     
      head->next =NULL;     
      ptr =head;   
      for(i=0;i<n;i++)     
                       
            if((newnode=(ptNode) malloc(sizeof(node))) ==NULL)           
                               
                  printf("cannot findspace!\n");                     
                  exit(0);           
                       
            ptr->next=newnode;//连接新结点           
            printf("Please input the %d man's name:",i+1);           
            scanf("%s",newnode->name);             
            newnode->prior =ptr;//定义newnode的连接关系             
            newnode->next =NULL;           
            ptr =newnode;     
      }//endfor     
      head->prior =newnode;   
      ptr->next =head;   
      return(head);
}


ptNode Search(ptNode head,char *pEle)
 
      ptNodeptr;   
      char*pTemp;     
      ptr =head->next;     
      while(ptr !=head)//以是否回到头结点为结束条件   
                 
            pTemp =ptr->name;//pTemp暂存结点的名字地址         
            if(strcmp(pTemp,pEle) ==0)             
                           
                  return(ptr);             
                       
            else               
                               
                  ptr =ptr->next;//指向下一结点           
               
         
      printf("查找不到数据!\n");     
      returnNULL;
}
//在选定名字前插入
void Insert_before(ptNode head,char *priorEle,char*insertEle)
         
      ptNodeptr,newnode;     
      if((ptr=Search(head,priorEle))==NULL)   
                 
            printf("Can't find the data toinsert!\n");             
            exit(0);     
         
      if((newnode=(ptNode)malloc(sizeof(node))) ==NULL)   
               
            printf("分配内存失败!\n");           
            exit(0);     
         
      strcpy(newnode->name,insertEle);//给新结点加载值   
      newnode->prior =ptr->prior;//前指针指向前结点,先处理以新结点为中心前后关系     
      newnode->next =ptr;//新结点后指针指向定位结点     
      (ptr->prior)->next =newnode;//前结点的由指针指向新结点     
      ptr->prior =newnode;     
}

//在选定名字后插入
void Insert_after(ptNode head,char *p,char *insertEle)
         
      ptNodeptr,newnode;     
      if((ptr=Search(head,p))==NULL)   
                 
            printf("Can't find the data toinsert!\n");             
            exit(0);     
         
      if((newnode=(ptNode)malloc(sizeof(node))) ==NULL)   
               
            printf("分配内存失败!\n");           
            exit(0);     
         
      strcpy(newnode->name,insertEle);//给新结点加载值   
      newnode->prior=ptr;
      newnode->next=ptr->next;
      ptr->next->prior=newnode;
      ptr->next=newnode;
}

void Print(ptNode head)
   
      ptNodeptr;   
      ptr =head->next;   
      //printf("\n正向循环双链表为:\n");     
      while(ptr !=head)   
      //while(ptr!= NULL) 
                 
            printf("%s",ptr->name);           
            ptr =ptr->next;     
         
      printf("\n");
}
void opposite(ptNode head)//反向输出
{
      ptNodeptr;
      ptr=head->next;
      while(ptr->next!=head)
          ptr=ptr->next;
      //printf("\n反向循环双链表为:\n");
      while(ptr!=head)
      {
          printf("%s",ptr->name);
          ptr=ptr->prior;
      }
      printf("\n");
}

void Delete(ptNode ptr)
   
      (ptr->next)->prior =ptr->prior;//(ptr->next)->prior下一结点的左指针被赋前指针   
      (ptr->prior)->next =ptr->next;     
      free(ptr);
}



void main(void)
   
      intnumber;     
      charstudName[20];   
      charinsertName[20];     
      ptNodehead,searchpoint; 
      intflag=1;
      charj;
      //number =N;     
      puts("输入双链表的最大结点数:");   
      scanf("%d",&number);     
      head =Creat(number);
      Print(head);   
      opposite(head);
      while(flag)
      {printf("请选择:\n");
          printf("1.显示所有元素\n");
          printf("2.删除一个元素\n");
          printf("3.元素前插入一个元素\n");
        printf("4.元素后插入一个元素\n");
          printf("5.退出程序      \n");
          scanf(" %c",&j);
          switch(j)
        {
            case'1':
                  printf("\n正向循环双链表为:\n"); 
                  Print(head);
                  printf("\n反向循环双链表为:\n");
                  opposite(head);
                  break;
            case'2':
                  printf("\n输入要删除的数据:\n");
                    scanf("%s",studName);     
                  searchpoint= Search(head,studName);
                  Delete(searchpoint);
                  printf("\n删除后的链表为:\n");
                  Print(head); 
              break;
            case'3':
                    printf("在双链表中指定一个元素的名字和要插入的数据(如aabb):\n");   
                  //scanf("%s",studName);     
                  //printf("输入想要插入的数据:\n");     
                  scanf("%s%s",studName,insertName);     
                  Insert_before(head,studName,insertName);   
                  Print(head); 
              break;
            case'4':
                    printf("在双链表中指定一个元素的名字和要插入的数据(如aabb):\n");     
                  //scanf("%s",studName);     
                  //printf("输入想要插入的数据:\n");     
                  scanf("%s%s",studName,insertName);     
                  Insert_after(head,studName,insertName);   
                  Print(head); 
              break;
            default:
              flag=0;
              printf("程序结束,按任意键退出!\n");
        }
      }
      getch();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值