数据结构及其简单实现

  1. 先进后出
  2. 栈顶操作(栈顶进,栈顶出)
class Strock {constructor() {this.data = [] // 可以是对象this.count = 0}push(item) {// 实现有三种// 1. this.data.push(item); // 2. this.data[this.data.length] = item; this.count++// 3this.data[this.count] = item// 入栈后,count 自增this.count++}pop() {// 出栈的前提是栈中存在元素,应先行检测if (this.isEmpty()) {console.log('栈为空!')return}// 移除栈顶数据// 方式1:数组方法 pop 移除// return this.data.pop()// 方式2:计数方式const temp = this.data[this.count - 1]delete this.data[--this.count]return temp}// isEmpty() 检测栈是否为空isEmpty() {return this.count === 0}top() {if (this.isEmpty()) {console.log('栈为空!')return}return this.data[this.count - 1]}size() {return this.count}cleatr() {this.count = 0this.data = []}
}
含有min函数的栈
  1. 辅助栈实现
// 在存储数据的栈外,再新建一个栈,用于存储最小值
class MinStack {constructor () {// stackA 用于存储数据this.stackA = []this.countA = 0// stackB 用于将数据降序存储(栈顶值为最小值)this.stackB = []this.countB = 0}// 入栈push (item) {// stackA 正常入栈this.stackA[this.countA++] = item// stackB 如果没有数据,直接入栈// 如果 item 的值 <= stackB 的最小值,入栈if (this.countB === 0 || item <= this.min()) {this.stackB[this.countB++] = item}}// 最小值函数min () {return this.stackB[this.countB - 1]}// 获取栈顶值top () {return this.stackA[this.countA - 1]}// 出栈pop () {// 先进行 stackB 的检测// 如果 stackA 的栈顶值 === stackB 的栈顶值,stackB 出栈if (this.top() === this.min()) {delete this.stackB[--this.countB]}// stackA 出栈delete this.stackA[--this.countA]}
}
const m = new MinStack()
  1. Math.min方法实现
class MinStack {constructor () {this.stack = []}// 入栈push (item) {this.stack.push(item)}// 查看栈顶值top () {return this.stack[this.stack.length - 1]}// 实现最小值功能min () {return Math.min.apply(null, this.stack)}// 出栈方法pop () {return this.stack.pop()}
}
const m = new MinStack()
每日温度

力扣题目 739. 每日温度

function s(arr) {let data = [0] // data是一个逆序栈 (变-> 小) 存储入栈的下标let count = 1let returnArr = Array(arr.length).fill(0)for (let index = 1; index < arr.length; index++) {const element = arr[index];while (count && element > arr[data[count - 1]]) {let i = data.pop()count--returnArr[i] = index - i}data.push(index)count++}return returnArr
}
console.log(s([73, 74, 75, 71, 69, 72, 76, 73])) // [1, 1, 4, 2, 1, 1, 0, 0]

队列

