数据结构——队列和链表

前言

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


文章目录

前言

一、队列

1.1 STL普通队列——queue

1.2 STL双端队列——deque

1.3 循环队列 

二、链表

2.1  ListNode及其基本操作

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

总结


一、队列

        什么是队列呢?顾名思义,队列这种数据结构其实跟日常生活中排队的情景类似,都是采用先进先出的策略,这很好理解,因为在日常生活中的排队场景下,第一个排队的一定是第一个通过的。 那么我们如何使用队列这种数据结构呢?C++在STL库中就提供了一个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及其基本操作

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

初始化: 

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

 单链表的构建过程:

struct ListNode
{
    double value;
    ListNode *next;
};
ListNode* head = nullptr;//空节点
head = new ListNode;
//给第一个节点赋值
head->value = 1;
//第一个创建节点的指针指向链表的末位置  
head->next = nullptr;

//创建第二个节点
ListNode* sPtr = new ListNode;
sPtr->value = 2;
//第二个创建节点的指针next指向链表的末位置  
sPtr->next = nullptr; 
//第一个创建节点的next指针第二个
head->next = sPtr; 

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

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

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

题目

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

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

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

代码示例: 

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/

//暴力解法——T:O(M,N)/S:O(1)
#include 
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
		//首先解决边界条件
		if(pHead1 == NULL)
			return pHead2;
		if(pHead2 == NULL)
			return pHead1;
		
		//初始化一个空节点
		ListNode* head = new ListNode(0);
		ListNode* cur = head;

		while (pHead1 && pHead2) {
			if(pHead1->val <= pHead2->val){
				cur->next = pHead1;
				pHead1 = pHead1->next;
			}else {
				cur->next = pHead2;
				pHead2 = pHead2->next;
			}
			//指针后移
			cur = cur->next;
		}
		if(pHead1)
            cur->next = pHead1;
        else
            cur->next = pHead2;
        //返回值去掉表头
        return head->next;
    }
};

总结

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

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

你可能感兴趣的:(C++与数据结构,链表,数据结构)