算法(二叉树-矩阵-堆排序)
最小和
位运算知识点
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大根堆=>就是完全二叉树
// 堆 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))
矩阵算法
回型打印
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形矩阵
宏观基础
一行是一横行
一列是一纵向
//虽然我懂了,但是我被这个行呀,列呀搞糊涂了
/*** 将 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)
链表
链表是由一系列的节点组成的集合,每个节点都使用一个对象的引用指向他的后继,指向另一个节点的引用叫链
有点麻烦,先放放
二叉树遍历
定义一个初始化的二叉树
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;}
记录的过程叫做序列化,把一个内容还原出内存中的树结构,就是反序列化
序列化二叉树
定义一个如图的二叉树
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
算法(二叉树-矩阵-堆排序)相关推荐
- 豪斯荷尔德变换及变形QR算法对矩阵进行奇异值分解VB算法
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ...
- matlab中服从高斯分布的矩阵_推荐基础算法之矩阵分解PMF
推荐基础算法之矩阵分解PMF 大多数存在的协同过滤算法不能处理以下两种情况: 1. 不能处理大规模数据 2.不能处理评分非常少的用户数据 概率矩阵分解模型可以解决大规模.稀疏且不平衡的数据.这篇文章主 ...
- 矩阵乘法 算法训练 试题_蓝桥杯习题集_ 算法训练 矩阵乘法
原文: 算法训练 矩阵乘法 时间限制:1.0s 内存限制:512.0MB 问题描述 输入两个矩阵,分别是m*s,s*n大小.输出两个矩阵相乘的结果. 输入格式 第一行,空格隔开的三个正整数m,s, ...
- python堆排序算法_python 排序 堆排序
算法思想 : 堆排序利用堆数据结构设计的一种排序算法,堆是一种近似完全二叉树的结构,同时满足堆积的性质,即对于任意的i均有ki>=k(2i+1),ki>=k(2i+2) 步骤: 将数组转化 ...
- 数据结构与算法--二叉树第k个大的节点
二叉树第k个大的节点 二叉树文章列表: 数据结构与算法–面试必问AVL树原理及实现 数据结构与算法–二叉树的深度问题 数据结构与算法–二叉堆(最大堆,最小堆)实现及原理 数据结构与算法–二叉查找树转顺 ...
- 数据结构与算法-- 二叉树中和为某一值的路径
二叉树中和为某一值的路径 题目:输入一颗二叉树和一个整数,打印出二叉树中节点值的和为给定值的所有路径.从树的根节点开始往下一只到叶子节点所经过的节点形成一条路径. 我们用二叉树节点的定义沿用之前文章中 ...
- 数据结构与算法-- 二叉树后续遍历序列校验
二叉树后续遍历序列校验 题目:输入一个整数数组,判断改数组是否是某个二叉搜索树的后续遍历结果,如果是返回true否则false,假设输入数组的任意两个数字不相同. 例如输入{5,7,6,9,11,10 ...
- java堆算法_用Java写算法之七:堆排序
堆是数据结构中的一种重要结构,了解了"堆"的概念和操作,可以快速掌握堆排序. 堆的概念 堆是一种特殊的完全二叉树(complete binary tree).如果一棵完全二叉树的所 ...
- javascript数据结构与算法--二叉树遍历(中序)
javascript数据结构与算法--二叉树遍历(中序) 中序遍历按照节点上的键值,以升序访问BST上的所有节点 代码如下: /**二叉树中,相对较小的值保存在左节点上,较大的值保存在右节点中*** ...
最新文章
- UML类图关系表示方法
- 视频光端机的应用领域有哪些?
- 模块 hashlib模块
- 太赞了!刷题PDF终于在GitHub上开源了!覆盖字节、蚂蚁、腾讯等多家大厂真题...
- 中国体外冲击波碎石机市场趋势报告、技术动态创新及市场预测
- element 输入框点击事件_Element Input输入框的使用方法
- python统计字符串中字母个数字母无视大小写_python判断字符串是字母 数字 大小写(转载)...
- hadoop启动mysql服务_Hadoop MySQL 服务自启动配置
- html文件上传 用到美化,纯css美化file文件上传控件方法
- 选择H5响应式网站建设的主要原因
- 纯C语言编程实现数独解法
- 时间序列 预处理 python_时间序列算法理论及python实现(1-算法理论部分)
- 查看linux版本的命令
- 【西行】Java 编程语言简单介绍
- HTML 标签列表(字母排序)
- 制作动态照片用什么软件?这些软件可以帮你搞定
- 磁力大会,快手“品销合一”铸造直播+营销商业双引擎
- 数据库缓存一致性问题
- 通过journalctl查看日志
- glsl 图片旋转不变形
热门文章
- java 判断数字二进制有几位_判断一个二进制数字有多少个1----java实现
- resnet152训练_Resnet-152的图像预处理
- 数据结构之平衡树:红黑树的介绍与Python代码实现——17
- Django基本概念、安装、配置到实现框架,Xmind学习笔记
- LeetCode 5832. 构造元素不等于两相邻元素平均值的数组
- LeetCode 1952. 三除数
- 正则邮箱_自己写一个通用的邮箱正则表达式
- 模块概念与使用及注意事项
- python指定范围内加法代码解析
- linux基础 linhaifeng,Linux 基础命令(一)