链表
反转单向链表
该题⽬来⾃ LeetCode,题⽬需要将⼀个单向链表反转。思路很简单,使⽤三个变量分别表示当前节点和当前节点的前后节点,虽然这题很简单,但是却是⼀道⾯试常考题
var reverseList = function ( head ) {
if ( ! head || ! head. next) return head
let pre = null
let current = head
let next
while ( current) {
next = current. next
current. next = pre
树
⼆叉树的先序,中序,后序遍历
先序遍历表示先访问根节点,然后访问左节点,最后访问右节点。 中序遍历表示先访问左节点,然后访问根节点,最后访问右节点。 后序遍历表示先访问左节点,然后访问右节点,最后访问根节点
递归实现
pre = current
current = next
}
return pre
} ;
function TreeNode ( val ) {
this . val = val;
this . left = this . right = null ;
}
var traversal = function ( root ) {
if ( root) {
console. log ( root) ;
traversal ( root. left) ;
traversal ( root. right) ;
}
} ;
对于递归的实现来说,只需要理解每个节点都会被访问三次就明⽩为什么这样实现了
⾮递归实现
⾮递归实现使⽤了栈的结构,通过栈的先进后出模拟递归实现。
以下是先序遍历代码实现
function pre ( root ) {
if ( root) {
let stack = [ ] ;
stack. push ( root) ;
while ( stack. length > 0 ) {
root = stack. pop ( ) ;
console. log ( root) ;
if ( root. right) {
stack. push ( root. right) ;
}
if ( root. left) {
stack. push ( root. left) ;
}
}
}
}
以下是中序遍历代码实现
function mid ( root ) {
if ( root) {
let stack = [ ] ;
while ( stack. length > 0 || root) {
if ( root) {
stack. push ( root) ;
root = root. left;
} else {
root = stack. pop ( ) ;
console. log ( root) ;
root = root. right;
}
}
以下是后序遍历代码实现,该代码使⽤了两个栈来实现遍历,相⽐⼀个栈的遍历来说要容易理解很多
function pos ( root ) {
if ( root) {
let stack1 = [ ] ;
let stack2 = [ ] ;
stack1. push ( root) ;
while ( stack1. length > 0 ) {
root = stack1. pop ( ) ;
stack2. push ( root) ;
if ( root. left) {
stack1. push ( root. left) ;
}
if ( root. right) {
stack1. push ( root. right) ;
}
}
while ( stack2. length > 0 ) {
console. log ( s2. pop ( ) ) ;
}
}
}
中序遍历的前驱后继节点
实现这个算法的前提是节点有⼀个 parent 的指针指向⽗节点,根节点指向null 该树的中序遍历结果是 4, 2, 5, 1, 6, 3, 7
前驱节点
对于节点 2 来说,他的前驱节点就是 4 ,按照中序遍历原则,可以得出以下结论 如果选取的节点的左节点不为空,就找该左节点最右的节点。对于节点 1 来说,他有左节点 2 ,那么节点 2 的最右节点就是 5 如果左节点为空,且⽬标节点是⽗节点的右节点,那么前驱节点为⽗节点。对于节点 5 来说,没有左节点,且是节点 2 的右节点,所以节点 2 是前驱节点 如果左节点为空,且⽬标节点是⽗节点的左节点,向上寻找到第⼀个是⽗节点的右节点的节点。对于节点 6 来说,没有左节点,且是节点 3 的左节点,所以向上寻找到节点 1 ,发现节点 3 是节点 1 的右节点,所以节点 1 是节点 6 的前驱节点
以下是算法实现
function predecessor ( node ) {
if ( ! node) return
if ( node. left) {
return getRight ( node. left)
} else {
let parent = node. parent
while ( parent && parent. right === node) {
node = parent
parent = node. parent
}
return parent
}
}
function getRight ( node ) {
if ( ! node) return
node = node. right
while ( node) node = node. right
return node
}
后继节点
对于节点 2 来说,他的后继节点就是 5 ,按照中序遍历原则,可以得出以下结论 如果有右节点,就找到该右节点的最左节点。对于节点 1 来说,他有右节点 3 ,那么节点3 的最左节点就是 6 如果没有右节点,就向上遍历直到找到⼀个节点是⽗节点的左节点。对于节点 5 来说,没有右节点,就向上寻找到节点 2 ,该节点是⽗节点 1 的左节点,所以节点 1 是后继节点 以 下是算法实现
function successor ( node ) {
if ( ! node) return
if ( node. right) {
return getLeft ( node. right)
} else {
let parent = node. parent
while ( parent && parent. left === node) {
node = parent
parent = node. parent
}
return parent
}
}
function getLeft ( node ) {
if ( ! node) return
node = node. left
while ( node) node = node. left
return node
}
树的深度
树的最⼤深度:该题⽬来⾃ Leetcode,题⽬需要求出⼀颗⼆叉树的最⼤深度 以下是算法实现
var maxDepth = function ( root ) {
if ( ! root) return 0
return Math. max ( maxDepth ( root. left) , maxDepth ( root. right) ) + 1
} ;
对于该递归函数可以这样理解:⼀旦没有找到节点就会返回 0,每弹出⼀次递归函数就会加⼀,树有三层就会得到3