前端数据结构与算法

news2024/11/18 1:42:46

前端数据结构与算法

文章宝典

链表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以快速删除和插入节点,只用修改节点的引用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

实例

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

队列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实例

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

并且左节点的值和后续节点的值都要小于等于该节点的值
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

根据图的节点之间的边是否有方向,可以分为有向图和无向图。

在这里插入图片描述

在这里插入图片描述
在有向图中,访问节点只能按照指定的方向进行。
在这里插入图片描述
在无向图中,可以以任意方向访问节点,因此它也容易构成环。
在这里插入图片描述

根据图的节点是否都可以遍历到,还分为连通图和非连通图(或叫作隔离图):
在这里插入图片描述
连通图中的每个节点都有连接的边。
在这里插入图片描述
非连通图则是由多个独立的图构成,它们之间没有边连接。
在这里插入图片描述
另外,如果连接节点的边还包含有额外信息,例如长度,那么这种图称为加权图。
在这里插入图片描述
使用代码表示图有多种方式,常见的有:
使用邻接矩阵。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

使用邻接节点数组
在这里插入图片描述

二叉树的遍历

遍历二叉树是指从根节点开始,访间树中所有的节点。它是其它一些算法的基础,例如深度优先搜索。
遍历二叉树是指从根节点开始,访间树中所有的节点。它是其它一些算法的基础,例如深度优先搜索。

对于二叉树、每个节点有左右两个子节点,对于是先访问左子节点、还是当前节点,或是右子节点,可以把遍历分为前序中序和后序三种。接下来我们分别看一下这三种形式。

先看前序遍历,前序遍历会先访问当前节点的值,之后访问左子节点或右子节点,这里假定先访问左子节点,然后再访问右子节点,对于每个子节点都是做同样的操作。

中序遍历则是先访问左子节点,再访问当前节点,最后访问右子节点,对于每个子节点也是重复这个过程。

后序遍历则是先访问左子节点的值,再访问右子节点的值,最后访问当前节点的值。对于每个子节点也是同样的操作。

二叉树遍历的代码实现,最简单直观的方法就是使用递归。

对于前序遍历,我们先打印出当前节点的值,然后递归的调用自己,传递左节点,再调用自己传递右节点。当子节点为 null 时退出递归。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二叉树的前序遍历

function Node(value) {
    this.value = value;
    this.leftChild = null;
    this.rightChild = null;
}

var a = new Node("a");
var b = new Node("b");
var c = new Node("c");
var d = new Node("d");
var e = new Node("e");
var f = new Node("f");
var g = new Node("g");
a.leftChild = c;
a.rightChild = b;
c.leftChild = f;
c.rightChild = g;
b.leftChild = d;
b.rightChild = e;

function qianxubianli(Node) {
    if (Node === null) return;
    console.log(Node.value)
    qianxubianli(Node.leftChild)
    qianxubianli(Node.rightChild)
}
qianxubianli(a)

中序遍历
前面相同的Node设置就不重复写了。

function zhongxubianli(Node) {
    if (Node === null) return;
    zhongxubianli(Node.leftChild);
    console.log(Node.value);
    zhongxubianli(Node.rightChild)
}

zhongxubianli(a)

后序遍历

function houxubianli(Node) {
    if (Node === null) return;
    houxubianli(Node.leftChild);
    houxubianli(Node.rightChild)
    console.log(Node.value);
}

houxubianli(a)

根据前序遍历、中序遍历获得二叉树

function Node(value) {
    this.value = value;
    this.leftChild = null;
    this.rightChild = null;
}
const qianxu = ["a", "c", "f", "g", "b", "d", "e"];
const zhongxu = ["f", "c", "g", "a", "d", "b", "e"];

function fn(qianxu, zhongxu) {
    if (qianxu == null || zhongxu == null || qianxu.length == 0 || zhongxu.length == 0 || qianxu.length !== zhongxu.length) return;
    var root = new Node(qianxu[0])
    var index = zhongxu.indexOf(root.value);
    var qianxuLeft = qianxu.slice(1, index + 1);
    var qianxuRight = qianxu.slice(index + 1, qianxu.length);
    var zhongxuLeft = zhongxu.slice(0, index);
    var zhongxuRight = zhongxu.slice(index + 1, zhongxu.length);
    root.leftChild = fn(qianxuLeft, zhongxuLeft);
    root.rightChild = fn(qianxuRight, zhongxuRight);
    return root;
}
var root = fn(qianxu, zhongxu);
console.log(root.leftChild)
console.log(root.rightChild)

根据中序遍历、后序遍历获得二叉树

function Node(value) {
    this.value = value;
    this.leftChild = null;
    this.rightChild = null;
}
const zhongxu = ["f", "c", "g", "a", "d", "b", "e"];
const houxu = ["f", "g", "c", "d", "e", "b", "a"];

