数据结构(U2)||线性表复习整理

167 阅读5分钟

1、线性表复习整理

统考、非统考甚至是工作面试中,数据结构都是非常重要的。在2022年整理的考研大纲中对线性表的命题在于算法题,但实际上大题中需要具有优秀的时间、空间复杂度才能够拿到高分。接下来针对大纲对线性表的要求对线性表进行复习吧。下图是自行整理的2022年考研大纲对线性表的要求(23年考研会实时更换图片)。

image-20220811171828811.png

1、线性表的基本概念

线性表结合王道书中的概括整理如下图:

image-20220811172832832.png

tip.在形参中,如果该线性表需要内存空间的变动——比如添加、删除、创建销毁,需要添加(引用&)来访问该内存。

引用本质也就是指针常量。它是一个对象的别名,既然初始化了所指向的地址,那么它一定不为空,而且地址不可变。(即只能做指针内的变值不能修改其地址指向)
引用对比与指针,更加安全,因为在使用指针的时候,往往都需要先判断是否为NULL,而引用可以直接用。

拓展:另外,在STL编程还是Java面对的集合等编程类,可能会出现数组、列表和集合相混淆,下图稍微描述三者的区别

image-20220811173511351.png

列表根据概念就是线性表;数组是一种线性表的推广,并且在顺序表的实现上会使用到它;集合可以认为是一个衣柜,将衣服、裤子袜子全都放进一团进去。所以是一种“无序”的数据结构。

2、线性表的实现

2.1 顺序表的基本实现

image-20220811180452398.png

具体实现可以移步到我的另一篇博客:数据结构U2-顺序表的实现 - 掘金 (juejin.cn)

2.2 链式存储的基本实现

该部分主要通过leetcode编程练习整理,接下来结合代码注释来分别解释单链表和双链表(注意到编程网站中并没有按值查找。实际上也可以在leetcode结合复习即可)。可结合具体网址练习。网址如下:链表 - LeetBook

image-20220811175448488.png 具体博客可以移步到我另一篇链表的基本介绍:链式存储的基本实现 - 掘金 (juejin.cn)

3、线性表的应用

这里会接着leetbook的经典问题进行讨论。链表 - LeetBook - 力扣(LeetCode)

首先顺序表会放在后面讲栈、队列和数组会具体讨论应用,这里主要讲链表的应用。

3.1 环形链表

给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true 。 否则,返回 false 。
​
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
​

image-20220812200910703.png

代码思路如下

bool hasCycle(ListNode *head) {
        if(head==nullptr) return false;
        /*
        这道题使用双链表进行解决。其解决思路在于设置一个快指针和慢指针。如果在两个指针移动时发现相等便可判断
        */
        ListNode *cur1 = head;//cur1表示每次只移动一次
        ListNode *cur2 = head;//cur2表示每次移动两次
        while(cur1!=nullptr&&cur2!=nullptr){
            //while包括判断是否会走出"环形链表"
            if(!cur2->next) return false;
            if(!cur2->next->next) return false;
            cur1 = cur1->next;
            cur2 = cur2->next->next;
            if(cur1==cur2){
                return true;
            }
        }
        return false;
    }

image-20220812200947095.png

3.2 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
​
示例 2:
输入:head = [1,2]
输出:[2,1]

image-20220812193308800.png

在具体方法的实现基础上,其实在做这道题应该也能够稍微想通其中的道理。下面是我写的代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //1->2->3->4->5
        //5->4->3->2->1
        ListNode* cur1 = head;//辅助指针
        ListNode* res = new ListNode();//构建后链表
        //初始化一个空链表
        while (cur1) {
            ListNode* node = new ListNode(cur1->val);
            //此操作跟前面在头节点后添加节点类似
            if (res->next) {
                //如果非空
                node->next = res->next;
                res->next = node;
            }
            else {
                //第一次插入时,只需要将头节点连接第一个数据即可
                res->next = node;
            }
            cur1 = cur1->next;
        }
        return res->next;
    }
};

很简单的实现,其实总结起来就是设计一个新链表,然后在实现首部添加节点的基础上稍微讨论情况。最后返回的时候应该跳过头结点(即返回res->next)

这里有一段小插曲就是,我执行完成后发现用时击败用户很低,然后疯狂提交(doge)后,执行时间的分数被我刷高,但是由于使用了双指针和链式结构花费内存开销,所以内存分数基本变化不大。从下图1变成下图2:

image-20220812193526033.png

image-20220812193652613.png

3.3 总结

其实链表还有很多很有趣的应用,不过结合leetcode等编程网站的学习会远比在这里稍微阅读浏览来的更方便。比如回文链表、反转链表2.0等等,有兴趣的话可以额外编程探索噢。 后续也会在复习其他专业课之余再回顾数据结构算法的更新,并且积极查阅资料提高自己的理解。如有需要改正的地方还请多多指教。