  1. 先进先出
  2. 队首出,队尾入
class Queue {constructor () {// 用于存储队列数据this.queue = []this.count = 0}// 入队方法enQueue (item) {this.queue[this.count++] = item}// 出队方法deQueue () {if (this.isEmpty()) {return}// 删除 queue 的第一个元素// delete this.queue[0]// 利用 shift() 移除数组的第一个元素this.count--return this.queue.shift()}isEmpty () {return this.count === 0}// 获取队首元素值top () {if (this.isEmpty()) {return}return this.queue[0]}size () {return this.count}clear () {// this.queue = []this.length = 0this.count = 0}
}
const q = new Queue()

基于对象

class Queue {constructor () {this.queue = {}this.count = 0// 用于记录队首的键this.head = 0}// 入队方法enQueue (item) {this.queue[this.count++] = item}// 出队方法deQueue () {if (this.isEmpty()) {return}const headData = this.queue[this.head]delete this.queue[this.head]this.head++return headData}length () {return this.count - this.head}top () {return this.queue(this.head)}isEmpty () {return this.length() === 0}clear () {this.queue = {}this.count = 0this.head = 0}
}
const q = new Queue()
双端队列
class Deque {constructor () {this.queue = {}this.count = 0this.head = 0}// 队首添加addFront (item) {this.queue[--this.head] = item}// 队尾添加addBack (item) {this.queue[this.count++] = item}// 队首删除removeFront () {if (this.isEmpty()) {return}const headData = this.queue[this.head]delete this.queue[this.head++]return headData}// 队尾删除removeBack () {if (this.isEmpty()) {return}const backData = this.queue[this.count - 1]delete this.queue[--this.count]// this.count-- 与 上一步 this.count - 1 合并return backData}// 获取队首值frontTop () {if (this.isEmpty()) {return}return this.queue[this.head]}// 获取队尾值backTop () {if (this.isEmpty()) {return}return this.queue[this.count - 1]}isEmpty () {return this.size() === 0}size () {return this.count - this.head}
}
const deq = new Deque()

队列的最大值

var MaxQueue = function() {// 存储队列数据this.queue = {}// 双端队列维护最大值(每个阶段的最大值)this.deque = {}// 准备队列相关的数据this.countQ = this.countD = this.headQ = this.headD = 0
};/** 队尾入队* @param {number} value* @return {void}*/
MaxQueue.prototype.push_back = function(value) {// 数据在 queue 入队this.queue[this.countQ++] = value// 检测是否可以将数据添加到双端队列//   - 队列不能为空//   - value 大于队尾值while (!this.isEmptyDeque() && value > this.deque[this.countD - 1]) {// 删除当前队尾值delete this.deque[--this.countD]}// 将 value 入队this.deque[this.countD++] = value
};/** 队首出队* @return {number}*/
MaxQueue.prototype.pop_front = function() {if (this.isEmptyQueue()) {return - 1}// 给 queue 出队,并返回const frontData = this.queue[this.headQ]// 比较 deque 与 queue 的队首值,如果相同,deque 出队,否则 deque 不操作if (frontData  === this.deque[this.headD]) {delete this.deque[this.headD++]}delete this.queue[this.headQ++]return frontData
};/** 获取队列最大值* @return {number}*/
MaxQueue.prototype.max_value = function() {if (this.isEmptyDeque()) {return -1}// 返回 deque 队首值即可return this.deque[this.headD]
};/** 检测队列 deque 是否为空* */
MaxQueue.prototype.isEmptyDeque = function () {return !(this.countD - this.headD)
};/** 检测队列 Queue 是否为空* */
MaxQueue.prototype.isEmptyQueue = function () {return !(this.countQ - this.headQ)
};
滑动窗口问题

力扣题目 239. 滑动窗口最大值

/*** @param {number[]} nums 传入数组* @param {number} k 滑动窗口宽度* @return {number[]} */
var maxSlidingWindow = function(nums, k) {if (k <= 1) {return nums}const result = []const deque = []// 1 将窗口第一个位置的数据添加到 deque 中,保持递减deque.push(nums[0])let i = 1for (; i < k; i++) {// - 存在数据// - 当前数据大于队尾值//   - 出队,再重复比较while (deque.length && nums[i] > deque[deque.length - 1]) {deque.pop()}deque.push(nums[i])}// 将第一个位置的最大值添加到 resultresult.push(deque[0])// 2 遍历后续的数据const len = nums.lengthfor (; i < len; i++) {// 同上进行比较while (deque.length && nums[i] > deque[deque.length - 1]) {deque.pop()}deque.push(nums[i])// 检测当前最大值是否位于窗口外if (deque[0] === nums[i - k]) {deque.shift()}// 添加最大值到 resultresult.push(deque[0])}return result
};

链表

操作上和数组很像,为什么不用数组?

