算法(二叉树-矩阵-堆排序)

最小和

1308525-20190626104223069-1561954324.png

位运算知识点

12>>1 //6 a/2 等价为 a>>1

中间数 (L+R)/2 会出现溢出(溢出的意思就是超过了二进制)

L+(R-L)/2 最终改成 l+((r-l)>>1)

const smallSum = arr => {if (arr == null || arr.length < 2) {return 0;}return mergeSort(arr, 0, arr.length - 1)
}
const mergeSort = (arr, l, r) => {if (l == r) {return 0;}// let mid = Math.floor((l + r) / 2)let mid = l+((r-l)>>1)return mergeSort(arr, l, mid) + mergeSort(arr, mid + 1, r) + merge(arr, l, mid, r)
}
const merge = (arr, l, m, r) => {let help = [];let i = 0;let p1 = l;let p2 = m + 1;let res=0;while (p1 <= m && p2 <= r) {//如果左边小于右边,r开始到p2的个数*p1//简单理解成 p1<p2  重复的加在一起res+=arr[p1]<arr[p2]?(r-p2+1)*arr[p1]:0;help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]}while (p1 <= m) {help[i+1]=arr[p1++]}while (p2 <= r) {help[i++]=arr[p2++]}for (let j = 0; j < help.length; j++) {arr[l + j] = help[j]}return res
}
console.log(smallSum([1, 2, 3]))

递归的理解

递归算法实际上是一种分而治之的方法,它把复杂问题分解为简单问题来求解。对于某些复杂问题(例如hanio塔问题),递归算法是一种自然且合乎逻辑的解决问题的方式,但是递归算法的执行效率通常比较差。因此,在求解某些问题时,常采用递归算法来分析问题,用非递归算法来求解问题

,递归会出问题的话,循环也一定会出问题,只不过递归是出了问题才告诉你,而循环则在执行前就可以知道有问题

循环和递归有种逆向思维关系, 循环通常来自底向上, 递归自顶向下。

堆排序

将数组转化成二叉树

左节点 2*i+1 右节点 2*i+2 父节点 (i-1)/2

大根堆=>就是完全二叉树

heapSort.gif

// 堆
let len; //数组长度
//建立大堆顶
function builddMaxHeap(arr) {len = arr.length;for (let i = Math.floor(len / 2); i >= 0; i--) {heapify(arr, i)}
}//堆调整
const heapify = (arr, i) => {let left = 2 * i + 1,right = 2 * i + 2,largest = i;if (left < len && arr[left] > arr[largest]) {largest=left;}if (right < len && arr[right] > arr[largest]) {largest=right;}if (largest != i) {swap(arr, i, largest)heapify(arr, largest)}
}
function swap(arr, i, j) {var temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}
//排序
function heapSort(arr) {builddMaxHeap(arr)for (let i = arr.length-1; i >0 ; i--) {//0 i>0  最后一个和0交换  swap(arr, 0, i)len--;//0重新被排到最后  heapify(arr,0)}return arr;
}

排序

let arr=[{name:'张三',age:122,height:423},{name:'张三',age:14,height:223},{name:'张三',age:16,height:123},
]
console.log(arr.sort((a, b) => a.age - b.age))

矩阵算法

回型打印

1308525-20190628164327130-1604236181.png

1308525-20190627124307820-1034537836.png

let arr=[[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]
]
const spiralOrder=(arr)=>{let x1=0;let y1=0;let x2=arr.length-1;let y2=arr[0].length-1;//这个代码是直接找外层循环后再找内层循环while (x1 <= x2 && y1 <= y2) {printEdge(arr,x1++,y1++,x2--,y2--)}//下面这层代码是直接找外层循环//printEdge(arr,x1,y1,x2,y2)
}
const printEdge = (arr,x1, y1, x2, y2) => {// x轴相等// 0  0 0 3if(x1==x2){for (let i = y1; i <=y2 ; i++) {// [0][0]   [0][1]   [0][2]  [0][3]console.log(arr[x1][i])}//y轴相等//0 0 3 0}else if (y1 == y2) {for (let i = x1; i <=x2 ; i++) {console.log(arr[i][y1])}}else{let cy1=y1;let cx1=x1;while (cy1 != y2) {//(0,0) (0,1) (0,2)console.log(arr[x1][cy1])cy1++}while (cx1 != x2) {//(0,3)(1,3)(2,3)console.log(arr[cx1][y2])cx1++}while (cy1 != y1) {//(3,3)(3,2)(3,1)console.log(arr[x2][cy1])cy1--}while (cx1 != x1) {//(3,0)(2,0)(1,0)console.log(arr[cx1][y1])cx1--}}
}
spiralOrder(arr)

打印Z形矩阵

1

宏观基础

一行是一横行

一列是一纵向

//虽然我懂了,但是我被这个行呀,列呀搞糊涂了

/*** 将   AB连线上的元素打印出来* @param {要打印的矩阵} m* @param {A的横坐标} x1* @param {A的纵坐标} y1* @param {B的横坐标} x2* @param {B的纵坐标} y2* @param {打印方向} f*/printMatrizIGZag=(arr) =>{let x1 = 0;let y1 = 0;let x2 = 0;let y2 = 0;let enx2 = arr.length - 1,eny2 = arr[0].length - 1;let fromUp = false;// 判断条件:AB走到最后即结束循环while (x1 != enx2 + 1) {printLevel(arr, x1, y1, x2, y2, fromUp);x1 = y1 == eny2 ? x1 + 1 : x1;y1 = y1 == eny2 ? y1 : y1 + 1;y2 = x2 == enx2 ? y2 + 1 : y2;x2 = x2 == enx2 ? x2 : x2 + 1;fromUp = !fromUp;}}printLevel=(m, x1, y1, x2, y2, f)=> {if (f) {while (x1 != x2 + 1) {console.log(m[x1++][y1--])}} else {while (x2 != x1 - 1) {console.log(m[x2--][y2++])}}}
let arr = [[1, 2, 3, 4],[1, 2, 3, 4],[1, 2, 3, 4],[1, 2, 3, 4]
]
printMatrizIGZag(arr)

链表

链表是由一系列的节点组成的集合,每个节点都使用一个对象的引用指向他的后继,指向另一个节点的引用叫链

1308525-20190628164609413-1150992232.png

有点麻烦,先放放

二叉树遍历

定义一个初始化的二叉树

var nodes = {node: 6,left: {node: 5, left: { node: 4 }, right: { node: 3 }},right: { node: 2, right: { node: 1 } }
}/*
*         6   
*     5       2  
*   4   3        1
* */

先序遍历

递归版

  • 若二叉树为空,则算法结束,否则:
  • 访问根节点
  • 前序遍历根节点的左子树
  • 前序遍历根节点的右子树
let result = [];
const dfs = nodes => {
if (nodes.node) {result.push(nodes.node)//先递归添加所有的左节点nodes.left && dfs(nodes.left)//再递归添加所有的右节点nodes.right && dfs(nodes.right)
}
}
dfs(nodes)
console.log(result)
// [6, 5, 4, 3, 2, 1]

非递归版

  • 初始化一个栈,将根节点压入栈中
  • 先判断右节点有没有,有就入栈,再判断左节点有没有,有就入栈
  • 然后再出栈(pop), 先出左节点,再出右节点
var dfs = function(nodes) {var result = []var stack = []stack.push(nodes)while (stack.length) {var item = stack.pop()result.push(item.node)item.right && stack.push(item.right)item.left && stack.push(item.left)}return result
}
console.log(dfs(nodes))
// [6, 5, 4, 3, 2, 1]

中序遍历

左 中 右

递归版

  • 先入栈6,5,4 出栈4,5,6再5节点的时候因为有右节点3,先入栈,添加到数组中,所以是4,5,3,6
  • 再右节点入栈的时候,因为入栈一个就添加到数组中,所以是2,1
var result = []
var dfs = function(nodes) {if(nodes.node) {//也就是先入栈6,5,4,所有出栈是4,5,6nodes.left && dfs(nodes.left)result.push(nodes.node)//(4,5) 3  6nodes.right && dfs(nodes.right)//因为5有右节点(3)  ,// 然后就是右节点2入栈的时候就添加到数组中,右节点1入栈也被添加了}
}
dfs(nodes)
console.log(result)
// [4, 5, 3, 6, 2, 1]

非递归版

var dfs = function(nodes) {var result = []var stack = []var item = nodesstack.push(nodes)while (stack.length) {if(item.left && !item.touched) {//因为4的item.left没有直接跳出item.touched = trueitem = item.leftstack.push(item)  //(6,5,4)continue}item.touched && delete item.touched // 清理标记item = stack.pop()result.push(item.node) //4,5,item.right && stack.push(item.right) //然后把3入栈,因为3没有左节点直接出栈}return result
}
console.log(dfs(nodes))

后序遍历

左右中

递归版

不用解释,打印下你就懂了
var result = []
var dfs = function(nodes) {if(nodes.node) {nodes.left && dfs(nodes.left)nodes.right && dfs(nodes.right)result.push(nodes.node)}
}
dfs(nodes)
console.log(result)

非递归版

function Stack() {var items = [];     //用来保存栈里的元素this.push = function (element) {items.push(element);}this.pop = function () {return items.pop();}this.peek = function () {return items[items.length - 1];}this.isEmpty = function () {return items.length == 0;}this.size = function () {return items.length;}this.clear = function () {items = [];}this.print = function () {console.log(items.toString());}
}
//也就是先序遍历(中左右)换成中右左
const preOrder = (head) => {if (head != null) {const stack = new Stack()stack.push(head)while (!stack.isEmpty()) {head=stack.pop()console.log(head.node)if (head.right != null) {stack.push(head.right)}if (head.left != null) {stack.push(head.left)}}}
}
preOrder(nodes)最简洁的方法
const preOrder = (head) => {if (head != null) {const stack = new Stack()stack.push(head)let c=null;while (!stack.isEmpty()) {//查看栈顶(就是最后一个)c=stack.peek()if (c.left != null && head != c.left && head != c.right) {stack.push(c.left)}else if (c.right != null && head != c.right) {stack.push(c.right)}else{console.log(stack.pop().node)head=c}}}
}
preOrder(nodes)

打印直观的二叉树

点我你就知道啦

 给一个节点,找到这个节点的后继

直接用java代码吧比较直观

    public static class Node {public int value;public Node left;public Node right;public Node parent;public Node(int data) {this.value = data;}}public static Node getSuccessorNode(Node node) {if (node == null) {  return node;}if (node.right != null) { //如果当前节点的右孩子节点不为空,说明有右子树,return getLeftMost(node.right); //则找到并返回右子树上最左的节点} else {               //如果当前节点没有右子树Node parent = node.parent;while (parent != null && parent.left != node) {node = parent;parent = node.parent;}return parent;}}public static Node getLeftMost(Node node) { //在这个函数里面,node是某个节点的头部if (node == null) {return node;}while (node.left != null) { //左子树不为空的情况下,一路向左node = node.left;}return node;}

记录的过程叫做序列化,把一个内容还原出内存中的树结构,就是反序列化

 序列化二叉树

1308525-20190628150356062-278803499.png

定义一个如图的二叉树

const symmetricalTree = {val: 1,left: {val: 2,left: { val: 4, left: null, right: null },right: { val: 5, left: null, right: null }},right: {val: 3,left: { val: 6, left: null, right: null },right: { val: 7, left: null, right: null }}
}

先序序列化

//序列化
function Serialize(pRoot, arr = []) {if (!pRoot) {arr.push('#');} else {arr.push(pRoot.val);Serialize(pRoot.left, arr);Serialize(pRoot.right, arr);}return arr.join(',');
}

反序列化

//反序列化
function Deserialize(str) {if (!str) {return null;}return deserialize(str.split(','));
}function deserialize (arr) {let node = null;const current = arr.shift();if (current !== '#') {node = { val: current };node.left = deserialize(arr);node.right = deserialize(arr);}return node;
}

可以去查查先序,中序,后序,层序的实现,还有其中的递归版和非递归版

................................................................................................................................................................

转载于:https://www.cnblogs.com/fangdongdemao/p/11103515.html

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

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

相关文章

Nature:盐粒大小的相机,可以拍出清晰彩色照片,未来或可应用到手机

来源&#xff1a;大数据文摘你能想象上图只有盐粒大小的物体是一款相机吗&#xff1f;事实上&#xff0c;这款微型相机甚至可以拍出清晰的全彩图像&#xff0c;而相比之下&#xff0c;普通相机的尺寸要大50万倍。我们可以来看看它的成片。这款微型相机是普林斯顿大学和华盛顿大…

spring学习笔记01-BeanFactory和ApplicationContext的区别

spring学习笔记01-BeanFactory和ApplicationContext的区别 BeanFactory 和 ApplicationContext 的区别 BeanFactory 才是 Spring 容器中的顶层接口。 ApplicationContext 是它的子接口。           BeanFactory 和 ApplicationContext 的区别&#xff1a; 创建对象的…

java微博爬虫

微博爬取要做到每日百万级的数据量&#xff0c;需要解决很多问题。 1.springboot自带Scheduled注解是一个轻量级的quartz&#xff0c;可以完成定时任务。只需要在运行方法上加一个Scheduled注解即可。 该注解有许多属性值 initiaDelay 从程序开始延长一定时间后首次执行。 fixe…

2100年彻底颠覆世界的“十大未来科技”

来源&#xff1a;于硅谷智库 科学家们对2100年前的人类生活进行了十大预测&#xff0c;如果这些预测能够变成现实的话&#xff0c;将会让世界发生翻天覆地的变化。1能上网的隐形眼镜出现时间&#xff1a;2030年前预测者&#xff1a;来自华盛顿大学西雅图分校的巴巴克A帕尔维兹教…

智能如何产生,这仍然是个问题

来源&#xff1a;孙学军科学网博客链接地址&#xff1a;https://blog.sciencenet.cn/blog-41174-1316772.html本文的智能只是生物系统工作原理层面&#xff0c;而不是意识层面的&#xff0c;无论是工作原理&#xff0c;还是大脑意识层面&#xff0c;今天的科学仍然没有给出理想…

spring学习笔记05-IOC常用注解(二)

文章目录2.3 关于 Spring 注解和 XML 的选择问题2.4spring 管理对象细节2.5spring 的纯注解配置2.5.1 待改造的问题2.5.2 新注解说明2.5.2.1 Configuration2.5.2.2 ComponentScan2.5.2.3 Bean2.5.2.4 PropertySource2.5.2.5 Import2.5.2.6 通过注解获取容器&#xff1a;2.3 关于…

一文掌握明年物联网传感器市场!2022中国AIoT产业全景图谱报告新鲜出炉

来源&#xff1a;传感器专家网物联网产业是传感器应用最广泛的领域之一&#xff0c;研发新型传感器&#xff0c;做传感器市场&#xff0c;都不能不考虑物联网产业的需求。2021年随着COVID-19 病毒的存在已常态化&#xff0c;防疫抗疫进入了拉锯阶段&#xff1b;波及全球的“芯片…

EUV光刻机内部揭秘!

转载自: ittbank来源&#xff1a;半导体行业观察PatrickWhelan正在透过他的洁净室服面板凝视着事情的进展。在他面前是一块闪闪发光的玻璃&#xff0c;大约有一个烤箱那么大&#xff0c;上面刻有许多挖出的部分以减轻重量&#xff0c;看起来像一个外星图腾。Whelan 的团队正在将…

数据结构与算法——搜索

文章目录1.内容概述2.岛屿数量2.1 题目描述2.2 DFS深度搜索算法思路2.3 BFS宽度搜索算法思路2.4 C代码实现3.单词接龙3.1 题目描述3.2 算法思路3.3 C代码实现4.单词接龙 II4.1 题目描述4.2 算法思路5.火柴拼正方形5.1 题目描述5.2 算法思路5.3 代码实现5.4 算法思路25.5 代码实…

小程序基础能力~网络

&#xff08;1&#xff09;网络-使用说明 网络 在小程序/小游戏中使用网络相关的 API 时&#xff0c;需要注意下列问题&#xff0c;请开发者提前了解。 1. 服务器域名配置 每个微信小程序需要事先设置通讯域名&#xff0c;小程序只可以跟指定的域名与进行网络通信。包括普通 HT…

mybatis学习笔记-02-第一个mybatis程序

该视频为狂神说java视频配套笔记&#xff08;博主自己手打223&#xff0c;日后做个参考223&#xff09;&#xff0c;b站连接&#xff1a;Mybatis最新完整教程IDEA版【通俗易懂】-02-第一个mybatis程序) 文章目录2.第一个mybatis程序2.1搭建环境2.2 创建一个模块2.3编写代码2.4测…

徐波所长专访 | 人工智能:从“作坊式”走向“工业化”新时代

来源&#xff1a;人民网人工智能创新不断 “一体两翼”快速发展人民网&#xff1a;当前&#xff0c;人工智能技术创新不断&#xff0c;应用层出不穷。它究竟走到了哪一步&#xff1f;能否谈谈您是如何看待我国人工智能技术发展现状的&#xff1f;徐波&#xff1a;人工智能是一个…

linux——线程(1)

文章目录1.线程概念1.1 什么是线程1.2 线程和进程区别1.3 线程实现原理1.4 三级映射1.5 线程共享资源1.6 线程非共享资源1.7 线程优、缺点2.线程控制原语2.1 pthread_self 函数2.2 pthread_create 函数3.线程与共享3.1 线程共享全局变量4.线程退出4.1 pthread_exit 函数1.线程概…

Redis压缩列表原理与应用分析

摘要 Redis是一款著名的key-value内存数据库软件&#xff0c;同时也是一款卓越的数据结构服务软件。它支持字符串、列表、哈希表、集合、有序集合五种数据结构类型&#xff0c;同时每种数据结构类型针对不同的应用场景又支持不同的编码方式。这篇文章主要介绍压缩列表编码&…

Science公布2021年度十大科学突破,AI这项前所未有的突破上榜

来源&#xff1a; 学术头条撰文&#xff1a;朱哼哼编审&#xff1a;王哈哈排版&#xff1a;李雪薇2021 年 11 月 17 日&#xff0c;Science 杂志公布了 2021 年的年度科学突破榜单&#xff0c;AlphaFold 和 RoseTTA-fold 两种基于人工智能预测蛋白质结构的技术位列榜首。除此之…

OpenAI教GPT-3学会上网,「全知全能」的AI模型上线了

来源&#xff1a;机器学习研究组订阅它被命名为 WebGPT&#xff0c;OpenAI 认为浏览网页的方式提高了 AI 解答问题的准确性。如果 AI 学会上网&#xff0c;那么它就拥有了无限获取知识的方式&#xff0c;之后会发生什么就不太好预测了。于是著名 AI 研究机构 OpenAI 教那个开启…

Hadoop(2):常见的MapReduce[在Ubuntu中运行!]

1 以词频统计为例子介绍 mapreduce怎么写出来的 弄清楚MapReduce的各个过程&#xff1a; 将文件输入后&#xff0c;返回的<k1,v1>代表的含义是&#xff1a;k1表示偏移量&#xff0c;即v1的第一个字母在文件中的索引&#xff08;从0开始数的&#xff09;&#xff1b;v1表…

springboot学习笔记-01-springboot-helloworld的编写以及原理初步了解(自动装配)

文章目录原理初探主程序关于spring boot&#xff0c;谈谈你的理解&#xff1a;微服务阶段原理初探 pom.xml spring-boot-dependencies&#xff1a;核心依赖在父工程中&#xff01;我们在写或者引入一些springboot依赖的时候&#xff0c;不需要指定版本&#xff0c;就因为有这…

2022年:机器人技术的重大革命

来源&#xff1a;ScienceAI编辑&#xff1a;萝卜皮一段时间以来&#xff0c;跟踪机器人技术发展的人已经注意到该领域的一场无声革命。虽然自动驾驶汽车占据了所有的头条新闻&#xff0c;但人工智能、机器视觉和机器学习的交叉领域正在迅速成为下一阶段机器人技术的基础。通过将…

陈天奇高赞文章:新一代深度学习编译技术变革和展望

来源&#xff1a;机器之心作者&#xff1a;陈天奇陈天奇是机器学习领域著名的青年华人学者之一&#xff0c;本科毕业于上海交通大学ACM班&#xff0c;博士毕业于华盛顿大学计算机系&#xff0c;研究方向为大规模机器学习。在本文中&#xff0c;陈天奇回答了目前深度学习编译技术…