数据结构与算法-要点整理

知识导图:

请添加图片描述

一、数据结构

    包含:线性表(数组、队列、链表、栈)、散列表、树(二叉树、多路查找树)、图

1.线性表

    数据之间就是“一对一“的逻辑关系。
    线性表存储数据的实现方案有两种,分别是顺序存储结构链式存储结构
    包含:数组、队列、链表、栈。

1.1 数组:

    连续内存存储。简单,此处不多介绍。

1.2 队列:

可以通过数组+前后索引实现,也可以通过链表+前后指针实现。

queue:
1)通过数组+前后索引实现

#include <iostream>
#include <stdexcept>template <typename T, int capacity>
class Queue {
private:T arr[capacity];int front;  // 队头索引int rear;   // 队尾索引int size;   // 当前队列中的元素数量public:Queue() : front(0), rear(0), size(0) {}// 判断队列是否为空bool isEmpty() const {return size == 0;}// 判断队列是否已满bool isFull() const {return size == capacity;}// 入队操作void enqueue(const T& value) {if (isFull()) {throw std::overflow_error("Queue is full");}arr[rear] = value;rear = (rear + 1) % capacity;  // 循环更新队尾索引++size;}// 出队操作T dequeue() {if (isEmpty()) {throw std::underflow_error("Queue is empty");}T value = arr[front];front = (front + 1) % capacity;  // 循环更新队头索引--size;return value;}// 获取队头元素T getFront() const {if (isEmpty()) {throw std::underflow_error("Queue is empty");}return arr[front];}// 获取队列中的元素数量int getSize() const {return size;}
};int main() {Queue<int, 5> queue;try {// 入队操作queue.enqueue(1);queue.enqueue(2);queue.enqueue(3);// 输出队头元素std::cout << "Front element: " << queue.getFront() << std::endl;// 出队操作std::cout << "Dequeued element: " << queue.dequeue() << std::endl;// 再次输出队头元素std::cout << "Front element after dequeue: " << queue.getFront() << std::endl;// 输出队列中的元素数量std::cout << "Queue size: " << queue.getSize() << std::endl;} catch (const std::exception& e) {std::cerr << "Exception: " << e.what() << std::endl;}return 0;
}

2)通过链表+前后指针实现

#include <iostream>
#include <stdexcept>// 定义链表节点结构体
template <typename T>
struct Node {T data;Node<T>* next;Node(const T& value) : data(value), next(nullptr) {}
};// 定义队列类
template <typename T>
class Queue {
private:Node<T>* front;  // 队头指针Node<T>* rear;   // 队尾指针int size;        // 当前队列中的元素数量public:// 构造函数Queue() : front(nullptr), rear(nullptr), size(0) {}// 析构函数~Queue() {while (!isEmpty()) {dequeue();}}// 判断队列是否为空bool isEmpty() const {return size == 0;}// 获取队列中的元素数量int getSize() const {return size;}// 入队操作void enqueue(const T& value) {Node<T>* newNode = new Node<T>(value);if (isEmpty()) {front = rear = newNode;} else {rear->next = newNode;rear = newNode;}++size;}// 出队操作T dequeue() {if (isEmpty()) {throw std::underflow_error("Queue is empty");}T value = front->data;Node<T>* temp = front;front = front->next;if (front == nullptr) {rear = nullptr;}delete temp;--size;return value;}// 获取队头元素T getFront() const {if (isEmpty()) {throw std::underflow_error("Queue is empty");}return front->data;}
};int main() {Queue<int> queue;try {// 入队操作queue.enqueue(1);queue.enqueue(2);queue.enqueue(3);// 输出队头元素std::cout << "Front element: " << queue.getFront() << std::endl;// 出队操作std::cout << "Dequeued element: " << queue.dequeue() << std::endl;// 再次输出队头元素std::cout << "Front element after dequeue: " << queue.getFront() << std::endl;// 输出队列中的元素数量std::cout << "Queue size: " << queue.getSize() << std::endl;} catch (const std::exception& e) {std::cerr << "Exception: " << e.what() << std::endl;}return 0;
}

双端队列Deque:
    允许你从队列的两端进行元素的插入和删除操作,既可以在头部进行操作,也可以在尾部进行操作。

1)通过数组+前后索引实现

