单向链表和双向链表的原理及其相关实现

(一)什么是链表?

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

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

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

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

2、双向链表:

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

3、循环链表:

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

(二)链表有什么作用?

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

(三)链表的实现?

1、单向链表的实现

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

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

第二步:创建一个空表。

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

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

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

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

第一步:找到表头。

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

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

第四步:转到第二步。

[html] view plain copy

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

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

2、双向链表的实现

[html] view plain copy

    1. #include"stdio.h"
    2. #include"stdlib.h"
    3. typedef int DataType;//双向链表中数据的类型
    4. typedef struct DNode
    5. {
    6. DataType element;
    7. struct DNode *prior,*next;
    8. }DNode,*DoubleList;//定义双向链表中一个节点
    9. DoubleList createDList()//创建双向链表
    10. {
    11. DoubleList head,p1,p2;
    12. DataType data;
    13. scanf("%d",&data);
    14. if(data!=0)//初始化头结点
    15. {
    16. head=(DoubleList)malloc(sizeof(DNode));
    17. head->element=data;            //         head
    18. head->prior=NULL;      //----------------------
    19. head->next=NULL;       //|prior| data |  next |
    20. p1=head;               // -----------------------
    21. }                              //         p1
    22. else
    23. {
    24. return NULL;//如果是0的话,直接跳出去,后面的工作一律不再进行
    25. }
    26. scanf("%d",&data);
    27. while(data!=0)
    28. {                                            //        head             p2
    29. p2=(DoubleList)malloc(sizeof(DNode));//-----------------   -----------------
    30. p2->element=data;                    //|prior|data|next|-->|prior|data|next|
    31. p2->prior=p1;                        //-----------------    -----------------
    32. p2->next=NULL;                       //                           p1
    33. p1->next=p2;
    34. p1=p2;
    35. scanf("%d",&data);                   //其实p1的作用就是为了把后面的
    36. }                                            //节点依次连接到双向链表的尾部
    37. return head;
    38. }
    39. DoubleList delDList(DoubleList head,DataType data)//删除链表某个节点,该节点的值等于data
    40. {
    41. DoubleList p;
    42. if(head==NULL)
    43. {
    44. return NULL;
    45. }
    46. if(data==0)
    47. {
    48. printf("please input the data which will be deleted!\n");
    49. scanf("%d",&data);
    50. }
    51. p=head;//让p指向头结点,p在双向链表上移动,完成相应的操作
    52. while(p!=NULL&& p->element!=data)//用p->element!=data而不是p->element=data,
    53. {                                //是想让p在循环的控制下,在双向链表上不断移动
    54. p=p->next;
    55. }
    56. if(p!=NULL)
    57. {
    58. if(p==head)//如果第一次的时候就跳出来的话,p肯定指向的是head
    59. {
    60. head=p->next;//删除头结点
    61. head->prior=NULL;
    62. free(p);
    63. }
    64. else
    65. {
    66. if(p->next==NULL)//已经找到最后一个节点了才找到
    67. {
    68. (p->prior)->next=NULL;
    69. free(p);
    70. }
    71. else //中间某个节点上找到了要删除的节点
    72. {
    73. p->prior->next=p->next; //语句1  1和2次序很关键,绝对不能颠倒
    74. p->next->prior=p->prior;//语句2
    75. free(p);
    76. }
    77. }
    78. }
    79. else
    80. {
    81. printf("we can not find the element that you want to find!\n");
    82. }
    83. return head;
    84. }
    85. void printDList(DoubleList head)
    86. {
    87. DoubleList p=head;
    88. while(p!=NULL)
    89. {
    90. printf("%d\t",p->element);
    91. p=p->next;
    92. }
    93. printf("\n");
    94. }
    95. void freeDList(DoubleList head)
    96. {
    97. DoubleList p;
    98. if(head==NULL)
    99. {
    100. return;
    101. }
    102. while(head!=NULL)
    103. {
    104. p=head->next;
    105. free(head);
    106. head=p;
    107. }
    108. }
    109. int main(void)
    110. {
    111. DoubleList head;
    112. printf("please input the interge,and create the Doublelist! \n");
    113. head=createDList();
    114. printf("print the Doublelist you have created!\n");
    115. printDList(head);
    116. printf("delete the Doublelist!\n");
    117. head=delDList(head,0);//delDList()函数有返回值
    118. printf("print the Doublelist you have deleted!\n");
    119. printDList(head);
    120. freeDList(head);
    121. }

原文地址:https://www.cnblogs.com/yixiao21/p/8398056.html

时间: 2024-07-28 17:56:32

单向链表和双向链表的原理及其相关实现的相关文章

[算法]反转单向链表和双向链表

