当前位置:   article > 正文

数据结构与算法基础(王卓)(5):关于(单)链表较复杂的操作_将值为e的先结点,插入到单链表的第i个位置,及插入到结点,值为a和b之间,画出过

将值为e的先结点,插入到单链表的第i个位置,及插入到结点,值为a和b之间,画出过

目录

取第i个元素

按值查找(查找其地址,以及是表中第几个元素(位置序号))

插入(把元素e插到第i个位置结点上)

删除(链表中第i个元素结点)

单链表的建立(头插法)<倒序插入>

单链表的建立(尾插法)<顺序插入>


位置:PPT第二章:127


默认前置:

  1. #include<iostream>
  2. using namespace std;
  3. #include<stdlib.h>//存放exit
  4. #include<math.h>//OVERFLOW,exit
  5. #define MAXlength 100 //初始大小为100,可按需修改
  6. typedef int Status; //函数调用状态
  7. struct K
  8. {
  9. float a;
  10. int b;
  11. string c;
  12. };
  13. typedef K Elemtype; //函数调用状态
  14. struct Lnode
  15. //node:结; 结点;
  16. {
  17. Elemtype data;
  18. Lnode* next;
  19. };
  20. typedef Lnode* LinkList;

取第i个元素

project 1:(自己写的,凑合着也能用)

  1. Status 取第i个元素(LinkList L, int i,Elemtype e)
  2. {
  3. if (链表是否为空(L))
  4. cerr << "链表为空" << endl;
  5. if (i < 1)
  6. cerr << "i不对" << endl;
  7. LinkList p = L->next;
  8. int j = 0;
  9. while (p)
  10. {
  11. if (i == j)
  12. {
  13. e = p->data;
  14. break;
  15. }
  16. p = p->next;
  17. j++;
  18. }
  19. return true;
  20. }

project 2:根据课程上写的(算法复杂度低一些,比较好用)

  1. Status GetElem“i”(LinkList L, int i, Elemtype e)
  2. {
  3. LinkList p;
  4. p = L->next;
  5. int j = 1;
  6. while (p && i > j)
  7. {
  8. p = p->next;
  9. j++;
  10. }
  11. if (i<0 || i<j || !p)
  12. return false;
  13. e=p->data;
  14. return true;
  15. }

按值查找(查找其地址,以及是表中第几个元素(位置序号))

project 1:

  1. Status 按值查找地址和位置序号(LinkList L,Elemtype e)
  2. {
  3. LinkList p; int i=1;
  4. p = L->next;
  5. while (p)
  6. {
  7. i++;
  8. if (e == p->data)
  9. {
  10. cout << "地址为: " << p << ";" << endl;
  11. cout << "位置序号为: " << i <<";" << endl;
  12. }
  13. p = p->next;
  14. }
  15. //如果最后运行失败查找不到最后怎么返回ERROR?
  16. if (p = NULL)
  17. return NULL;
  18. return true;
  19. }

 但是要注意,如果要这么写的话,在类型K的声明里,还需要加上手撸判断表达式的定义:

  1. struct K
  2. {
  3. float a;
  4. int b;
  5. string c;
  6. bool operator==(K& t)
  7. {
  8. return t.a == a && t.b == b;
  9. //&& t.c = c;
  10. }
  11. };
  12. typedef K Elemtype; //函数调用状态

 project 2:根据课程上写的(算法复杂度低一些,比较好用)

  1. Status LocateELem(LinkList L, Elemtype e)
  2. {
  3. //在线性表L中查找值为e的数据元素
  4. //找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
  5. auto p = L->next; int i=1;
  6. while (p && p->data != e)
  7. {
  8. i++;
  9. if (e == p->data)
  10. {
  11. cout << "地址为: " << p << ";" << endl;
  12. cout << "位置序号为: " << i << ";" << endl;
  13. }
  14. p = p->next;
  15. }
  16. if (p == NULL)
  17. return NULL;
  18. return true;
  19. }

同理:

  1. struct K
  2. {
  3. float a;
  4. int b;
  5. string c;
  6. bool operator==(K& t)
  7. {
  8. return t.a == a && t.b == b;
  9. //&& t.c = c;
  10. }
  11. bool operator!=(K& t)
  12. {
  13. return t.a != a || t.b != b;
  14. //|| t.c = c;
  15. }
  16. };
  17. typedef K Elemtype; //函数调用状态