#include <iostream>
#include <stdexcept>template <typename T, int capacity>
class ArrayDeque {
private:T arr[capacity];int front;int rear;int size;public:ArrayDeque() : front(0), rear(0), size(0) {}// 判断队列是否为空bool isEmpty() const {return size == 0;}// 判断队列是否已满bool isFull() const {return size == capacity;}// 在队头插入元素void insertFront(const T& value) {if (isFull()) {throw std::overflow_error("Deque is full");}front = (front - 1 + capacity) % capacity;arr[front] = value;++size;}// 在队尾插入元素void insertRear(const T& value) {if (isFull()) {throw std::overflow_error("Deque is full");}arr[rear] = value;rear = (rear + 1) % capacity;++size;}// 从队头删除元素T deleteFront() {if (isEmpty()) {throw std::underflow_error("Deque is empty");}T value = arr[front];front = (front + 1) % capacity;--size;return value;}// 从队尾删除元素T deleteRear() {if (isEmpty()) {throw std::underflow_error("Deque is empty");}rear = (rear - 1 + capacity) % capacity;T value = arr[rear];--size;return value;}// 获取队头元素T getFront() const {if (isEmpty()) {throw std::underflow_error("Deque is empty");}return arr[front];}// 获取队尾元素T getRear() const {if (isEmpty()) {throw std::underflow_error("Deque is empty");}return arr[(rear - 1 + capacity) % capacity];}// 获取队列中的元素数量int getSize() const {return size;}
};int main() {ArrayDeque<int, 5> deque;try {deque.insertFront(1);deque.insertRear(2);std::cout << "Front element: " << deque.getFront() << std::endl;std::cout << "Rear element: " << deque.getRear() << std::endl;deque.deleteFront();std::cout << "Front element after deleteFront: " << deque.getFront() << std::endl;deque.deleteRear();std::cout << "Is deque empty after deletions? " << (deque.isEmpty() ? "Yes" : "No") << std::endl;} catch (const std::exception& e) {std::cerr << "Exception: " << e.what() << std::endl;}return 0;
}

2)通过链表+前后指针实现

#include <iostream>
#include <stdexcept>// 定义链表节点结构体
template <typename T>
struct Node {T data;Node<T>* prev;Node<T>* next;Node(const T& value) : data(value), prev(nullptr), next(nullptr) {}
};template <typename T>
class LinkedDeque {
private:Node<T>* front;Node<T>* rear;int size;public:LinkedDeque() : front(nullptr), rear(nullptr), size(0) {}~LinkedDeque() {while (!isEmpty()) {deleteFront();}}// 判断队列是否为空bool isEmpty() const {return size == 0;}// 在队头插入元素void insertFront(const T& value) {Node<T>* newNode = new Node<T>(value);if (isEmpty()) {front = rear = newNode;} else {newNode->next = front;front->prev = newNode;front = newNode;}++size;}// 在队尾插入元素void insertRear(const T& value) {Node<T>* newNode = new Node<T>(value);if (isEmpty()) {front = rear = newNode;} else {newNode->prev = rear;rear->next = newNode;rear = newNode;}++size;}// 从队头删除元素T deleteFront() {if (isEmpty()) {throw std::underflow_error("Deque is empty");}T value = front->data;Node<T>* temp = front;front = front->next;if (front == nullptr) {rear = nullptr;} else {front->prev = nullptr;}delete temp;--size;return value;}// 从队尾删除元素T deleteRear() {if (isEmpty()) {throw std::underflow_error("Deque is empty");}T value = rear->data;Node<T>* temp = rear;rear = rear->prev;if (rear == nullptr) {front = nullptr;} else {rear->next = nullptr;}delete temp;--size;return value;}// 获取队头元素T getFront() const {if (isEmpty()) {throw std::underflow_error("Deque is empty");}return front->data;}// 获取队尾元素T getRear() const {if (isEmpty()) {throw std::underflow_error("Deque is empty");}return rear->data;}// 获取队列中的元素数量int getSize() const {return size;}
};int main() {LinkedDeque<int> deque;try {deque.insertFront(1);deque.insertRear(2);std::cout << "Front element: " << deque.getFront() << std::endl;std::cout << "Rear element: " << deque.getRear() << std::endl;deque.deleteFront();std::cout << "Front element after deleteFront: " << deque.getFront() << std::endl;deque.deleteRear();std::cout << "Is deque empty after deletions? " << (deque.isEmpty() ? "Yes" : "No") << std::endl;} catch (const std::exception& e) {std::cerr << "Exception: " << e.what() << std::endl;}return 0;
}
1.3 链表:

    和顺序表不同,使用链表存储数据,不强制要求数据在内存中集中存储,各个元素可以分散存储在内存中。链表存储数据间逻辑关系的实现方案是:为每一个元素配置一个指针,每个元素的指针都指向自己的直接后继元素。

