线性数据结构(数组/链表/栈/队列)优缺点、特点及其应用场景

一.数组、字符串

为什么把字符串和数组放在一起呢?因为很多时候要对字符串给个字符进行某种操作,遍历字符串并不方便,常把字符串转成字符数组。

1.1优点

  1. 构建一个数组非常简单
  2. 可以在O(1)的时间内根据数组的下标查询某个元素

1.2缺点

  1. 构建时必须分配一段连续的空间
  2. 查询某个元素是否存在时需要遍历整个数组,耗费O(n)的时间,n为元素的个数
  3. 删除和增添某个元素时同样需要耗费O(n)的时间

1.3应用场景

只需要进行访问数据操作时使用数组

1.4例题

力扣P242
思路:本题只是对字符串进行访问,不需要特殊操作。首先设置一个长度为26的judge数组记录每个字符串26个字母出现的次数;然后遍历两个字符串,第一个字符串中某字母出现一次就在judge对应下标加一,第二个字符串中某字母出现一次就在judge对应下标减一;最后判断judge数组中是否都为0。

class Solution {
public:
    bool isAnagram(string s, string t) {
        int judge[26]={0};
        for(auto c:s)
            judge[c-'a']++;
        for(auto c:t)
            judge[c-'a']--;
        for(auto a:judge){
            if(0!=a)
                return false;
        }     
        return true;
    }
};

二.链表

链表就是为了避免数组的一大缺陷——开辟数组需要一片连续的空间,但也牺牲了数组的一些优点。

  • 单链表:链表中为一个结点实际上是一个单独的对象,而所有对象都通过每个有元素中的引用字段链接在一起。
  • 双链表:与单链表类似,但是每个结点中都含有两个引用字段。

2.1优点

  • 灵活分配内存空间
  • 能在O(1)时间内删除或者添加元素,前提:该元素前一个元素已知(单、双),该元素后一个元素已知(双)

2.2缺点

  • 查询元素需要O(n)时间

2.3应用场景

数据元素个数不确定,需要经常添加和删除元素,不需要频繁查询数据时用链表

2.4例题

2.4.1解题技巧
  • 利用快慢指针(链表翻转、访问链表倒数第k个元素或链表中间位置元素、判断是否有环)
  • 构建一个虚假的头节点(需要返回一个新链表、合并两个有序链表、将链表的奇偶数按原定顺序分离为前后两部分)
2.4.2题目

力扣24
思路:分为递归和迭代两种思想

  • 递归解法:将问题抽象为三个结点(代指1,2,3,其中3把其他结点抽象为一个结点)的链表,先将1接3,然后2接1,最后返回2。不断递归,节点为空或只剩一个结点作为递归出口。
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head==NULL||head->next==NULL)
            return head;
        ListNode *pre=head;
        ListNode *rear=head->next;
        pre->next=swapPairs(rear->next);
        rear->next=pre;
        return rear;
    }
};
  • 迭代解法:思路与递归解法雷同

三.栈

3.1特点

先进后出,可以用单链表实现

3.2应用场景

当问题只关心最近一次的操作,而且需要在O(1)的时间内查找到更前的一次操作时使用栈

3.3例题

例一:力扣20
思路:这是一道经典的栈应用问题,因为一个表达式的括号匹配就是由内向外的。首先用字典map去存储左右括号的映射关系,然后遍历字符串遇见左括号压栈、右括号弹栈同时判断是否匹配,不匹配返回false,如果右括号全部被匹配,还要判断栈是否为空,空返回true,否则返回false。

class Solution {
public:
    bool isValid(string s) {
        map<char, char> map;
        map[')'] = '(';
        map[']'] = '[';
        map['}'] = '{';
        stack<char> st;
        for(char c : s){
            if(map.count(c)){
                if(!st.empty() && map[c] == st.top())
                    st.pop();
                else 
                    return false;
            }
            else
                st.push(c);
        }
        if(st.empty())
            return true;
        return false;
    }
};