插入(把元素e插到第i个位置结点上)

 project 1:

  1. Status 插入(LinkList L,int i,Elemtype e)
  2. {
  3. LinkList p,s; int j = 1;
  4. p = L->next;
  5. s->data = e;
  6. while (p)//&& j < i)
  7. {
  8. if (j == i-1)
  9. {
  10. s->next = p->next;
  11. p->next = s;
  12. return true;
  13. }
  14. p = p->next;
  15. j++;
  16. }
  17. if (!p || j > i - 1)
  18. return false;//别忘了写插入非法时的情况
  19. }

 project 2:根据课程上写的

  1. Status Listlnsert(LinkList& L, int i, Elemtype e)
  2. {
  3. auto p = L; int j = 0;
  4. while (p && j < i - 1)
  5. { p = p->next; ++j; }
  6. if (!p ||j > i - 1)
  7. return false;
  8. auto s = new Lnode;
  9. s->data = e;
  10. s->next=p->next;
  11. p->next = s;
  12. return true;
  13. }//Listlnsert_L

问题:(其实我觉得应该是一样的,只是把这个还没有确定的问题暂时先放在这里mark一下希望来日可以顺利解答)在这个算法里:

int j = 1;p = L->next;

auto p = L; int j = 0;

等价吗

删除(链表中第i个元素结点)

project 1:

  1. Status 删除(LinkList& L, int i)
  2. {
  3. LinkList p,s,q; int j=1;
  4. while (p&&j<i-1)
  5. {
  6. p->next;
  7. j++;
  8. }
  9. s = p->next;
  10. q = s->next;
  11. delete s;
  12. p = q;
  13. return true;
  14. }

project 2:

  1. Status 删除(LinkList& L, int i)
  2. {
  3. LinkList p, s; int j = 1;
  4. while (p && j < i - 1)
  5. {
  6. p->next;
  7. j++;
  8. }
  9. s = (p->next)->next;
  10. delete p->next;
  11. p->next = s;
  12. return true;
  13. }

project 3:根据视频(逻辑更严谨)

  1. Status 删除(LinkList& L, int i)
  2. {
  3. LinkList p = L, s; int j = 1;
  4. while (p && j < i - 1)
  5. {
  6. p = p->next;
  7. j++;
  8. }
  9. if (!p || j > i - 1)
  10. return false;
  11. s = p->next;
  12. p->next = s->next;
  13. //auto e = s->data;
  14. delete s;
  15. return true;
  16. }

各操作的时间复杂度:

单链表的查找、插入和删除:O(n)

线性表的插入和删除:O(1)



单链表的建立(头插法)<倒序插入>

project 1:

用头插法建立链表,并插入(输入)数据结点(这里简化我们只输入3个)a,b,c

  1. Status 头插法(LinkList &L)
  2. {
  3. //创建空链表
  4. K a, b, c;
  5. L= new Lnode;//就一个首元结点
  6. L->next = NULL;
  7. //L->data里面没什么东西
  8. //(我们也不知道里面有啥)
  9. //但可以确定,里面不为空(NULL)
  10. auto p = new Lnode;//(头)插入
  11. L->data = c;
  12. p->next = L->next;
  13. L->next = p;
  14. //每次循环的操作,唯一的区别只有:
  15. //data域输入的数值不同
  16. auto p = new Lnode;
  17. L->data = b;
  18. p->next = L->next;
  19. L->next = p;
  20. //
  21. auto p = new Lnode;
  22. L->data = a;
  23. p->next = L->next;
  24. }

实际上,这个程序是错的,程序设计逻辑:

Points:

关于

L= new Lnode;

实际上我觉得真的是多此一举:

系统开始带有参数LinkList &L的时候不是实际上已经提前给你默认提前分配好了L的内存空间吗,你他*还在这边费劲干啥呢

另外,   L= new Lnode;这种开辟空间的格式是哪弄出来的???

原来学过关于new的用法,只有通过定义指针分配新空间,like:

   Lnode* p = new Lnode;

但是既然这里可行可用,那我们也需要记住:

L= new Lnode;

即:

<开辟空间首地址> = new  <开辟空间存放数据类型>

格式(前面没有定义过记得加auto)

最后经过我们后面深入专门去学习了关于new的使用方法和格式,发现并不是这么一回事:

并不是因为代表L是表,而像我们猜测的那样有了什么新的格式

而是由于表头前面的Linklist &L,表明了他本来就是一个指针,依然属于符合原来的使用规范

也就是说,如果前面(形参传递时)我们已经定义过了该变量,那么在后面开辟空间时

我们就不用(也不能)再(重新)申明变量的类型

详见:

数据结构与算法基础(王卓)(8)附:关于new的使用方法详解_宇 -Yu的博客-CSDN博客_数据结构new

C语言日记 26 指针与函数,动态存储分配_宇 -Yu的博客-CSDN博客