单向链表:
在这里插入图片描述

#include <iostream>struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};class LinkedList {
private:ListNode* head;public:LinkedList() : head(nullptr) {}void insertAtHead(int val) {ListNode* newNode = new ListNode(val);newNode->next = head;head = newNode;}void insertAtTail(int val) {ListNode* newNode = new ListNode(val);if (head == nullptr) {head = newNode;return;}ListNode* curr = head;while (curr->next!= nullptr) {curr = curr->next;}curr->next = newNode;}void deleteAtHead() {if (head == nullptr) {std::cout << "链表为空,无法删除" << std::endl;return;}ListNode* temp = head;head = head->next;delete temp;}void deleteAtTail() {if (head == nullptr) {std::cout << "链表为空,无法删除" << std::endl;return;}if (head->next == nullptr) {delete head;head = nullptr;return;}ListNode* curr = head;while (curr->next->next!= nullptr) {curr = curr->next;}delete curr->next;curr->next = nullptr;}void printList() {ListNode* curr = head;while (curr!= nullptr) {std::cout << curr->val << " ";curr = curr->next;}std::cout << std::endl;}// 查找元素是否存在bool search(int val) {ListNode* curr = head;while (curr!= nullptr) {if (curr->val == val) {return true;}curr = curr->next;}return false;}
};int main() {LinkedList list;list.insertAtHead(3);list.insertAtHead(2);list.insertAtHead(1);std::cout << "插入头部后的链表: ";list.printList();list.insertAtTail(4);list.insertAtTail(5);std::cout << "插入尾部后的链表: ";list.printList();list.deleteAtHead();std::cout << "删除头部节点后的链表: ";list.printList();list.deleteAtTail();std::cout << "删除尾部节点后的链表: ";list.printList();if (list.search(3)) {std::cout << "元素 3 存在于链表中" << std::endl;} else {std::cout << "元素 3 不存在于链表中" << std::endl;}return 0;
}

双向链表:

    “双向”指的是各节点之间的逻辑关系是双向的,头指针通常只设置一个。
在这里插入图片描述

#include <iostream>// 定义双向链表节点结构体
struct ListNode {int val;ListNode* prev;ListNode* next;ListNode(int x) : val(x), prev(nullptr), next(nullptr) {}
};// 双向链表类
class DoublyLinkedList {
private:ListNode* head;ListNode* tail;public:DoublyLinkedList() : head(nullptr), tail(nullptr) {}// 插入节点到链表头部void insertAtHead(int val) {ListNode* newNode = new ListNode(val);if (head == nullptr) {head = newNode;tail = newNode;} else {newNode->next = head;head->prev = newNode;head = newNode;}}// 插入节点到链表尾部void insertAtTail(int val) {ListNode* newNode = new ListNode(val);if (tail == nullptr) {head = newNode;tail = newNode;} else {newNode->prev = tail;tail->next = newNode;tail = newNode;}}// 删除头部节点void deleteAtHead() {if (head == nullptr) {std::cout << "链表为空,无法删除" << std::endl;return;}ListNode* temp = head;if (head == tail) {head = nullptr;tail = nullptr;} else {head = head->next;head->prev = nullptr;}delete temp;}// 删除尾部节点void deleteAtTail() {if (tail == nullptr) {std::cout << "链表为空,无法删除" << std::endl;return;}ListNode* temp = tail;if (head == tail) {head = nullptr;tail = nullptr;} else {tail = tail->prev;tail->next = nullptr;}delete temp;}// 打印链表元素(从头到尾)void printList() {ListNode* curr = head;while (curr!= nullptr) {std::cout << curr->val << " ";curr = curr->next;}std::cout << std::endl;}// 打印链表元素(从尾到头)void printListReverse() {ListNode* curr = tail;while (curr!= nullptr) {std::cout << curr->val << " ";curr = curr->prev;}std::cout << std::endl;}
};int main() {DoublyLinkedList list;list.insertAtHead(3);list.insertAtHead(2);list.insertAtHead(1);std::cout << "插入头部后的链表: ";list.printList();list.insertAtTail(4);list.insertAtTail(5);std::cout << "插入尾部后的链表: ";list.printList();list.deleteAtHead();std::cout << "删除头部节点后的链表: ";list.printList();list.deleteAtTail();std::cout << "删除尾部节点后的链表: ";list.printList();std::cout << "从尾到头打印链表: ";list.printListReverse();return 0;
}