  • 数组添加、移除会导致后续元素位移性能开销大
  • 获取、修改元素时,数组效率高
  • 添加、删除元素时,链表效率高
链表实现
  • 节点类: value、next
  • 链表类
    – addAtTail 尾部添加节点
    – addHead 头部添加节点
    – addAtIndex 指定位置添加节点
    – get 获取节点
    – removeAtIndex 删除指定节点
    – size 节点个数
// 节点类
class LinkedNode {constructor (value) {this.value = value// 用于存储下一个节点的引用this.next = null}
}// 链表类
class LinkedList {constructor () {this.count = 0this.head = null}// 添加节点 (尾)addAtTail (value) {// 创建新节点const node = new LinkedNode(value)// 检测链表是否存在数据if (this.count === 0) {this.head = node} else {// 找到链表尾部节点,将最后一个节点的 next 设置为 nodelet cur = this.headwhile (cur.next != null) {cur = cur.next}cur.next = node}this.count++}// 添加节点(首)addAtHead (value) {const node = new LinkedNode(value)if (this.count === 0) {this.head = node} else {// 将 node 添加到 head 的前面node.next = this.headthis.head = node}this.count++}// 获取节点(根据索引)get (index) {if (this.count === 0 || index < 0 || index >= this.count) {return}// 迭代链表,找到对应节点let current = this.headfor (let i = 0; i < index; i++) {current = current.next}return current}// 添加节点(根据索引)addAtIndex (value, index) {if (this.count === 0 || index >= this.count) {return}// 如果 index <= 0,都添加到头部即可if (index <= 0) {return this.addAtHead(value)}// 后面为正常区间处理const prev = this.get(index - 1)const next = prev.nextconst node = new LinkedNode(value)prev.next = nodenode.next = nextthis.count++}// 删除(根据索引)removeAtIndex (index) {if (this.count === 0 || index < 0 || index >= this.count) {return}if (index === 0) {this.head = this.head.next} else {const prev = this.get(index - 1)prev.next = prev.next.next}this.count--}
}
链表的形式
  1. 双向链表
  2. 循环链表
    力扣题目 024. 反转链表
  • 循环实现
var reverseList = function(head) {// 声明变量记录 prev、curlet prev = nulllet cur = head// 当 cur 是节点时,进行迭代while (cur) {// 先保存当前节点的下一个节点const next = cur.nextcur.next = prevprev = curcur = next}return prev
};
  • 递归实现
var reverseList = function(head) {if (head === null || head.next === null) {return head}const newHead = reverseList(head.next)// 能够第一次执行这里的节点为 倒数第二个 节点head.next.next = head// head 的 next 需要在下一次递归执行时设置。当前设置为 null 不影响//   - 可以让最后一次(1)的 next 设置为 nullhead.next = nullreturn newHead
};

力扣题目 022. 环形链表 II

var detectCycle = function(head) {if (head === null || head.next === null) {return null}// 声明快慢指针let slow = headlet fast = headwhile (fast !== null) {// 慢每次指针移动一位slow = slow.next// 如果满足条件,说明 fast 为尾部结点,不存在环if (fast.next === null) {return null}// 快指针每次移动两位fast = fast.next.next// 检测是否有环if (fast === slow) {// 找到环的起点位置let ptr = headwhile (ptr !== slow) {ptr = ptr.nextslow = slow.next}// ptr 和 slow 的交点就是环的起始节点return ptr}}// while 结束,说明 fast 为 null,说明链表没有环return null
};

  1. 满二叉树 (每个节点都有左右子节点)
    满二叉树
  2. 完全二叉树
  • 最低层的节点在最左侧
  • 上面的层级都是满二叉树
    完全二叉树
二叉树遍历
  1. 前序遍历
    根结点 -> 左子树 -> 右子树
    上图顺序为 ABDHIECFG
  2. 中序遍历
    左子树 -> 根结点 -> 右子树
    中序遍历
    上图遍历顺序: GDHBEACIF
  3. 后序遍历
    左子树 -> 右子树 -> 根结点
    上图遍历顺序: GHDEBIFCA

前序、中序、后序都是深度优先遍历

力扣题目 二叉树的前序遍历

  • 递归实现
var preorderTraversal = function(root) {// 用于存储遍历的结果const res = []// 设置函数用于进行递归遍历const preorder = (root) => {// 当前结点为空时,无需进行递归if (!root) {return}// 记录根节点值res.push(root.val)// 前序遍历左子树preorder(root.left)// 前序遍历右子树preorder(root.right)}preorder(root)return res
}; 
  • 迭代 实现
const preorderTraversal = function(root) {const res = []const stk = [] // 栈while (root || stk.length) {while (root) {// 右子结点入栈stk.push(root.right)// 记录根节点res.push(root.val)// 下一步处理左子节点root = root.left}// 左子树处理完毕,将 stk 出栈,处理右子树root = stk.pop()}return res
}

力扣题目 104. 二叉树的最大深度

var maxDepth = function(root) {if (!root) {return 0}return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1
};
广度优先

即是逐层遍历

var levelOrder = function(root) {const res = []if (!root) {return res}// 声明队列用于存储后续数据const q = []q.push(root)// 遍历队列while (q.length !== 0) {// 针对本轮操作,创建一个新的二维数组res.push([])let len = q.lengthfor (let i = 0; i < len; i++) {// 将本次操作的结点出队const node = q.shift()res[res.length - 1].push(node.val)// 检测是否存在左右子结点,如果有,入队即可if (node.left) {q.push(node.left)}if (node.right) {q.push(node.right)}}}return res
};

二叉搜索树
二叉搜索树
左子树小于根结点,右子树大于根结点
力扣题目 98. 验证二叉搜索树