末尾


OK,现在,我们来修正project 1:

注意如果我们想要实现像前面画的图中的“我们想要达到的效果”,那是不可能的了

我们最多只能退而求其次:

让头指针指向头结点,搞一个新的首元结点插进去,而不是搞个新的首元结点(办不到)

project 2:

其实要实现对前面的修正和更改也很简单,只需:

把语句 L->data = (结点信息);修改为:p->data = (结点信息),即可;

  1. Status 头插法(LinkList& L)
  2. {
  3. //创建空链表
  4. K a, b, c;
  5. L = new Lnode;//就一个首元结点
  6. L->next = NULL;//别忘了这句
  7. //L->data里面没什么东西
  8. //(我们也不知道里面有啥)
  9. //但可以确定,里面不为空(NULL)
  10. auto p = new Lnode;//(头)插入
  11. p->data = c;
  12. p->next = L->next;
  13. L->next = p;
  14. //
  15. auto p = new Lnode;
  16. p->data = b;
  17. p->next = L->next;
  18. L->next = p;
  19. //
  20. auto p = new Lnode;
  21. p->data = a;
  22. p->next = L->next;
  23. }

正式根据PPT(148)设计的程序流程来设计实现程序:

Project 3:

  1. Status 头插法()//LinkList &L)
  2. {
  3. //创建空链表
  4. auto L = new Lnode;
  5. //创建新节点
  6. auto p = new Lnode;
  7. K an,an_1;
  8. p->data = an;
  9. //把新节点和链表串起来
  10. p->next = L->next;
  11. L->next = p;
  12. //重复下一轮循环
  13. auto p = new Lnode;
  14. p->next = L->next;
  15. L->next = p;
  16. }

将其实现为我们具体能够落地实现使用的函数:(假设我们输入n个节点的数据)

  1. Status 头插法(LinkList& L, int n)
  2. {
  3. //创建空链表
  4. auto L = new Lnode;
  5. L->next = NULL;//别忘了这句
  6. int i = 1;
  7. while (i <= n)
  8. {
  9. auto p = new Lnode;
  10. cin >> p->data.a;
  11. cin >> p->data.b;
  12. cin >> p->data.c;
  13. p->next = L->next;
  14. L->next = p;
  15. i++;
  16. }
  17. return true;
  18. }

这个结果基本和标准答案差不多,只不过标准答案用的是for语句:

  1. void CreatListHead(LinkList& L, int n)
  2. {
  3. auto L = new Lnode;
  4. L->next = NULL;//别忘了这句
  5. for (int i = n; i > 0; --i)
  6. //for (int i = 0; i < n; ++i)
  7. {
  8. auto p = new Lnode;
  9. cin >> p->data.a;
  10. cin >> p->data.b;
  11. cin >> p->data.c;
  12. p->next = L->next;
  13. L->next = p;
  14. i++;
  15. }
  16. }

最终使用时,不能使返回表和构造表重定义:

  1. Status 头插法(LinkList& A, int n)
  2. {
  3. //创建空链表
  4. auto L = new Lnode;
  5. L->next = NULL;//别忘了这句
  6. int i = 1;
  7. while (i <= n)
  8. {
  9. auto p = new Lnode;
  10. cin >> p->data.a;
  11. cin >> p->data.b;
  12. cin >> p->data.c;
  13. p->next = L->next;
  14. L->next = p;
  15. i++;
  16. }
  17. A = L;
  18. return true;
  19. }

时间复杂度:O(n) 

单链表的建立(尾插法)<顺序插入>

project 1:

  1. Status 尾插法(int n)
  2. {
  3. auto L = new Lnode;
  4. L->next = NULL;
  5. LinkList r = L;
  6. for (auto i = 1; i <= n; i++)
  7. {
  8. auto p = new Lnode;
  9. cin >> p->data.a;
  10. cin >> p->data.b;
  11. cin >> p->data.c;
  12. p->next = NULL;
  13. r->next = p;//尾插
  14. r = p;
  15. }
  16. return true;
  17. }

project 2:(同理,不再赘述)

  1. Status 尾插法(LinkList& A, int n)
  2. {
  3. auto L = new Lnode;
  4. L->next = NULL;
  5. LinkList r = L;
  6. for (auto i = 1; i <= n; i++)
  7. {
  8. auto p = new Lnode;
  9. cin >> p->data.a;
  10. cin >> p->data.b;
  11. cin >> p->data.c;
  12. p->next = NULL;
  13. r->next = p;//尾插
  14. r = p;
  15. }
  16. A = L;
  17. return true;
  18. }

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号