function fn(houxu, zhongxu) {
    if (houxu == null || zhongxu == null || houxu.length == 0 || zhongxu.length == 0 || houxu.length !== zhongxu.length) return;
    var root = new Node(houxu[houxu.length - 1]);
    var index = zhongxu.indexOf(root.value);
    var houLeft = houxu.slice(0, index);
    var houRight = houxu.slice(index, houxu.length - 1);
    var zhongLeft = zhongxu.slice(0, index);
    var zhongRight = zhongxu.slice(index + 1, zhongxu.length);
    root.leftChild = fn(houLeft, zhongLeft);
    root.rightChild = fn(houRight, zhongRight);
    return root;
}
var root = fn(houxu, zhongxu);
console.log(root.leftChild)
console.log(root.rightChild)

前序遍历

在这里插入图片描述
压入调用栈—执行完代码开始出栈
在这里插入图片描述


代码:

调用 traversePreOrder() 遍历 root | [traversePreOrder(13)]
第一行先打印出根节点的值 13| [traversePreOrder(13)]
接下来,执行到遍历左节点的方法 traversePreOrder(6),放入调用栈并执行,打印出 6,此时因为遍历左节点的方法还未 return,所以遍历右子节点的函数调用还不能执行 | 调用栈:[traversePreOrder(6), traversePreOrder(13)]。
接着,递归调用 traversePreOrder() 遍历 6 的左子节点,函数压入调用栈并执行,打印出 3 | 调用栈:[traversePreOrder(3), traversePreOrder(6), traversePreOrder(13) ]。
接着递归调用 traversePreOrder(treeNode.left) 遍历 3 的左子节点|调用栈:[traversePreOrder(null),traversePreOrder(3), traversePreOrder(6) , traversePreOrder(13)]
此时,执行 traversePreOrder(null),treeNode 为 null,函数执行到 if 后,直接 return|调用栈:[traversePreOrder(3), traversePreOrder(6) , traversePreOrder(13)]
那么接下来就从调用栈拿出最顶部的函数 traversePreOrder(3),继续执行,调用 traversePreOrder(treeNode.right) |调用栈:[traversePreOrder(null), traversePreOrder(3), traversePreOrder(6) , traversePreOrder(13)]
treeNode.right 也是 null,所以函数直接返回 |调用栈:[ traversePreOrder(3), traversePreOrder(6) , traversePreOrder(13)]。
接着继续执行 traversePreOrder(3),后面没有代码了,所以 traversePreOrder(3) 函数返回。| [ traversePreOrder(6) , traversePreOrder(13)]
接着执行 traversePreOrder(6),调用它里边的 traversePreOrder(treeNode.right) | [traversePreOrder(9), traversePreOrder(6) , traversePreOrder(13)]。
执行打印出 9 | 调用栈 [traversePreOrder(9), traversePreOrder(6) , traversePreOrder(13)]。
接着调用 9 里的 traversePreOrder(treeNode.left) | [traversePreOrder(7), traversePreOrder(9), traversePreOrder(6) , traversePreOrder(13)]。
执行打印出 7。后面它没有子节点,所以它里边的 traversePreOrder(treeNode.left)traversePreOrder(treeNode.right) 直接返回,这里就不演示,它本身到这里也执行结束了。| [traversePreOrder(9), traversePreOrder(6) , traversePreOrder(13)]。
又回到节点 9,它没有右节点,所以也执行结束并返回。| [traversePreOrder(6) , traversePreOrder(13)]。
到了 traversePreOrder(6),它的代码也执行完毕了,返回。| [ traversePreOrder(13)]
现在开始继续执行 13 根节点的 traversePreOrder(treeNode.right) 方法了,这里边的执行顺序和之前一样,我们简单过一下。
调用 traversePreOrder(20) 打印出 20 | [traversePreOrder(20), traversePreOrder(13)]。
遍历左节点并打印出 15| [traversePreOrder(15), traversePreOrder(20), traversePreOrder(13)]15 没有子节点直接返回,遍历 20 的右节点,打印出 28| [traversePreOrder(28), traversePreOrder(20), traversePreOrder(13)]28 没有左子节点,遍历右子节点,打印出 32 并返回。| [traversePreOrder(32), traversePreOrder(20), traversePreOrder(13)]20 节点遍历完毕并返回。| [traversePreOrder(13)]13 根节点遍历完毕并返回 | []。

此时,前序遍历就完成了,结果是:
13  6  3  9  7  20  15 28  32

在这里插入图片描述

中序遍历

在这里插入图片描述
在这里插入图片描述

后续遍历

在这里插入图片描述
在这里插入图片描述

O 表示法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
大 O 表示法是粗略的估算算法的效率,会直接忽略常数,例如我们使用平行的两个 for 循环,遍历两次数组,可能直接得出时间复杂度为 O(2N),但是最终我们还是表示为 O(N):
在这里插入图片描述
对于无关输入大小,只执行固定行数的代码,无论是 1 行、5 行还是 10 行,都可以认为是 O(1):
在这里插入图片描述
对于算法的评价,会分为最佳情况、平均情况和最坏情况,因为有的算法会根据输入数据的不同,会有不同的时间复杂度,大 O 表示法通常表示的是最坏情况。

在这里插入图片描述

对于空间复杂度,大 O 表示法表示的是算法在执行时,需要额外占用的内存空间,例如对于冒泡排序,它不需要额外创建存储空间,而是就地对原数组进行排序,所以它的空间复杂度是 O(1):
在这里插入图片描述

常见算法的时间复杂度

下面列出一些常见算法的时间复杂度:

数组的访问:O(1)
链表的插入和删除:O(1)
数组的查找:O(N)
折半查找:O(logN),因为每次查找都会少 N / 2 数据。
冒泡排序、选择排序、插入排序、快速排序:O(N2)
归并排序:O(NlogN)
有些算法的时间复杂度并不稳定,例如插入排序、快速排序等。它们会根据原始输入的数组是否已经整体有序,所表现出来的时间复杂度也不相同。例如插入排序在最好情况下的时间复杂度是 O(n)。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

树的广度优先遍历

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

归并排序

##

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

动态规划 Dynamic Programming DP

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

数字调制系列:如何理解IQ ?

最近在筹划写一系列关于数字IQ 调制的短文,以帮助初学者能够更好地理解和掌握。虽然IQ 调制技术已经非常广泛地应用于各种无线通信应用中,但是究其细节,仍有很多人存在疑惑,尤其对于初学者。作者从事测试工作多年,对IQ…

强化学习的Sarsa与Q-Learning的Cliff-Walking对比实验

强化学习的Sarsa与Q-Learning的Cliff-Walking对比实验Cliff-Walking问题的描述Sarsa和Q-Learning算法对比代码分享需要改进的地方引用和写在最后Cliff-Walking问题的描述 悬崖行走:从S走到G,其中灰色部分是悬崖不可到达,求可行方案 建模中&am…

(Java)【深基9.例4】求第 k 小的数

【深基9.例4】求第 k 小的数 一、题目描述 输入 nnn&#xff08;1≤n<50000001 \le n < 50000001≤n<5000000 且 nnn 为奇数&#xff09;个数字 aia_iai​&#xff08;1≤ai<1091 \le a_i < {10}^91≤ai​<109&#xff09;&#xff0c;输出这些数字的第 kk…

元旦礼第三弹!玻色量子荣登2022年中国创新力量50榜单

​2022年12月&#xff0c;国内最大的创新者社区极客公园重磅发布了全新的「中国创新力量 50 榜单&#xff08;InnoForce 50&#xff09;」——在过去一年为泛计算机科学领域及其交叉领域带来创新和突破的中国公司/机构。玻色量子凭借在光量子计算领域突出的核心竞争力&#xff…

配电网前推后带法求电力系统潮流(PythonMatlab实现)

目录 1 概述 2 数学模型 3 节点分层前推回代潮流计算及步骤 3.1 计算方法 3.2 计算步骤 4 算例及数据 5 Matlab&Python代码实现 1 概述 配电网通常是单电源全网连接、开环运行&#xff0c;即呈树状。针对配电系统分析&#xff0c;其根本就是进行潮流计算。潮流计算的…

通过反射机制访问java对象的属性 给属性赋值 读取属性的值

package com.javase.reflect;import java.lang.reflect.Field;/*** 通过反射机制&#xff0c;访问java对象的属性&#xff0c;给属性赋值&#xff0c;读取属性的值&#xff08;重点&#xff1a;五颗星*****&#xff09;* 本例中使用反射机制编写代码&#xff0c;看起来比不使用…

Hi3861鸿蒙物联网项目实战:智能温度计

华清远见FS-Hi3861开发套件&#xff0c;支持HarmonyOS 3.0系统。开发板主控Hi3861芯片内置WiFi功能&#xff0c;开发板板载资源丰富&#xff0c;包括传感器、执行器、NFC、显示屏等&#xff0c;同时还配套丰富的拓展模块。开发板配套丰富的学习资料&#xff0c;包括全套开发教程…

art-template模板引擎

1、模板引擎的基本概念 1.1、渲染UI结构时遇到的问题 var rows [] $.each(res.data, function (i, item) { // 循环拼接字符串 rows.push(<li class"list-group-item"> item.content <span class"badge cmt-date">评论时间&#xff1a; item…

C++ 使用Socket实现主机间的UDP/TCP通信

前言 完整代码放到github上了&#xff1a;cppSocketDemo 服务器端的代码做了跨平台&#xff08;POSIX和WINDOWS&#xff09;&#xff0c;基于POSIX平台&#xff08;Linux、Mac OS X、PlayStation等&#xff09;使用sys/socket.h库&#xff0c;windows平台使用winsock2.h库。 客…

STM32配置LED模块化

文章目录前言一、LED的模块化二、GPIO初始化详细解析三、LED代码封装总结前言 本篇文章将带大家深入了解GPIO的配置&#xff0c;并带大家实现LED模块化编程。 一、LED的模块化 什么叫模块化编程&#xff1f;我的理解就是每一个模块都分别写成对应的.c和.h文件&#xff0c;有…

S32K144—从0到1一个MBD模型的诞生

一个MBD模型的诞生&#xff0c;分为以下几步&#xff1a; 1、连接好硬件S32K144 EVB 2、选择一个合适的工作空间&#xff0c;新建一个simulink模型&#xff0c;保存 3、在模型中拖入模块&#xff1a; MBD_S32K1xx_Config_Information Digital_Input_ISR Periodic_Interrupt…

C++ 设计模式

设计模式序创建型模式工厂方法模式抽象工厂模式单例模式建造者模式&#xff08;生成器模式&#xff09;原型模式结构型模式适配器模式装饰器代理模式外观模式桥接模式组合模式&#xff08;部分--整体模式&#xff09;享元模式行为型模式策略模式模板模式观察者模式迭代器模式责…

对抗js前端加密的万能方法

1、前言 现在越来越多的网站采用全报文加密&#xff0c;测试的时候需要逆向提取加密算法以及密钥&#xff0c;过程十分繁琐和复杂。本文提供一种更为简单快捷的方法来解决此问题。 原理大致如下&#xff1a;使用浏览器的Override Hook加密前的数据&#xff0c;配置代理地址发…

[Linux]Linux编译器-gcc/g++

&#x1f941;作者&#xff1a; 华丞臧. &#x1f4d5;​​​​专栏&#xff1a;【LINUX】 各位读者老爷如果觉得博主写的不错&#xff0c;请诸位多多支持(点赞收藏关注)。如果有错误的地方&#xff0c;欢迎在评论区指出。 推荐一款刷题网站 &#x1f449; LeetCode刷题网站 文…

SpringBoot+Redis(官方案例)

在线文档项目结构 1.源码克隆&#xff1a;git clone https://github.com/spring-guides/gs-messaging-redis.git 2.包含两个项目initial和complete&#xff0c;initial可以根据文档练习完善&#xff0c;complete是完整项目 3.功能描述&#xff1a;构建应用程序&#xff0c;使用…

【谷粒商城基础篇】商品服务:商品维护

谷粒商城笔记合集 分布式基础篇分布式高级篇高可用集群篇简介&环境搭建项目简介与分布式概念&#xff08;第一、二章&#xff09;基础环境搭建&#xff08;第三章&#xff09;整合SpringCloud整合SpringCloud、SpringCloud alibaba&#xff08;第四、五章&#xff09;前端知…

xxx.lua入门编程

lua入门级编程,openresty的前置技能lua入门级编程,openresty的前置技能 看上图 lua示例&#xff1a; 入门示例 print("hello world!") local arr {"java","mysql","oracle"}; local map {usernamezhangsan,password123}; local fu…

Debezium 同步 PostgreSQL 数据到 RocketMQ 中

1.RocketMQ Connect概览 RocketMQ Connect是RocketMQ数据集成重要组件&#xff0c;可将各种系统中的数据通过高效&#xff0c;可靠&#xff0c;流的方式&#xff0c;流入流出到RocketMQ&#xff0c;它是独立于RocketMQ的一个单独的分布式&#xff0c;可扩展&#xff0c;可容错系…

字节二面:Redis 的大 Key 对持久化有什么影响?

Redis 的持久化方式有两种&#xff1a;AOF 日志和 RDB 快照。 所以接下来&#xff0c;针对这两种持久化方式具体分析分析。 大 Key 对 AOF 日志的影响 先说说 AOF 日志三种写回磁盘的策略 Redis 提供了 3 种 AOF 日志写回硬盘的策略&#xff0c;分别是&#xff1a; Always&am…

Git(四) - Git 分支操作

​​​​​​​ 一、什么是分支 在版本控制过程中&#xff0c;同时推进多个任务&#xff0c;为每个任务&#xff0c;我们就可以创建每个任务的单独分支。使用分支意味着程序员可以把自己的工作从开发主线上分离开来&#xff0c;开发自己分支的时候&#xff0c;不会影响主线分支…