 var isValidBST = function(root) {// 通过一个辅助函数来统一设置左右子树的比较return helper(root, -Infinity, Infinity);
};const helper = (root, lower, upper) => {if (root === null) {return true}// 当前节点值超出边界,说明二叉树为非 BSTif (root.val <= lower || root.val >= upper) {return false;}// 否则,递归处理左右子节点,并更新大小范围// 同时根据左右子节点的返回值进行返回,只有全部递归结果均为 true, 才说明二叉树为 BSTreturn helper(root.left, lower, root.val) && helper(root.right, root.val, upper);
} 

中序遍历迭代实现

function ss(root) {let res = []let dep = []while (root || dep.length) {while (root) {dep.push(root)root = root.left}root = dep.pop()res.push(root.val)root = root.right}return res
}

中序遍历验证二叉搜索树
原理是中序遍历后的数组是一个从小到大的数组, 只需要将当前的值和上一项的值做比较。

var isValidBST = function(root) {let stk = []// 用于记录上一次取得的节点值,BST 中这个值应小于当前节点// 设置默认值为 -Infinity 避免对比较结果产生干扰let oldNode = -Infinitywhile (root || stk.length) {while (root) {stk.push(root) root = root.left}root = stk.pop()// 如果任意节点比上个节点值小,说明二叉树不是 BSTif (root.val <= oldNode) {return false}// 通过比较,记录当前节点值oldNode = root.valroot = root.right}return true
};

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

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

相关文章

CentOS 7 权限管理实战指南:用户组管理相关命令详解

前言 深入了解 CentOS 7 用户组管理的命令&#xff0c;掌握关键的用户组操作技巧。从创建和删除用户组、修改组属性&#xff0c;到设置组密码和管理组成员&#xff0c;这篇文章详细介绍了 CentOS 7 系统下常用的用户组管理命令&#xff0c;为读者小伙伴提供了实用而全面的指南…

Python武器库开发-武器库篇之Whois信息收集模块化(四十五)

Python武器库开发-武器库篇之Whois信息收集模块化(四十五) 我们在进行渗透的时候&#xff0c;需要进行全面的信息收集&#xff0c;除了主动信息收集之外&#xff0c;我们还经常会进行被动信息收集&#xff0c;Whois信息收集就是其中的一种,我们可以利用一些网站进行Whois信息收…

【LabVIEW FPGA入门】没有CompactRIO时进行编程测试

1.新建一个空白项目。 2.新建cRIO终端。 要添加仿真的远程实时目标&#xff0c;请选择项目名称&#xff0c;右击并选择新建>>目标和设备(Targets and Devices)。 3.新建终端和设备&#xff0c;选一个cRIO型号 接下来&#xff0c;当添加目标和设备窗口出现时&#xff0c;请…

虚拟ip可以解决所有的安全问题吗

虚拟IP&#xff08;Virtual IP&#xff09;是一种网络技术&#xff0c;可以把多台物理服务器或设备组合成一个逻辑集群&#xff0c;并且使用同一个IP地址对外提供服务。虚拟IP具有负载均衡、故障切换和高可用性等优势&#xff0c;同时还可以作为一种安全措施来增加系统的抗攻击…

[足式机器人]Part2 Dr. CAN学习笔记-Advanced控制理论 Ch04-12+13 不变性原理+非线性系统稳定设计

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-Advanced控制理论 Ch04-1213 不变性原理非线性系统稳定设计 1. Invariance Princilpe-LaSalle;s Theorem不变性原理2. Nonlinear Basic Feedback Stabilization 非线性系统稳定设计 1. Invarianc…

springCloud使用apache的http类和RestTemplate以及Eureka

使用apache的&#xff1a; package com.csgholding.pvgpsp.eqp.util;import com.esotericsoftware.minlog.Log; import org.apache.commons.collections4.MapUtils; import org.apache.http.HttpEntity; import org.apache.http.client.config.RequestConfig; import org.apac…

强化学习(1)——scratching the surface

李宏毅老师的课件 https://www.bilibili.com/video/BV1XP4y1d7Bk/?spm_id_from333.337.search-card.all.click&vd_sourcee7939b5cb7bc219a05ee9941cd297ade ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/9502a795feba46959c56092d5f3…

蓝桥杯练习题(六)

&#x1f4d1;前言 本文主要是【算法】——蓝桥杯练习题&#xff08;六&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

【软件工程】《软件工程》期末复习提纲

《软件工程》期末复习提纲 第一章 第二章 第三章 第四章 第五章 第六章 第七章 第八章 第九章 第十章 第十一章 第十二章 第十三章 第十四章 小题参考 大题参考 《软件工程》期末复习提纲 第一章 1.在下列选项中&#xff0c;&#xff08; &#xff09;不是软…

Monorepo-uniapp 构建分享

Monorepo uniapp 构建灵感&#xff1a;刚好要做一个项目&#xff0c;于是想到升级一下之前自己写的一个vue3tspiniauno的模版框架&#xff0c;其实那个框架也不错&#xff1b;只是感觉还差点东西&#xff0c;我已经用那个小框架写了两三个项目&#xff1b;轻巧实用。为什么选…

Unity中的异步编程【7】——在一个异步方法里播放了animation动画,取消任务时,如何停止动画播放

用一个异步方法来播放一个动画&#xff0c;正常情况是&#xff1a;动画播放结束时&#xff0c;异步方法宣告结束。那如果我提前取消这个异步任务&#xff0c;那在这个异步方法里面&#xff0c;我要怎么停止播放呢&#xff1f;&#xff01; 一、播放animation动画的异步实现 1…

探索数据的奥秘:一份深入浅出的数据分析入门指南

数据分析 书籍推荐 入门读物 深入浅出数据分析啤酒与尿布数据之美数学之美 数据分析 Scipy and NumpyPython for Data AnalysisBad Data Handbook集体智慧编程Machine Learning in Action机器学习实战Building Machine Learning Systems with Python数据挖掘导论Machine L…

基于Python的汽车信息爬取与可视化分析系统

介绍 这款汽车信息网站是基于多项技术和框架设计的全面的汽车信息展示及查询系统。其中&#xff0c;采用了Python Django框架和Scrapy爬虫技术实现数据的抓取和处理&#xff0c;结合MySQL数据库进行数据存储和管理&#xff0c;利用Vue3、Element-Plus、ECharts以及Pinia等前端…

vivado 添加现有IP文件、生成IP

添加现有IP文件 作为从AMD IP目录添加和自定义IP的替代方案&#xff0c;您可以直接添加XCI或XCIX文件。此过程不同于从按以下方式编目&#xff1a; •XCI或XCIX文件可能是早期版本&#xff0c;也可能是相同或完全自定义的版本AMD IP目录中发现的类似IP。 •XCI或XCIX文件可能…

计算机毕业设计 基于Java的手机销售网站的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

设计模式之开闭原则:如何优雅地扩展软件系统

在现代软件开发中&#xff0c;设计模式是解决常见问题的最佳实践。其中&#xff0c;开闭原则作为面向对象设计的六大基本原则之一&#xff0c;为软件系统的可维护性和扩展性提供了强大的支持。本文将深入探讨开闭原则的核心理念&#xff0c;以及如何在实际项目中运用这一原则&a…

计算机二级Python基本排序题-序号44(补充)

1. 统计一个英文单词的集合中包含全部是小写字母的单词总数。 strings { cad, PE , Window, FM, hello, world,flowers } n 0 for word in strings :if word.islower() :n 1 print(n)2. 根据列表中保存的数据采用turtle库画图直方图&#xff0c;显示输出在屏幕上&#xff0…

竞赛保研 基于计算机视觉的身份证识别系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的身份证识别系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-sen…

游戏开发丨基于PyGlet的简易版Minecraft我的世界游戏

文章目录 写在前面我的世界PyGlet简介实验内容游戏按键程序设计引入文件 运行结果写在后面 写在前面 本期内容&#xff1a;基于PyGlet的简易版Minecraft我的世界游戏 实验环境&#xff1a; pycharmpyglet 项目下载地址&#xff1a;https://download.csdn.net/download/m0_6…

Linux中的yum源仓库和NFS文件共享服务

一.yum简介 1.1 yum简介 yum&#xff0c;全称“Yellow dog Updater, Modified”&#xff0c;是一个专门为了解决包的依赖关系而存在的软件包管理器。类似于windows系统的中电脑软件关键&#xff0c;可以一键下载&#xff0c;一键安装和卸载。yum 是改进型的 RPM 软件管理器&am…