单向循环链表与双向循环链表:
    单链表通过首尾连接可以构成单向循环链表:
在这里插入图片描述
    双向链表也可以进行首尾连接,构成双向循环链表:
在这里插入图片描述

静态链表:
    用静态链表存储数据,数据全部存储在数组中(和顺序表一样),但存储位置是随机的,数据之间"一对一"的逻辑关系通过一个整形变量(称为"游标",和指针功能类似)维持(和链表类似)。
在静态链表中,数组的每个元素代表一个链表节点,每个节点通常包含两部分:

  1. 数据域:存储节点的数据。
  2. 游标域(或指针域):存储下一个节点在数组中的索引,而不是像动态链表那样存储一个物理地址。

在这里插入图片描述

1.4 栈

    栈是一种后进先出的数据结构。

#include <iostream>
#include <vector>class ArrayStack {
private:std::vector<int> data;  // 存储元素的数组
public:// 入栈操作void push(int value) {
//使用 data.push_back(value) 将元素添加到 data 的末尾,实现入栈操作。data.push_back(value);}// 出栈操作int pop() {if (isEmpty()) {throw s

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/893880.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二级C语言题解:统计奇偶个数以及和与差、拼接字符串中数字并计算差值、提取字符串数组中单词尾部字母

目录 一、程序填空 --- 统计奇偶个数以及和与差 题目 分析 二、程序修改 --- 拼接字符串中数字并计算差值 题目 分析 三、程序设计题 --- 提取字符串数组中单词尾部字母 题目 分析 前言&#xff1a; 本节讲解C语言二级的统计奇偶个数以及和与差、拼接字符串中数字并计…

【四川乡镇界面】图层shp格式arcgis数据乡镇名称和编码2020年wgs84无偏移内容测评

本文将详细解析标题和描述中提到的IT知识点&#xff0c;主要涉及GIS&#xff08;Geographic Information System&#xff0c;地理信息系统&#xff09;技术&#xff0c;以及与之相关的文件格式和坐标系统。 我们要了解的是"shp"格式&#xff0c;这是一种广泛用于存储…

关于MySQL InnoDB存储引擎的一些认识

文章目录 一、存储引擎1.MySQL中执行一条SQL语句的过程是怎样的&#xff1f;1.1 MySQL的存储引擎有哪些&#xff1f;1.2 MyIsam和InnoDB有什么区别&#xff1f; 2.MySQL表的结构是什么&#xff1f;2.1 行结构是什么样呢&#xff1f;2.1.1 NULL列表&#xff1f;2.1.2 char和varc…

2018年全国硕士研究生入学统一考试管理类专业学位联考英语(二)试题-解析版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;目前中南大学MBA在读&#xff0c;也考取过HCIE Cloud Computing、CCIE Security、PMP、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &…

高可用集群故障之join

本文记录了在部署高可用的k8s集群时&#xff0c;遇到的一个故障及其解决方法。 集群环境 描述&#xff1a;三主三从&#xff0c;eth0为外网网卡&#xff0c;eth1为内网网卡&#xff0c;内网互通。 需求&#xff1a;eth0只负责访问外网&#xff0c;eth1作为集群间的通信。 主…

FPGA实现任意角度视频旋转(完结)视频任意角度旋转实现

本文主要介绍如何基于FPGA实现视频的任意角度旋转&#xff0c;关于视频180度实时旋转、90/270度视频无裁剪旋转&#xff0c;请见本专栏前面的文章&#xff0c;旋转效果示意图如下&#xff1a; 为了实时对比旋转效果&#xff0c;采用分屏显示进行处理&#xff0c;左边代表旋转…

RocketMQ原理—5.高可用+高并发+高性能架构

大纲 1.RocketMQ的整体架构与运行流程 2.基于NameServer管理Broker集群的架构 3.Broker集群的主从复制架构 4.基于Topic和Queue实现的数据分片架构 5.Broker基于Pull模式的主从复制原理 6.Broker层面到底如何做到数据0丢失 7.数据0丢失与写入高并发的取舍 8.RocketMQ读…

一文简单回顾Java中的String、StringBuilder、StringBuffer

简单说下String、StringBuilder、StringBuffer的区别 String、StringBuffer、StringBuilder在Java中都是用于处理字符串的&#xff0c;它们之间的区别是String是不可变的&#xff0c;平常开发用的最多&#xff0c;当遇到大量字符串连接的时候&#xff0c;就用StringBuilder&am…

Go:基于Go实现一个压测工具

