| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> 记录数据结构的学习003 -> 正文阅读 |
|
[数据结构与算法]记录数据结构的学习003 |
(此文为王道数据结构学习笔记,只供个人后续复习使用,若有错误,还望指出我改正,谢谢) 回顾上一篇文章学习内容: 单链表的定义。 带头结点与不带头结点的区别。 初始化带头结点的单链表。 头/插插法建立单链表。 按序查找,按值查找,按序插入。 ?指定结点的后插操作: 先找到指定结点,再将next区域与新结点进行交接即可。
时间复杂度为O(1);? 指定结点的后插操作: 1.若有头指针,且链表元素均可一一访问,则一个一个扫描,直到扫描到指定结点p的前一个,再执行插入操作即可。时间复杂度为O(n); 2.若无头指针,或链表前面区域情况未知,则找到p结点后,将p的next指向新结点,同时将p结点数据与新结点数据对调,即可完成了后插入后对调,相当于完成了前插操作。时间复杂度为O(1);
按照位序删除: 先执行按照位序查找工作,找到想要删除的结点 i 后,将?i - 1 结点的next覆盖为i的next,此时已完成交接工作,然后将 i 结点释放内存即可完成删除,如若需要返回被删除值,可以return第 i 结点的data。
指定结点的删除: 同样的,如若不知道指定结点前序结点的信息,同样需要替换操作。找到p的后一个结点p+1,将p+1的值覆盖掉p的值,同时将p+1的next变为p的next,再删除p+1结点。将想要删除的结点变成下一个结点,再将下一个结点删除,这样实则完成了删除指定结点的工作。 要注意到的是如果要删除最后一个结点,即其没有后续结点的这种情况,将会出现问题,此时不得不想办法找到前一个结点修改其next为NULL。直接free(p)的话,前一个结点的next将指向不正确。
双链表 单链表由于只有一个next指针,只能沿着一个方向,有局限性,故引入双链表,加一个prior指针。其他内容与单链表大致相同。双链表可双向遍历。 初始化双链表(带头结点)
双链表的插入 在p结点后插入s结点,需要将s结点的prior指向p,将s结点的next指向p原本next指向的结点,然后将p的next指向s。要注意语句顺序。
此为后插操作,但由于双链表的特性,想要执行前插操作,只需找到该结点的前一个结点进行后插操作即可。 双链表的删除 与单链表的删除相类似,不过需要注意的是,要修改被删除的后续结点prior指针。同样的,删除最后一个结点时会有错误。
如若想删除整个链表,只需从头结点开始一个一个删除即可。
循环链表 循环单链表:只需要将尾结点的next指向头结点即可。这样可以通过向下遍历而达到找到前序结点的功能。判断是否为空即看头结点的next是否指向自己。 循环双链表:头结点prior指向尾结点,尾结点next指向头结点,形成闭环。判断是否为空即看头结点的prior和next是否都指向自己。? 静态链表 用数组的方式实现链表。存储在连续内存空间中,单个结点为:数据+游标 两者组成,游标可以指向在这个内存空间的相对位置,即前一个结点和后一个结点物理位置可以不相接,但前一个结点可以通过游标指向后一个结点的位置。定义一个静态链表的结点的结构体。
以上两个方式等价 查找:从头结点出发挨个遍历 插入位序为 i 的结点思路: 1.找到一个空的结点。存入数据元素 2.从头结点出发找到位序为 i-1 的结点 3.修改新结点的next 4.修改i-1号结点的next 顺序表和链表的对比 逻辑结构: 逻辑上都是线性表 存储结构: 顺序表:随机存取 存储密度高 分配空间不方便 改变容量不方便 链表:离散空间分配方便,改变容量方便 不可随机存取 存储密度低 基本操作:? 创建: 顺序表:需要大片空间,浪费空间,不好扩容;静态数组分配容量不可改,动态数组分配需要移动大量元素。 ?链表:需要头指针(及头结点),方便扩展;静态数组和动态数组都能改容量,并且不需要移动大量元素。 销毁: 顺序表:将length修改为0。 链表:依次删除各个结点。 静态分配等待系统自动回收,动态分配手动free。 插入/删除: 顺序表:插入删除都需要移动后续大量元素,时间复杂度为O(n),主要开销为移动元素。 链表:插入删除都只需要修改指针,时间复杂度为O(n),主要开销为查找目标元素。(效率更高) 查找; 顺序表:按位查找:O(1);按值查找:O(n),若有序,可用折半查找等方法让其变成O(log2n)。 链表:按位查找:O(n);按值查找:O(n)。都需要一个一个遍历。 表长难以估计,经常需要增加删除元素——链表 表长可以估计,查询搜索操作较多——顺序表 练习: ?思路:初步思路:首先遍历一遍链表,计算结点个数,设为n,再重新遍历一遍,倒数第k个结点,即n-k+1个结点即可。改进思路:定义两个指针变量p和q,初始时都在头结点,先让p移动到k号结点后,再让p与q同步进行向后移动,当p移动到最后一个结点时,q刚好比p少移动k个结点,即为倒数第k个结点。
总结:两个指针能同步移动的方法通常会时间开销更少,多往这方面考虑。 ?思路:初步思路:设定两个指针变量p、q,初始位于str1和str2处,p指针变量每向后移动一格,与q比对,不同则继续遍历,遍历完成以后,仍未找到,q指针向后移动一格,p重新从头开始遍历。设单词长为a,b,后缀长为k,此方法需要的时间开销为【(a-k)*b+b-k+1】,过于繁琐。优化思路:首先各自遍历一遍,计算各自总长度,较长的为M,较短的为m,再让p从长的那个链表开始移动到第M-m+1个结点,然后pq同步移动,直到出现指向相同。此法时间开销为【2(M+m)?】? ,相对较低,比较合适。
? ? 总结:与上一题类似,两个指针能同步移动的方法通常会时间开销更少,多往这方面考虑。 ? ? ? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 思路: 初始思路:从第一个数字开始,选取为备选数字,开始向后遍历,每到下一个数字,判断是否为该数字或该数字的相反数,如果是,执行一次删除结点操作,如果不是继续向后遍历,直到遍历完成。然后选取第二个数字作为备选数字,重复执行上一个操作。直到选取的备选数字无后继或者无下一个备选数字为止。完成操作。该方法需要遍历很多次,不是特别方便。 优化思路 :用一个辅助数组 q[] 来作为某数字及其绝对值是否出现的表示,将数组大小设置为n+1,,初始全部元素设为0,用 q[|data|]来标记data以及data相反数是否出现过。开始遍历链表,每遍历一个,读取其data,并观察数组中 q[|data|] 的值:如此时?q[|data|] = 0 ,视为该数字或其相反数第一次出现,将之改为0;如此时?q[|data|]??= 1 ,视为已出现过,将遍历到的结点删除。遍历结束后,将 q[] 释放。此方法只需要一次遍历即可,时间复杂度为O(m)(m为整数数量),但需要引入一个辅助数组,空间复杂度为O(n+1)(n为链表中最大整数,题目已给出)。?
? ?总结:用空间换时间,此思路值得借鉴反思。 栈和队列 栈的基本概念: 逻辑结构:是一种只允许在一段进行插入或删除操作的线性表 空栈:没有元素? ?栈顶:允许操作的一段? ?栈底:不允许操作的一端 进栈顺序:1 2 3 4 5,出栈顺序:5 4 3 2 1 后进先出 LIFO (Last In First Out) 常用操作: InitStack(&S); 初始化栈 DestoryStack(&S); 销毁栈 Push(&S, x); 进栈 Pop(&S, &x); 出栈 GetTop(&S, &x); 读栈顶元素 StackEmpty(S); 判断栈是否为空 顺序栈的定义
如果要判断栈是否为空,判断栈顶指针是否为-1即可
进栈操作: 先判断栈是否已满,不满则可进栈,并让top加1
出栈操作: 先判断栈是否已空,不空则可出栈,并让top减1
读栈顶元素操作: 如同出栈操作,只是不改变top指针
共享栈: 同一片空间一端是一个栈的栈底部,另一端是另一个栈栈底,共同往中间入栈,当top1+1=top2时,存满 链栈 特殊的但链表,只是只能在一段进行删除/插入,操作与单链表类似。 队列: 只允许在一端进行插入,另一端进行删除的线性表 队头删除,队尾删除,空队列 FIFO (First In First Out) 队列的顺序实现: 引入队头指针front 队尾指针rear,当front =rear 时,为空队列。 队列的各个操作:
前文可知,为了不让队头指针和队尾指针指向同一个位置而导致误以为队空,队满实际上会空出一个位置出来,是浪费空间的行为。为了解决这一问题,可以引入size变量,每入队size+1,每出队size-1,如果当front=rear的时候,只需判断size=0还是MaxSize,为0则代表队空,为MaxSize则代表队满。同样的,可以引入tag变量,每当操作为入队时,令tag=1,出队时,令tag=0,如果当front=rear的时候,只需判断tag=0还1,为0则代表队空,为1则代表队满。
想你!!!! 想你!!!! 想你!!!! 想你!!!! 想你!!!! |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 19:27:29- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |