zoukankan      html  css  js  c++  java
  • 单向链表和双向链表的原理及其相关实现

    (一)什么是链表?

    链表是线性表的一种,所谓的 线性表包含顺序线性表和链表,顺序线性表是用数组实现的,在内存中有顺序排列,通过改变数组大小实现。而链表不是用顺序实现的,用指针实现,在内存中不连 续。意思就是说,链表就是将一系列不连续的内存联系起来,将那种碎片内存进行合理的利用,解决空间的问题。

    所以,链表允许插入和删除表上任意位置上的节点,但是不允许随即存取。链表有很多种不同的类型:单向链表、双向链表及循环链表。

    1、那么先从单向链表着手,先看看单向链表的模拟图:


    单向链表包含两个域,一个是信息域,一个是指针域。也就是单向链表的节点被分成两部分,一部分是保存或显示关于节点的信息,第二部分存储下一个节点的地址,而最后一个节点则指向一个空值。

    2、双向链表:


    从上图可以很清晰的看出,每 个节点有2个链接,一个是指向前一个节点(当此链接为第一个链接时,指向的是空值或空列表),另一个则指向后一个节点(当此链接为最后一个链接时,指向的 是空值或空列表)。意思就是说双向链表有2个指针,一个是指向前一个节点的指针,另一个则指向后一个节点的指针。

    3、循环链表:


    循环链表就是首节点和末节点被连接在一起。循环链表中第一个节点之前就是最后一个节点,反之亦然。

    (二)链表有什么作用?

    链表本质上就是一种数据结构,主要用来动态放置数据。也可用来构建许多数据结构,比如堆栈、队列及它们的派生。

    (三)链表的实现?

    1、单向链表的实现

    (1)单向链表的创建过程:

    第一步:定义节点的数据结构;

    第二步:创建一个空表。

    第三步:利用malloc()向系统申请分配一个节点。

    第四步:将新节点的指针成员赋值为空。若是空表,将新节点连接到表头;若是非空表,将新节点连接到表尾。

    第五步:判断是否有后续节点,如有则转入第三步,否则结束。

    (2)单向链表的输出过程:

    第一步:找到表头。

    第二步:若为非空表,则输出节点的值成员,是空表则退出。

    第三步:跟踪链表,找到下一节点的地址。

    第四步:转到第二步。

    [html] view plain copy
     
    1. #include <stdio.h>  
    2. #include <conio.h>  
    3.   
    4. struct date//申明结构体  
    5. {  
    6.     char str;  
    7.     date *prior;   
    8.     date *next;//用来指向下一个结构体指针  
    9. };  
    10.   
    11. int main()  
    12. {  
    13.     date *pS,*pE,*head;//定义三个结构体指针,head用来保存链头,pE保存链尾  
    14.     date *Rhead = NULL;//定义读取结构体指针  
    15.     pE = head;//刚开始没有任何结点,指向表头  
    16.     char temp;  
    17.     scanf("%c",&temp);  
    18.     if(temp != '#')   
    19.     {  
    20.         head = new date;//新建结点  
    21.         head->str = temp;//给新结点赋值数据  
    22.         head->prior = NULL;  
    23.         head->next = NULL;  
    24.         pS = head;        
    25.     }   
    26.       
    27.     scanf("%c",&temp);  
    28.     while (temp != '#')  
    29.     {  
    30.             pS = new date;//新建结点  
    31.             pS->str = temp;//给新结点赋值数据  
    32.             pS->prior = pE;  
    33.             pS->next = NULL;//让指向下一个为空(新结点,也就是新链尾)  
    34.             pE->next = pS;//把新结点连接到链尾  
    35.             pE = pS;//新结点成为了新的链尾  
    36.     }  
    37.     printf(" 刚才输入的是: ");  
    38.     Rhead = head;//取得链头  
    39.     /*  
    40.         当然也可以直接用head不过这样就会改变其值,而无法再次查找链表  
    41.         切忌链头的重要性,只要找不到链头,整条链表就没用!  
    42.     */  
    43.     while (Rhead != NULL)//循环到链尾  
    44.     {  
    45.         printf("%c",Rhead->str);  
    46.         if (Rhead!=NULL)  
    47.         {  
    48.             Rhead = Rhead->next;//让其指向下一个链表  
    49.         }  
    50.     }  
    51.   
    52.     printf(" ");  
    53.     getch();  
    54.     return 0;  
    55. }  

    以上程序代码参考http://blog.csdn.net/duke56/article/details/5764614,比起其他实现,这个很直观明了。

    2、双向链表的实现

    [html] view plain copy
     
      1. #include"stdio.h"  
      2. #include"stdlib.h"  
      3.   
      4. typedef int DataType;//双向链表中数据的类型  
      5. typedef struct DNode  
      6. {  
      7.     DataType element;  
      8.     struct DNode *prior,*next;  
      9. }DNode,*DoubleList;//定义双向链表中一个节点  
      10.   
      11. DoubleList createDList()//创建双向链表  
      12. {  
      13.     DoubleList head,p1,p2;  
      14.     DataType data;  
      15.     scanf("%d",&data);  
      16.     if(data!=0)//初始化头结点  
      17.     {  
      18.         head=(DoubleList)malloc(sizeof(DNode));  
      19.         head->element=data;            //         head  
      20.         head->prior=NULL;      //----------------------  
      21.         head->next=NULL;       //|prior| data |  next |  
      22.         p1=head;               // -----------------------  
      23.     }                              //         p1  
      24.     else                         
      25.     {  
      26.         return NULL;//如果是0的话,直接跳出去,后面的工作一律不再进行  
      27.     }  
      28.     scanf("%d",&data);  
      29.     while(data!=0)                                         
      30.     {                                            //        head             p2                   
      31.         p2=(DoubleList)malloc(sizeof(DNode));//-----------------   -----------------      
      32.         p2->element=data;                    //|prior|data|next|-->|prior|data|next|   
      33.         p2->prior=p1;                        //-----------------    -----------------    
      34.         p2->next=NULL;                       //                           p1  
      35.         p1->next=p2;                                                                
      36.         p1=p2;                                 
      37.         scanf("%d",&data);                   //其实p1的作用就是为了把后面的  
      38.     }                                            //节点依次连接到双向链表的尾部  
      39.         return head;                               
      40. }                                              
      41.   
      42. DoubleList delDList(DoubleList head,DataType data)//删除链表某个节点,该节点的值等于data  
      43. {  
      44.     DoubleList p;  
      45.     if(head==NULL)  
      46.     {  
      47.     return NULL;  
      48.     }  
      49.     if(data==0)  
      50.     {  
      51.         printf("please input the data which will be deleted! ");  
      52.         scanf("%d",&data);  
      53.     }  
      54.         p=head;//让p指向头结点,p在双向链表上移动,完成相应的操作  
      55.     while(p!=NULL&& p->element!=data)//用p->element!=data而不是p->element=data,  
      56.     {                                //是想让p在循环的控制下,在双向链表上不断移动  
      57.         p=p->next;  
      58.     }  
      59.     if(p!=NULL)  
      60.     {  
      61.     if(p==head)//如果第一次的时候就跳出来的话,p肯定指向的是head  
      62.     {  
      63.         head=p->next;//删除头结点  
      64.         head->prior=NULL;  
      65.         free(p);  
      66.     }  
      67.     else  
      68.     {  
      69.     if(p->next==NULL)//已经找到最后一个节点了才找到  
      70.     {  
      71.         (p->prior)->next=NULL;  
      72.         free(p);  
      73.     }  
      74.     else //中间某个节点上找到了要删除的节点  
      75.     {  
      76.         p->prior->next=p->next; //语句1  1和2次序很关键,绝对不能颠倒  
      77.         p->next->prior=p->prior;//语句2  
      78.         free(p);  
      79.     }  
      80.     }  
      81.     }  
      82.     else  
      83.     {  
      84.         printf("we can not find the element that you want to find! ");  
      85.     }  
      86.     return head;  
      87. }  
      88.   
      89. void printDList(DoubleList head)  
      90. {  
      91.     DoubleList p=head;  
      92.     while(p!=NULL)  
      93.     {  
      94.         printf("%d ",p->element);  
      95.         p=p->next;  
      96.     }  
      97.     printf(" ");  
      98. }  
      99.   
      100. void freeDList(DoubleList head)  
      101. {  
      102.     DoubleList p;  
      103.     if(head==NULL)  
      104.     {  
      105.         return;  
      106.     }  
      107.     while(head!=NULL)  
      108.     {  
      109.         p=head->next;  
      110.         free(head);  
      111.         head=p;  
      112.     }  
      113. }  
      114.   
      115. int main(void)  
      116. {  
      117.     DoubleList head;  
      118.     printf("please input the interge,and create the Doublelist!  ");  
      119.     head=createDList();  
      120.     printf("print the Doublelist you have created! ");  
      121.     printDList(head);  
      122.     printf("delete the Doublelist! ");  
      123.     head=delDList(head,0);//delDList()函数有返回值  
      124.     printf("print the Doublelist you have deleted! ");  
      125.     printDList(head);  
      126.     freeDList(head);  
      127. }  
  • 相关阅读:
    Python学习之路 (五)爬虫(四)正则表示式爬去名言网
    Python学习之路 (四)爬虫(三)HTTP和HTTPS
    Python学习之路 (三)爬虫(二)
    Python学习之路 (二)爬虫(一)
    Python学习之路 (一)开发环境搭建
    ZooKeeper学习之路 (十一)ZooKeeper API的应用
    ZooKeeper学习之路 (十)Hadoop的HA集群的机架感知
    Spring Security
    Spring Validation
    [转]linux下完全备份数据库mysql
  • 原文地址:https://www.cnblogs.com/yixiao21/p/8398056.html
Copyright © 2011-2022 走看看