读书笔记-《数据结构与算法》-摘要1[数据结构]

文章目录

  • [数据结构]
    • 1. String - 字符串
    • 2. Linked List - 链表
      • 2.1 链表的基本操作
      • 2.1.1 反转链表
        • 单向链表
        • 双向链表
      • 2.1.2 删除链表中的某个节点
      • 2.1.3 链表指针的鲁棒性
      • 2.1.4 快慢指针
    • 3. Binary Tree - 二叉树
      • 3.1 树的遍历
      • 3.2 Binary Search Tree - 二叉查找树
    • 4. Queue - 队列
      • 4.1 Queue - 队列
      • 4.2 Priority Queue - 优先队列
      • 4.3 Deque - 双端队列
    • 5. Heap - 堆
    • 堆的基本操作
    • 6. Stack - 栈
    • 7. Set
    • 8. Map - 哈希表
    • 9. Graph - 图

[数据结构]

1. String - 字符串

开发常用,没啥可说的,注意的是字符串拼接时,可能会用到 StringBuffer 与 StringBuilder,前者保证线程安全,后者不是,但单线程下效率高一些,一般使用 StringBuilder。

2. Linked List - 链表

链表是线性表的一种。线性表是最基本、最简单、也是最常用的一种数据结构。

线性表有两种存储方式,一种是顺序存储结构(例如数组),另一种是链式存储结构。

链式存储结构就是两个相邻的元素在内存中可能不是相邻的,每一个元素都有一个指针域,指针域一般是存储着到下一个元素的指针。这种存储方式的优点是插入和删除的时间复杂度为 O(1),缺点是访问的时间复杂度最坏为 O(n)。

链表就是链式存储的线性表。根据指针域的不同,链表分为单向链表、双向链表、循环链表等等。

2.1 链表的基本操作

2.1.1 反转链表

单向链表

链表的基本形式是:1 -> 2 -> 3 -> null,反转需要变为 3 -> 2 -> 1 -> null。这里要注意:

  • 访问某个节点 curt.next 时,要检验 curt 是否为 null。
  • 要把反转后的最后一个节点(即反转前的第一个节点)指向 null。
class ListNode {int val;ListNode next;ListNode(int val) {this.val = val;}
}public ListNode reverse(ListNode head) {ListNode prev = null;while (head != null) {ListNode next = head.next;head.next = prev;prev = head;head = next;}return prev;
}
双向链表

和单向链表的区别在于:双向链表的反转核心在于nextprev域的交换,还需要注意的是当前节点和上一个节点的递推。

class DListNode {int val;DListNode prev, next;DListNode(int val) {this.val = val;this.prev = this.next = null;}
}public DListNode reverse(DListNode head) {DListNode curr = null;while (head != null) {curr = head;head = curr.next;curr.next = curr.prev;curr.prev = head;}return curr;
}

2.1.2 删除链表中的某个节点

删除链表中的某个节点一定需要知道这个点的前继节点,所以需要一直有指针指向前继节点。还有一种删除是伪删除,是指复制一个和要删除节点值一样的节点,然后删除,这样就不必知道其真正的前继节点了。

然后只需要把 prev -> next = prev -> next -> next 即可。

2.1.3 链表指针的鲁棒性

综合上面讨论的两种基本操作,链表操作时的鲁棒性问题主要包含两个情况:

  • 当访问链表中某个节点 curt.next 时,一定要先判断 curt 是否为 null。
  • 全部操作结束后,判断是否有环;若有环,则置其中一端为 null

2.1.4 快慢指针

所谓快慢指针中的快慢指的是指针向前移动的步长,每次移动的步长较大即为快,步长较小即为慢,常用的快慢指针一般是在单链表中让快指针每次向前移动2,慢指针则每次向前移动1。快慢两个指针都从链表头开始遍历,于是快指针到达链表末尾的时候慢指针刚好到达中间位置,于是可以得到中间元素的值。快慢指针在链表相关问题中主要有两个应用:

  • 快速找出未知长度单链表的中间节点 设置两个指针 *fast*slow 都指向单链表的头节点,其中*fast的移动速度是*slow的2倍,当*fast指向末尾节点的时候,slow正好就在中间了。
  • 判断单链表是否有环 利用快慢指针的原理,同样设置两个指针 *fast*slow 都指向单链表的头节点,其中 *fast的移动速度是*slow的2倍。如果 *fast = NULL,说明该单链表 以 NULL结尾,不是循环链表;如果 *fast = *slow,则快指针追上慢指针,说明该链表是循环链表。

3. Binary Tree - 二叉树

二叉树是每个节点最多有两个子树的树结构,子树有左右之分,二叉树常被用于实现二叉查找树二叉堆

