• 线性表的链式存储的基本


    链表是线性表的链式存储方式,逻辑上相邻的数据在计算机内的存储位置不一定相邻,因此,我们需要为每一个元素设置有一个指针来指向与它逻辑相邻的元素。

    为此,我们为每个元素设置一个结点,每个结点由数据域和指针域组成,数据域用来存放该结点的元素值,指针域用来存放与其逻辑相邻的元素的地址。

    链表有带头结点的链表和不带头结点的链表之分,带头结点的链表会有一个头结点,头结点

    单链表只能向后走,不能往回走。

    为了操作方便,我们给单向链表加了头结点,头结点的data域是不存储数据的,

    什么时候操作方便呢?当我们把第一个结点删除的时候,如果在没有头结点的情况下,删除第一个结点与删除其他结点是不一样的,因为我们需要改头指针,第一个结点删除,头指针需要指向第二个;但是当我们设置头结点后,我要删除第一个结点,头指针是不用动的。

     单链表的基本操作包含:

    • 初始化

    首先要生成一个结点,然后将其next域置空。

    • 创建

    头插法:采用头插法将结点s插入链表L中,逆序建表

    1. s->next = L->next;
    2. L->next = s;

     

     尾插法:采用尾插法将结点s插入链表L中,正序建表

    1. 定义尾指针r记录尾结点
    2. 创建新生成了的结点用s,将待插值赋给结点s的data域,并将s结点的next域置空
    3. r->next = s;
    4. r = s;更新尾指针

     

    • 取值:找链表L的第i个结点
    1. 链表头指针不可以随意改动
    2. 设置一个指针 p 指向第一个元素即  p = L->next;
    3. 设置计数变量 j  并将其初始化为1
    4. 如果 j < i 且 p->next != NULL,继续向后找即  p = p->next; j++;
    5. 一直走到 j == i ,成功找到了链表L的第i个结点
    6. 一直往后找的时候,需要判断有没有走到链表的头部,有没有等空,等空就不需要再找了
    7. 另外,需要判断 j 是否小于 i,如果大于的话,也不需要再找了

    • 插入:再链表的第 i 个结点之前插入新结点s
    1. 先找到第 i-1 个结点,让p指针指向该结点
    2.  s->next = p->next;
    3. p->next = s;

     

    • 查找:在单链表L中查找data域为e的结点
    1. 定义指针p并将其指向链表的第一个结点
    2. 在p结点存在的情况下,判断p的data域的值是否等于e,如果不等于继续向后查找
    3. 如果找到链表结尾仍然没有找到,返回false
    4. 如果找到的情况下,返回true

    • 删除:删除链表L的第 i 个结点
    1. 查找链表的第 i - 1 个结点,将p指向该节点
    2. 判断删除的结点位置是否合理,如果第 i - 1 个结点的next域为空,即不存在要删除的第 i 个结点,或者 如果要删除的位置索引 i 大于链表的长度或者小于 0时,删除位置不合理
    3. 如果删除位置合理的话,用指针q指向待删除的第 i 个结点,即p->next
    4. 将第 i - 1 个结点的next指向第 i 个结点的next域所指向的第 i+1 个结点
    5. 最后通过delete命令释放第 i 个结点的空间

     

     

     

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. typedef struct LNode {
    7. int data; //结点的数据域
    8. struct LNode *next; //结点的指针域
    9. }LNode, *LinkList; //LinkList为指向结构体LNode的指针类型
    10. bool InitList_L(LinkList &L)//构造一个空的单链表L
    11. {
    12. L=new LNode; //生成新结点作为头结点,用头指针L指向头结点
    13. if(!L)
    14. return false; //生成结点失败
    15. L->next=NULL; //头结点的指针域置空
    16. return true;
    17. }
    18. void CreateList_H(LinkList &L)//前插法创建单链表
    19. {
    20. //输入n个元素的值,建立到头结点的单链表L
    21. int n;
    22. LinkList s; //定义一个指针变量
    23. L=new LNode;
    24. L->next=NULL; //先建立一个带头结点的空链表
    25. cout <<"请输入元素个数n:" <
    26. cin>>n;
    27. cout <<"请依次输入n个元素:" <
    28. cout <<"前插法创建单链表..." <
    29. while(n--)
    30. {
    31. s=new LNode; //生成新结点s
    32. cin>>s->data; //输入元素值赋给新结点的数据域
    33. s->next=L->next;
    34. L->next=s; //将新结点s插入到头结点之后
    35. }
    36. }
    37. void CreateList_R(LinkList &L)//尾插法创建单链表
    38. {
    39. //输入n个元素的值,建立带表头结点的单链表L
    40. int n;
    41. LinkList s, r;
    42. L=new LNode;
    43. L->next=NULL; //先建立一个带头结点的空链表
    44. r=L; //尾指针r指向头结点
    45. cout <<"请输入元素个数n:" <
    46. cin>>n;
    47. cout <<"请依次输入n个元素:" <
    48. cout <<"尾插法创建单链表..." <
    49. while(n--)
    50. {
    51. s=new LNode;//生成新结点
    52. cin>>s->data; //输入元素值赋给新结点的数据域
    53. s->next=NULL;
    54. r->next=s;//将新结点s插入尾结点*r之后
    55. r=s;//r指向新的尾结点s
    56. }
    57. }
    58. bool GetElem_L(LinkList L, int i, int &e)//单链表的取值
    59. {
    60. //在带头结点的单链表L中查找第i个元素
    61. //用e记录L中第i个数据元素的值
    62. int j;
    63. LinkList p;
    64. p=L->next;//p指向第一个结点,
    65. j=1; //j为计数器
    66. while (j//顺链域向后扫描,直到p指向第i个元素或p为空
    67. {
    68. p=p->next; //p指向下一个结点
    69. j++; //计数器j相应加1
    70. }
    71. if (!p || j>i)
    72. return false; //i值不合法i>n或i<=0
    73. e=p->data; //取第i个结点的数据域
    74. return true;
    75. }
    76. bool LocateElem_L(LinkList L, int e) //按值查找
    77. {
    78. //在带头结点的单链表L中查找值为e的元素
    79. LinkList p;
    80. p=L->next;
    81. while (p && p->data!=e)//顺链域向后扫描,直到p为空或p所指结点的数据域等于e
    82. p=p->next; //p指向下一个结点
    83. if(!p)
    84. return false; //查找失败p为NULL
    85. return true;
    86. }
    87. bool ListInsert_L(LinkList &L, int i, int e)//单链表的插入
    88. {
    89. //在带头结点的单链表L中第i个位置插入值为e的新结点
    90. int j;
    91. LinkList p, s;
    92. p=L;
    93. j=0;
    94. while (p&&j-1) //查找第i-1个结点,p指向该结点
    95. {
    96. p=p->next;
    97. j++;
    98. }
    99. if (!p || j>i-1)//i>n+1或者i<1
    100. return false;
    101. s=new LNode; //生成新结点
    102. s->data=e; //将新结点的数据域置为e
    103. s->next=p->next; //将新结点的指针域指向结点ai
    104. p->next=s; //将结点p的指针域指向结点s
    105. return true;
    106. }
    107. bool ListDelete_L(LinkList &L, int i) //单链表的删除
    108. {
    109. //在带头结点的单链表L中,删除第i个位置
    110. LinkList p, q;
    111. int j;
    112. p=L;
    113. j=0;
    114. while((p->next)&&(j-1)) //查找第i-1个结点,p指向该结点
    115. {
    116. p=p->next;
    117. j++;
    118. }
    119. if (!(p->next)||(j>i-1))//当i>n或i<1时,删除位置不合理
    120. return false;
    121. q=p->next; //临时保存被删结点的地址以备释放空间
    122. p->next=q->next; //改变删除结点前驱结点的指针域
    123. delete q; //释放被删除结点的空间
    124. return true;
    125. }
    126. void Listprint_L(LinkList L) //单链表的输出
    127. {
    128. LinkList p;
    129. p=L->next;
    130. while (p)
    131. {
    132. cout<data<<"\t";
    133. p=p->next;
    134. }
    135. cout<
    136. }
    137. int main()
    138. {
    139. int i,x,e,choose;
    140. LinkList L;
    141. cout << "1. 初始化\n";
    142. cout << "2. 创建单链表(前插法)\n";
    143. cout << "3. 创建单链表(尾插法)\n";
    144. cout << "4. 取值\n";
    145. cout << "5. 查找\n";
    146. cout << "6. 插入\n";
    147. cout << "7. 删除\n";
    148. cout << "8. 输出\n";
    149. cout << "0. 退出\n";
    150. choose=-1;
    151. while (choose!=0)
    152. {
    153. cout<<"请输入数字选择:";
    154. cin>>choose;
    155. switch (choose)
    156. {
    157. case 1: //初始化一个空的单链表
    158. if (InitList_L(L))
    159. cout << "初始化一个空的单链表!\n";
    160. break;
    161. case 2: //创建单链表(前插法)
    162. CreateList_H(L);
    163. cout << "前插法创建单链表输出结果:\n";
    164. Listprint_L(L);
    165. break;
    166. case 3: //创建单链表(尾插法)
    167. CreateList_R(L);
    168. cout << "尾插法创建单链表输出结果:\n";
    169. Listprint_L(L);
    170. break;
    171. case 4: //单链表的按序号取值
    172. cout << "请输入一个位置i用来取值:";
    173. cin >> i;
    174. if (GetElem_L(L,i,e))
    175. {
    176. cout << "查找成功\n";
    177. cout << "第" << i << "个元素是:"<
    178. }
    179. else
    180. cout << "查找失败\n\n";
    181. break;
    182. case 5: //单链表的按值查找
    183. cout<<"请输入所要查找元素x:";
    184. cin>>x;
    185. if (LocateElem_L(L,x))
    186. cout << "查找成功\n";
    187. else
    188. cout << "查找失败! " <
    189. break;
    190. case 6: //单链表的插入
    191. cout << "请输入插入的位置和元素(用空格隔开):";
    192. cin >> i;
    193. cin >> x;
    194. if (ListInsert_L(L, i, x))
    195. cout << "插入成功.\n\n";
    196. else
    197. cout << "插入失败!\n\n";
    198. break;
    199. case 7: //单链表的删除
    200. cout<<"请输入所要删除的元素位置i:";
    201. cin>>i;
    202. if (ListDelete_L(L, i))
    203. cout<<"删除成功!\n";
    204. else
    205. cout<<"删除失败!\n";
    206. break;
    207. case 8: //单链表的输出
    208. cout << "当前单链表的数据元素分别为:\n";
    209. Listprint_L(L);
    210. cout << endl;
    211. break;
    212. }
    213. }
    214. return 0;
    215. }

  • 相关阅读:
    3D视觉 之 线激光3D相机
    Vue 使用SignalR.JS与Microsoft.AspNetCore.SignalR实时通讯
    StringBuilder,Stringbuffer和String相关面试笔试
    七周成为数据分析师 | 数据可视化
    Idea springboot 配置https
    Cadence OrCAD Capture CIS ODBC数据库文件在两台电脑上同步使用时一台电脑启动失败的问题解决图文教程
    Python毕业设计开题报告房屋租赁租房数据分析和展示系统
    用稳定扩散生成4K PBR纹理【SDXL】
    mabatis2:简单启动mybatis
    Ribbon 服务调用配置实战
  • 原文地址:https://blog.csdn.net/fencecat/article/details/127969395