当前位置:   article > 正文

数据结构——队列和链表_链表和队列

链表和队列

前言

        还有一个多月就要打蓝桥杯了,荔枝最近开始学习一些基本的数据结构和算法,接下来在数据结构这个专栏里可以看到荔枝学习的脚步哦哈哈哈哈。这篇文章主要是荔枝在队列和链表的学习笔记,希望对大家有帮助哈哈哈


文章目录

前言

一、队列

1.1 STL普通队列——queue

1.2 STL双端队列——deque

1.3 循环队列 

二、链表

2.1  ListNode及其基本操作

2.2 样题分析——力扣21.合并两个有序链表

总结


一、队列

        什么是队列呢?顾名思义,队列这种数据结构其实跟日常生活中排队的情景类似,都是采用先进先出的策略,这很好理解,因为在日常生活中的排队场景下,第一个排队的一定是第一个通过的。 那么我们如何使用队列这种数据结构呢?C++在STL库中就提供了一个queue容器适配器,使用前首先导入头文件<queue>。

1.1 STL普通队列——queue

获取队首

front():返回队首元素

获取队尾

back():返回队尾元素

入队与出队

push():队尾插入元素

pop():弹出队首元素

检查是否为空

empty():检查队列中元素为空

返回元素个数

size():返回队列中元素的个数

1.2 STL双端队列——deque

STL在deque容器中提供了有关双端队列的一众成员函数给我们使用。与queue相比,同样有front()和back()这两个获取队首和队尾的成员函数;同样的也有empty()和size()这两种成员函数。

有关修改操作的成员函数:

push_back():在队尾插入元素

pop_back():弹出队尾元素

push_front():在队首插入元素

push_back(): 弹出队首元素

insert():在指定位置前插入元素(传入迭代器和元素)

erase():删除指定位置的元素(传入迭代器)

1.3 循环队列 

        不管是顺序队列还是顺序链表,都会存在内存空间无法再次利用的情况,也就是假溢出的情况。这时候有一个循环的数据结构无疑会解决这一问题——随着元素的入队与出队,整个队列的存储其实即相当于在队列圈中环绕进行,但是整个队列还是一种线性表的形式,只是被我们当作环状表来实现。

判断队列已满的条件:

队列的rear指针(rear+1)%队列长度==top,其中rear是尾指针,top是头指针。


二、链表

        在前面我们其实比较熟悉的就是数组这一种数据结构,链表与数组相比都可以自由管理数据存取和删除,但其优点在于数据的增添或删除的速度上,这是因为链表并不是一种线性存储的结构,而是利用指针达到一种指向的关系从而形成数据的存储形式。

2.1  ListNode及其基本操作

  1. struct ListNode {
  2. int val; //当前结点的值
  3. ListNode *next; //指向下一个结点的指针
  4. ListNode(int x) : val(x), next(NULL) {} //初始化当前结点值为x,指针为空
  5. };

初始化: 

  1. //初始化一个空节点,head就是一个结构体指针,初始赋值为0
  2. ListNode* head = new ListNode(0);
  3. //cur和head都是一个结构体指针,指向同一个new关键字开辟的内存空间
  4. ListNode* cur = head;

 单链表的构建过程:

  1. struct ListNode
  2. {
  3. double value;
  4. ListNode *next;
  5. };
  6. ListNode* head = nullptr;//空节点
  7. head = new ListNode;
  8. //给第一个节点赋值
  9. head->value = 1;
  10. //第一个创建节点的指针指向链表的末位置
  11. head->next = nullptr;
  12. //创建第二个节点
  13. ListNode* sPtr = new ListNode;
  14. sPtr->value = 2;
  15. //第二个创建节点的指针next指向链表的末位置
  16. sPtr->next = nullptr;
  17. //第一个创建节点的next指针第二个
  18. head->next = sPtr;

C++中new关键字的作用:

        一般来说我们在创建一个变量的时候会默认是以栈的形式来储存的,但使用了new关键字就可以实现数据是以堆的形式来储存。使用new关键字来创建一个对象时,会获得一块内存空间(动态内存分配)、同时调用构造函数并放回正确的指针。使用了new关键字就可以不再使用定义结构体变量在将地址赋值给指针了。需要注意的是:new出来的是一段空间的首地址。所以一般需要用指针来存放这段地址。而对于结构体指针ListNode*,可以通过new来直接开辟内存空间并获得地址,使用->来获取属性或指针,当然也可以直接使用结构体的调用方法来实现功能。

2.2 样题分析——力扣21.合并两个有序链表

题目

输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。

数据范围: 0<=n<=1000,  -1000<=节点值<=1000
要求:空间复杂度 O(1),时间复杂度 O(n)

合并两个链表并按照升序的顺序进行重新排序并合并,这个过程需要利用链表的基本结构,这道题可以使用递归,也可以直接暴力出来,但是对比两种方法的复杂度其实我觉得直接暴力更好哈哈哈。 

代码示例: 

  1. /*
  2. struct ListNode {
  3. int val;
  4. struct ListNode *next;
  5. ListNode(int x) :
  6. val(x), next(NULL) {
  7. }
  8. };*/
  9. //暴力解法——T:O(M,N)/S:O(1)
  10. #include <cstddef>
  11. class Solution {
  12. public:
  13. ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
  14. //首先解决边界条件
  15. if(pHead1 == NULL)
  16. return pHead2;
  17. if(pHead2 == NULL)
  18. return pHead1;
  19. //初始化一个空节点
  20. ListNode* head = new ListNode(0);
  21. ListNode* cur = head;
  22. while (pHead1 && pHead2) {
  23. if(pHead1->val <= pHead2->val){
  24. cur->next = pHead1;
  25. pHead1 = pHead1->next;
  26. }else {
  27. cur->next = pHead2;
  28. pHead2 = pHead2->next;
  29. }
  30. //指针后移
  31. cur = cur->next;
  32. }
  33. if(pHead1)
  34. cur->next = pHead1;
  35. else
  36. cur->next = pHead2;
  37. //返回值去掉表头
  38. return head->next;
  39. }
  40. };

总结

        在这篇文章中,荔枝主要做了一下队列和链表的基础知识笔记,荔枝也知道后期肯定是要通过刷题来掌握的这些数据结构的,总之任重而道远!今天还是有点收获的——至少弄懂了结构体指针和队列、链表的基础部分。最后还要特别鸣谢博主IC 1396给我答疑解惑哈哈哈哈哈,果然我还是太菜了~~~成熟太难了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/928378
推荐阅读
相关标签