例二:力扣739
思路:遍历温度,如果比栈顶元素温度低就压栈;反之弹栈,直至栈顶元素比所遍历到的温度高或栈空停止弹栈,并压栈

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        stack<int>si;
        int n = T.size();
        vector<int>res(n,0);
        for (auto i = 0;i<n; ++i) {           
            while(!si.empty()&&T[i]>T[si.top()]){
                res[si.top()]=i-si.top();
                si.pop();                   
            }
            si.push(i);                                      
        }
        return res;
    }
};

四.队列

4.1普通队列

4.1.1特点

先进先出,可以用双链表实现

4.1.2应用场景

按一定顺序处理数据,而且数据在不断变化的时候(广度优先搜索)

4.2双端队列

4.2.1特点

头尾两端都可以在O(1)的时间内进行数据查看、添加和删除操作,也可以用双链表实现

4.2.2应用场景

实现一个长度动态变化的窗口或连续区间

4.2.3例题

力扣239
思路:题目所说的“窗口”,就是一直在变化的连续区间,如果遍历区间找到最大元素,时间复杂度是O(k*n),所以我们可以想到如果查询最大值可以在O(1)时间内完成,时间复杂度是不是就降下来了呢,我们想象一个线性结构,去存窗口元素,当遍历时该线性结构元素超过窗口大小,需要在前端删除元素;同时在还需要比较线性结构尾部的元素,尾部元素较大,就在尾部插入;尾部元素较小,就删除尾部元素,直至尾部元素较大或该线性结构为空。综上满足首尾可删除可插入的线性结构就是双端队列。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        deque<int>di;
        int n = nums.size();
        vector<int>res;
        for (int i = 0; i<n ; i++) {
            if (!di.empty() && i - k + 1 > di.front())
                di.pop_front();
            while (!di.empty() && nums[i] > nums[di.back()])
                di.pop_back();
            di.push_back(i);
            if (i >= k - 1)
                res.push_back(nums[di.front()]);
        }
        return res;
    }
};
  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 数组 - 特点:由相同类型的元素组成,通过下标访问元素,支持随机访问。 - 优点:内存连续,访问速度快。 - 缺点:插入和删除操作需要移动大量元素,大小固定。 - 常见应用场景:存储静态数据,如存储学生的成绩、存储图像像素等。 2. 链表 - 特点:由节点组成,每个节点包括数据和指向下一个节点的指针,支持动态扩容。 - 优点:插入和删除操作快,大小可以动态变化。 - 缺点:不支持随机访问,每个节点需要额外的指针空间。 - 常见应用场景:实现队列数据结构,实现LRU缓存淘汰算法,实现高精度计算等。 3. - 特点:先进后出,只能在顶进行操作。 - 优点:操作简单,存储顺序明确。 - 缺点:大小固定,不支持随机访问。 - 常见应用场景:实现函数调用,实现表达式求值,实现DFS深度优先搜索等。 4. 队列 - 特点:先进先出,只能在队头和队尾进行操作。 - 优点:操作简单,存储顺序明确。 - 缺点:大小固定,不支持随机访问。 - 常见应用场景:实现BFS广度优先搜索,实现消息队列,实现缓存等。 5. 树 - 特点:由节点和边组成,每个节点包括数据和指向子节点的指针,支持递归遍历。 - 优点:快速查找、插入和删除操作,支持动态扩容。 - 缺点:不支持随机访问,节点需要额外的指针空间。 - 常见应用场景:实现二叉查找树、平衡二叉树、堆、前缀树等。 6. 图 - 特点:由节点和边组成,每个节点包括数据和指向相邻节点的指针,支持复杂的拓扑结构。 - 优点:表达能力强,可以解决很多实际问题。 - 缺点:复杂度高,遍历和搜索操作耗时长。 - 常见应用场景:实现社交网络、地图导航、网络拓扑等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值