public class TreeNode {public int val;public TreeNode left, right;public TreeNode(int val) {this.val = val;this.left = null;this.right = null;}
}

3.1 树的遍历

从二叉树的根节点出发,节点的遍历分为三个主要步骤:对当前节点进行操作(称为“访问”节点,或者根节点)、遍历左边子节点、遍历右边子节点。访问节点顺序的不同也就形成了不同的遍历方式。需要注意的是树的遍历通常使用递归的方法进行理解和实现,在访问元素时也需要使用递归的思想去理解。实际实现中对于前序和中序遍历可尝试使用递归实现。

按照访问根元素(当前元素)的前后顺序,遍历方式可划分为如下几种:

  • 深度优先:先访问子节点,再访问父节点,最后访问第二个子节点。根据根节点相对于左右子节点的访问先后顺序又可细分为以下三种方式。
    1. 前序(pre-order):先根后左再右
    2. 中序(in-order):先左后根再右
    3. 后序(post-order):先左后右再根
  • 广度优先:先访问根节点,沿着树的宽度遍历子节点,直到所有节点均被访问为止。

3.2 Binary Search Tree - 二叉查找树

一颗二叉查找树(BST)是一颗二叉树,其中每个节点都含有一个可进行比较的键及相应的值,且每个节点的键都大于等于左子树中的任意节点的键,而小于右子树中的任意节点的键

使用中序遍历可得到有序数组,这是二叉查找树的又一个重要特征。

二叉查找树使用的每个节点含有两个链接,它是将链表插入的灵活性和有序数组查找的高效性结合起来的高效符号表实现。

4. Queue - 队列

4.1 Queue - 队列

Queue 是一个 FIFO(先进先出)的数据结构,并发中使用较多,可以安全地将对象从一个任务传给另一个任务。

Queue 在 Java 中是 Interface, 一种实现是 LinkedList 向上转型为 Queue, Queue 通常不能存储 null 元素,否则与 poll() 等方法的返回值混淆。

Queue<Integer> q = new LinkedList<Integer>();
int qLen = q.size(); // get queue length
0:0Throws exceptionReturns special value
Insertadd(e)offer(e)
Removeremove()poll()
Examineelement()peek()

优先考虑右侧方法,右侧元素不存在时返回 null. 判断非空时使用isEmpty()方法,继承自 Collection.