文章目录 写在前面整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理 客户端模块Http客户端处理Grpc客户端处理Websocket客户端处理 连接处理模块GrpcHttp 统计数据模块统计原理实现过程 写在前面 本篇主要是基于Go来实现一个压测的工具&#xff0c;关于压测的内…

Redis --- 分布式锁的使用

我们在上篇博客高并发处理 --- 超卖问题一人一单解决方案讲述了两种锁解决业务的使用方法&#xff0c;但是这样不能让锁跨JVM也就是跨进程去使用&#xff0c;只能适用在单体项目中如下图&#xff1a; 为了解决这种场景&#xff0c;我们就需要用一个锁监视器对全部集群进行监视…

小盒科技携手体验家,优化智能教育服务体验,打造在线教育新高度

北京小盒科技有限公司&#xff08;简称“小盒科技”&#xff0c;由“作业盒子”更名而来&#xff09;是一家专注于教育科技的公司&#xff0c;致力于利用人工智能、大数据等先进技术&#xff0c;为中小学教育提供创新的解决方案和产品。 近日&#xff0c;「小盒科技」携手体…

PhotoShop中JSX编辑器安装

1.使用ExtendScript Tookit CC编辑 1.安装 打开CEP Resource链接&#xff1a; CEP-Resources/ExtendScript-Toolkit at master Adobe-CEP/CEP-Resources (github.com) 将文件clone到本地或者下载到本地 点击AdobeExtendScriptToolKit_4_Ls22.exe安装&#xff0c;根据弹出的…

ESP32-CAM实验集(WebServer)

WebServer 效果图 已连接 web端 platformio.ini ; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library stor…

强化学习数学原理(三)——值迭代

一、值迭代过程 上面是贝尔曼最优公式&#xff0c;之前我们说过&#xff0c;f(v)v&#xff0c;贝尔曼公式是满足contraction mapping theorem的&#xff0c;能够求解除它最优的策略和最优的state value&#xff0c;我们需要通过一个最优v*&#xff0c;这个v*来计算状态pi*&…

03:Heap代码的分析

Heap代码的分析 1、内存对齐2、Heap_1.c文件代码分析3、Heap_2.c文件代码分析4、Heap_4.c文件代码分析5、Heap_5.c文件代码分析 1、内存对齐 内存对齐的作用是为了CPU更快的读取数据。对齐存储与不对齐存储的情况如下&#xff1a; 计算机读取内存中的数据时是一组一组的读取的…

three.js+WebGL踩坑经验合集(5.2):THREE.Mesh和THREE.Line2在镜像处理上的区别

本文紧接上篇&#xff1a; (5.1):THREE.Line2又一坑&#xff1a;镜像后不见了 本文将解答上篇提到的3个问题&#xff0c;首先回答第二个问题&#xff0c;如何获取全局的缩放值。 scaleWorld这个玩意儿呢&#xff0c;three.js官方就没提供了。应该说&#xff0c;一般的渲染引…

jQuery的系统性总结

前言 jQuery是一个快速、小型且功能丰富的 JavaScript 库&#xff08;实际上就是一堆JS代码&#xff09;。其目的在于&#xff1a;write less do more。 优点&#xff1a; 写得少做得多&#xff1b;兼容性&#xff1b;体积小&#xff1b;链式编程&#xff1b;隐式迭代、插件丰…

【背包问题】完全背包

目录 前言&#xff1a; 一&#xff0c;完全背包问题 问题描述&#xff1a; 模板题目&#xff1a; 题目解析&#xff1a; 代码&#xff1a; 空间优化&#xff1a; 二&#xff0c;典例 1&#xff0c;零钱兑换 题目解析&#xff1a; 算法分析&#xff1a; 代码&#xff…

【Python实现机器遗忘算法】复现2023年TNNLS期刊算法UNSIR

【Python实现机器遗忘算法】复现2023年TNNLS期刊算法UNSIR 1 算法原理 Tarun A K, Chundawat V S, Mandal M, et al. Fast yet effective machine unlearning[J]. IEEE Transactions on Neural Networks and Learning Systems, 2023. 本文提出了一种名为 UNSIR&#xff08;Un…

知识管理平台在企业信息化建设中的应用价值与未来展望

内容概要 在当今信息化时代&#xff0c;企业面临着海量信息的挑战&#xff0c;知识管理平台因此应运而生&#xff0c;成为企业提升管理效率和决策能力的关键工具。知识管理平台不仅仅是一个信息存储的工具&#xff0c;它集成了信息共享、协作与创新、决策支持等多项功能。通过…