• 数据结构与算法基础(王卓)(5)


    目录

    取第i个元素

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

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

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

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

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


    位置:PPT第二章:127


    默认前置:

    1. #include
    2. using namespace std;
    3. #include//存放exit
    4. #include//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
    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-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. }

  • 相关阅读:
    SQL 专项笔记
    交通 | 神奇动物在哪里?Operations Research经典文章
    数学建模:智能优化算法及其python实现
    最新面试必问:怎么写一个又好又快的日志库
    多线程&并发篇---第七篇
    MySQL的介绍
    Netty学习知识点总结
    商品 秒杀
    TechSmith Camtasia Studio 23.3.2.49471 Crack
    【ARM CoreLink 系列 1 -- SoC 片上互联介绍】
  • 原文地址:https://blog.csdn.net/Zz_zzzzzzz__/article/details/128166500