import java.util.LinkedList;
import java.util.Queue;public class QueueMethods {public static void main(String[] args) {Queue<Integer> q = new LinkedList<>();q.offer(1); // 增加元素q.offer(2); // 增加元素q.add(3); // 增加元素q.add(4); // 增加元素int size = q.size(); // 获取长度System.out.println("原始 q:" + q);/** remove 移除 Queue 的头部元素,并返回移除的元素* 移除时若队列为空,则报错:NoSuchElementException* 这也是它与 pull 方法的区别*/Integer remove = q.remove();System.out.println("remove 后 获取的元素 remove:" + remove);System.out.println("remove 后 q:" + q);Integer poll = q.poll();System.out.println("poll 后 获取的元素 poll:" + poll);System.out.println("poll 后 q:" + q);/** element 获取 Queue 的头部元素,并返回移除的元素* 移除时若队列为空,则报错:NoSuchElementException* 这也是它与 peek 方法的区别*/Integer element = q.element();System.out.println("element 后 获取的元素 element:" + element);System.out.println("element 后 q:" + q);Integer peek = q.peek();System.out.println("peek 后 获取的元素 peek:" + peek);System.out.println("peek 后 q:" + q);// 判断队列是否为空boolean empty = q.isEmpty();System.out.println("q 是否为空:" + empty);}
}

输出:

原始 q:[1, 2, 3, 4]
remove 后 获取的元素 remove:1
remove 后 q:[2, 3, 4]
poll 后 获取的元素 poll:2
poll 后 q:[3, 4]
element 后 获取的元素 element:3
element 后 q:[3, 4]
peek 后 获取的元素 peek:3
peek 后 q:[3, 4]
q 是否为空:false

在这里插入图片描述

(图网,侵删)

4.2 Priority Queue - 优先队列

应用程序常常需要处理带有优先级的业务,优先级最高的业务首先得到服务。因此优先队列这种数据结构应运而生。优先队列中的每个元素都有各自的优先级,优先级最高的元素最先得到服务;优先级相同的元素按照其在优先队列中的顺序得到服务。

优先队列可以使用数组或链表实现,从时间和空间复杂度来说,往往用二叉堆来实现。

Java 中提供PriorityQueue类,该类是 Interface Queue 的另外一种实现,和LinkedList的区别主要在于排序行为而不是性能,基于 priority heap 实现,非synchronized,故多线程下应使用PriorityBlockingQueue. 默认为自然序(小根堆),需要其他排序方式可自行实现Comparator接口,选用合适的构造器初始化。使用迭代器遍历时不保证有序,有序访问时需要使用Arrays.sort(pq.toArray()).

4.3 Deque - 双端队列

双端队列(deque,全名double-ended queue)可以让你在任何一端添加或者移除元素,因此它是一种具有队列和栈性质的数据结构。

Java 在1.6之后提供了 Deque 接口,既可使用ArrayDeque(数组)来实现,也可以使用LinkedList(链表)来实现。前者是一个数组外加首尾索引,后者是双向链表。

Deque<Integer> deque = new ArrayDeque<Integer>();
First Element (Head)Last Element (Tail)
Throws exceptionSpecial valueThrows exceptionSpecial value
InsertaddFirst(e)offerFirst(e)addLast(e)offerLast(e)
RemoveremoveFirst()pollFirst()removeLast()pollLast()
ExaminegetFirst()peekFirst()getLast()peekLast()

其中offerLast和 Queue 中的offer功能相同,都是从尾部插入。

5. Heap - 堆

一般情况下,堆通常指的是二叉堆二叉堆是一个近似完全二叉树的数据结构,即披着二叉树羊皮的数组,故使用数组来实现较为便利。子结点的键值或索引总是小于(或者大于)它的父节点,且每个节点的左右子树又是一个二叉堆(大根堆或者小根堆)。根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常被用作实现优先队列。

堆的基本操作

以大根堆为例,堆的常用操作如下。

  1. 最大堆调整(Max_Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
  2. 创建最大堆(Build_Max_Heap):将堆所有数据重新排序
  3. 堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算

其中步骤1是给步骤2和3用的。

—PS:这本书里有很多这种动图,简直就是神器

6. Stack - 栈

栈是一种 LIFO(Last In First Out) 的数据结构,常用方法有添加元素,取栈顶元素,弹出栈顶元素,判断栈是否为空。

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Stack;public class StackMethods {public static void main(String[] args) {/** JDK doc 中建议使用Deque代替Stack实现栈,* 因为Stack继承自Vector,需要synchronized,性能略低。*/Stack<Integer> stack = new Stack<>();Deque<Integer> s = new ArrayDeque<>();// E push(E item) - 向栈顶添加元素s.push(1);s.push(2);s.push(3);System.out.println("原始栈:" + s);System.out.println("原始栈,长度:" + s.size());// E peek() - 取栈顶元素,不移除Integer peek = s.peek();System.out.println("获取的栈顶元素:" + peek);System.out.println("peek 栈,长度:" + s.size());// E pop() - 移除栈顶元素并返回该元素Integer pop = s.pop();System.out.println("获取的栈顶元素:" + pop);System.out.println("pop 栈,长度:" + s.size());// 判断栈是否为空,若使用 Stack 类构造则为 empty()System.out.println("Deque 创建栈是否为空:" + s.isEmpty());System.out.println("Stack 创建栈是否为空:" + stack.empty());}
}

输出:

原始栈:[3, 2, 1]
原始栈,长度:3
获取的栈顶元素:3
peek 栈,长度:3
获取的栈顶元素:3
pop 栈,长度:2
Deque 创建栈是否为空:false
Stack 创建栈是否为空:true

7. Set

Set 是一种用于保存不重复元素的数据结构。常被用作测试归属性,故其查找的性能十分重要。

Set 与 Collection 具有安全一样的接口,通常有HashSet, TreeSetLinkedHashSet三种实现。HashSet基于散列函数实现,无序,查询速度最快;TreeSet基于红-黑树实现,有序。

8. Map - 哈希表

Map 是一种关联数组的数据结构,也常被称为字典或键值对。

Java 的实现中 Map 是一种将对象与对象相关联的设计。常用的实现有HashMapTreeMap, HashMap被用来快速访问,而TreeMap则保证『键』始终有序。Map 可以返回键的 Set, 值的 Collection, 键值对的 Set.

Map<String, Integer> map = new HashMap<String, Integer>();
map.put("bill", 98);
map.put("ryan", 99);
boolean exist = map.containsKey("ryan"); // check key exists in map
int point = map.get("bill"); // get value by key
int point = map.remove("bill") // remove by key, return value
Set<String> set = map.keySet();
// iterate Map
for (Map.Entry<String, Integer> entry : map.entrySet()) {String key = entry.getKey();int value = entry.getValue();// do some thing
}

9. Graph - 图

图的表示通常使用邻接矩阵和邻接表,前者易实现但是对于稀疏矩阵会浪费较多空间,后者使用链表的方式存储信息但是对于图搜索时间复杂度较高。

/* Java Definition */
int[][] g = new int[V][V];

在这里插入图片描述
(图网,侵删)

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

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

相关文章

人工智能-优化算法之学习率调度器

学习率调度器 到目前为止&#xff0c;我们主要关注如何更新权重向量的优化算法&#xff0c;而不是它们的更新速率。 然而&#xff0c;调整学习率通常与实际算法同样重要&#xff0c;有如下几方面需要考虑&#xff1a; 首先&#xff0c;学习率的大小很重要。如果它太大&#xf…

acwing算法基础之动态规划--数位统计DP、状态压缩DP、树形DP和记忆化搜索

目录 1 基础知识2 模板3 工程化 1 基础知识 暂无。。。 2 模板 暂无。。。 3 工程化 题目1&#xff1a;求a~b中数字0、数字1、…、数字9出现的次数。 思路&#xff1a;先计算1~a中每位数字出现的次数&#xff0c;然后计算1~b-1中每位数字出现的次数&#xff0c;两个相减即…

7、单片机与W25Q128(FLASH)的通讯(SPI)实验(STM32F407)

SPI接口简介 SPI 是英语Serial Peripheral interface的缩写&#xff0c;顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。 SPI&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并且在芯片的管脚上只占用四根…

uniapp uni-popup组件在微信小程序中滚动穿透问题

起因 在微信小程序中使用uni-popup组件时&#xff0c;出现滚动穿透&#xff0c;并且uni-popup内部内容不会滚动问题。 解决 滚动穿透 查阅官方文档&#xff0c;发现滚动穿透是由于平台差异性造成的&#xff0c;具体解决可以参照文档禁止滚动穿透 <template><page-…

python 实现链表

链表基础知识 链表是在物理内存中不连续&#xff0c;数据通过链表中的指针来链接到下一个元素。 链表由一系列节点组成&#xff0c;节点在运行时动态生成&#xff0c;节点一般包括两个部分&#xff1a;存储数据的数据域&#xff0c;存储下一个节点的指针域 链表的常用操作&a…

熬夜会秃头——beta冲刺Day4

这个作业属于哪个课程2301-计算机学院-软件工程社区-CSDN社区云这个作业要求在哪里团队作业—beta冲刺事后诸葛亮-CSDN社区这个作业的目标记录beta冲刺Day4团队名称熬夜会秃头团队置顶集合随笔链接熬夜会秃头——Beta冲刺置顶随笔-CSDN社区 一、团队成员会议总结 1、成员工作进…

C语言:写一个函数,输入一个十六进制数,输出相应的十进制数

分析&#xff1a; 当用户运行该程序时&#xff0c;程序会提示用户输入一个十六进制数。用户需要在命令行中输入一个有效的十六进制数&#xff0c;例如&#xff1a;"1A3F"。 接下来&#xff0c;程序调用了名为 xbed 的函数&#xff0c;并将用户输入的十六进制数作…

【翻译】直流电动机的控制

直流电&#xff08;DC&#xff09;电机由于其转矩易于控制&#xff0c;速度控制范围广&#xff0c;已广泛应用于可调速驱动或可变转矩控制中。然而&#xff0c;直流电机有一个主要的缺点&#xff0c;即它们需要机械装置&#xff0c;如换向器和刷子来连续旋转。这些机械部件需要…

《opencv实用探索·六》简单理解图像膨胀

1、图像膨胀原理简单理解 膨胀是形态学最基本的操作&#xff0c;都是针对白色部分&#xff08;高亮部分&#xff09;而言的。膨胀就是使图像中高亮部分扩张&#xff0c;效果图拥有比原图更大的高亮区域。 2、图像膨胀的作用 注意一般情况下图像膨胀和腐蚀是联合使用的。 &…

前端面试高频考点—事件循环Event loop

目录 事件循环 执行步骤 概念讲解 主线程 微任务(micro task) 宏任务(macro task) Event Loop经典例题 这段代码的执行结果是什么&#xff1f; 正确答案&#xff1a; 具体流程&#xff1a; 事件循环 主线程从"任务队列"中读取执行事件&#xff0c;这个过程…

利用 NRF24L01 无线收发模块实现传感器数据的无线传输

NRF24L01 是一款常用的无线收发模块&#xff0c;适用于远程控制和数据传输应用。本文将介绍如何利用 NRF24L01 模块实现传感器数据的无线传输&#xff0c;包括硬件的连接和配置&#xff0c;以及相应的代码示例。 一、引言 NRF24L01 是一款基于 2.4GHz 射频通信的低功耗无线收发…

RHCE学习笔记(RHEL8) - RH294

Chapter Ⅰ 介绍Ansible ansible ansible是一款开源自动化平台 ansible围绕一种无代理架构构建,在控制节点上安装ansible,且客户端不需要任何特殊的代理软件;ansible使用SSH等标准协议连接受管主机,并在受管主机上运行代码或命令来确保他们处于ansible指定的状态 Ansible帮…