题目: 分别实现反转单向链表和双向链表的函数. 要求: 如果链表长度为N,时间复杂度为O(N),额外空间复杂度要求为O(1). 程序: 反转单向链表: public class Node{ public Node(int data){ this.value=data; } public int value; public Node next; } public static Node reverseList(Node node){ Node pre=null; Node next=null; w

用Python写单向链表和双向链表

链表是一种数据结构,链表在循环遍历的时候效率不高,但是在插入和删除时优势比较大. 链表由一个个节点组成. 单向链表的节点分为两个部分:存储的对象和对下一个节点的引用.注意是指向下一个节点. 而双向链表区别于单向链表的是它是由三个部分组成:存储的对象.对下一个节点的引用.对上一个节点的引用,可以实现双向遍历. 单向列表的结构如下图: head是头节点,tail是尾节点,每个节点由Data存储对象和Next对下一个节点引用组成 下面说一下单向链表插入和删除的过程. 插入一个新节点: 原理:前一个节点

Java-链表(单向链表、双向链表)

Java-链表 1.什么是链表? 2.链表的特点是什么? 3.链表的实现原理? 4.如何自己写出一个链表? 1.什么是链表? 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针连接次序实现的. 每一个链表都包含多个节点,节点又包含两个部分,一个是数据域(储存节点含有的信息),一个是引用域(储存下一个节点或者上一个节点的地址). 链表的理解示意图 2.链表的特点是什么? 获取数据麻烦,需要遍历查找,比数组慢 方便插入.删除 3.链表的实现原理 创建一个节点类,其

单向链表和双向链表简介

1.单向链表内存结构图 2.双向链表内存图 QQ交流群:4060038 原文地址:https://www.cnblogs.com/zhangjianbing/p/8284654.html

数据结构和算法--3链表(单向链表、双向链表、环形单向链表和约瑟夫问题)

链表 链表是以节点的方式来存储 每个节点包含data域和next域,指向下一个节点 链表的各个节点不一定是连续存储 链表分带头节点的链表和没有头节点的链表,根据实际的需求来确定 单向列表 最大特点是可以将物理地址上不连续的数据连接起来,通过指针来对物理地址进行操作,实现增删改查等功能. 单链表分为两种:有头链表和无头链表. 有头节点的增删改查 定义一个单链表的类: //定义一个SingleLinkedList,单链表,管理HeroNode class SingleLinkedList{ //初始

数据结构--单向链表

C语言中,我们在使用数组时,会需要对数组进行插入和删除的操作,这时就需要移动大量的数组元素,但在C语言中,数组属于静态内存分配,数组在定义时就必须指定数组的长度或者初始化.这样程序一旦运行,数组的长度就不能再改变,若想改变,就只能修改源代码.实际使用中数组元素的个数也不能超过数组元素的最大长度,否则就会发生下标越界的错误(这是新手在初学C语言时肯定会遇到的问题,相信老师也会反复强调!!!但这种问题肯定会遇到,找半天找不到错误在哪,怪我咯???).另外如果数组元素的使用低于最大长度,又会造成系统资

数据结构-单向链表相关算法

#include <stdio.h>#include <stdlib.h>#define OVERFLOW -2#define OK 1#define ERROR 0typedef int ElemType;//单向链表结构体typedef struct LNode {    ElemType data;    struct LNode *next;}LNode,*LinkList; LinkList CreateList_L(LinkList L,int n);void Trav

C++异常机制的实现方式和开销分析 (大图,编译器会为每个函数增加EHDL结构,组成一个单向链表,非常著名的“内存访问违例”出错对话框就是该机制的一种体现)

白杨 http://baiy.cn 在我几年前开始写<C++编码规范与指导>一文时,就已经规划着要加入这样一篇讨论 C++ 异常机制的文章了.没想到时隔几年以后才有机会把这个尾巴补完 :-). 还是那句开场白:“在恰当的场合使用恰当的特性” 对每个称职的 C++ 程序员来说都是一个基本标准.想要做到这点,就必须要了解语言中每个特性的实现方式及其时空开销.异常处理由于涉及大量底层内容,向来是 C++ 各种高级机制中较难理解和透彻掌握的部分.本文将在尽量少引入底层细节的前提下,讨论 C++ 中这一

【转】单向链表(单链表)的Java实现

最近被问到链表,是一个朋友和我讨论Java的时候说的.说实话,我学习编程的近一年时间里,学到的东西还是挺少的.语言是学了Java和C#,关 于Web的学了一点Html+css+javascript.因为比较偏好,学习WinForm时比较认真,数据库操作也自己有所研究.但链表这个东西我 还真没有学习和研究过,加上最近自己在看WPF,而课程也到了JSP了,比较紧. 但是我还是抽了一个晚上加半天的时间看了一下单向链表.并且使用Java试着写了一个实例出来.没有接触过链表的朋友可以作为参考,希望大家多提