二叉树
对于算法题,树的遍历确实是经常考的(这里我们只讲二叉树哈,二叉树就是指除了叶子节点外,其余节点都有两个子节点)。一般就是前序遍历,中序遍历和后序遍历。所谓的前,中,后其实就是指什么时候遍历根节点。
如图:这就是一个二叉树,什么是前序遍历呢?前序遍历就是先遍历根节点,再遍历左子树,最后遍历右子树。我一般实现二叉树遍历喜欢使用递归。以我们这个图为例,前序:先遍历根节点:A,再遍历左子树:左子树是B所在分支,这时候可以把B当做A,进行递归。结果是:ABDECFG;
递归思路
递归其实就是直接或者间接自己调用自己,有一个出口(要是没有出口会出现死循环)这个出口就是判断他是不是叶子节点,如果是叶子节点意味着他没有左右子树。
代码实现:
const root = {
val: "A",
left: {
val: "B",
left: {
val: "D"
},
right: {
val: "E"
}
},
right: {
val: "C",
left:{
val:"F",
},
right: {
val: "G"
}
}
};
function preorder(root){
if(!root){
return
}
console.log(root.val)
preorder(root.left)
preorder(root.right)
}
preorder(root)
同理:
如果是中序的话,那我们就先遍历左子树,再遍历根节点,最后遍历右子树。
代码实现:
function preorder(root){
if(!root){
return
}
preorder(root.left)
console.log(root.val)
preorder(root.right)
}
preorder(root)
想必到这:后序遍历大家也知道该怎么做了吧,这里就不赘述了。
链表
说到链表,首先大家得知道链表的结构是什么样的:
大家可以看到一个节点包含数据域和指针域,数据域就是这个节点保存的数据,指针域代表下一个结点(后继结点)的引用。在上篇文章中说数组的时候说过,数组他是顺序存储结构,也就是我们定义了一个大小固定的数组,他是占据一个连续的空间,而链表不同,他不是占据连续的空间,类似这样:
js怎么写一个节点呢?简单
function Node(val){
this.val = val
this.next = null
}
那怎么实现一个链表呢?首先要知道他们之间的联系是通过指针来实现的。就像上边我画的那个图的红箭头就意味着指针。
function Node(val){
this.val = val
this.next = null
}
let a = new Node(1)
let b = new Node(2)
let c = new Node(3)
a.next = b
b.next = c
console.log(a)
log:
链表的特点其实就是能够快速的添加删除元素,有很多人问:为什么需求是方便添加删除元素我们需要使用链表这种数据结构而不是数组呢?其实答案之前我已经给出了,数组他是顺序存储,占据的是一块连续的存储空间,而链表占据的不连续的,他是靠指针建立的联系。比如当我们在任意位置增加一个元素,如果是数组的话,这个位置之后的元素是不是得都要往后挪一位,那他的空间复杂度就是O(n),而如果是链表的话,我们只需要将前一个节点的指针指向这个需要添加的元素,把刚添加的这个元素的指针指向前一个元素指针指向的元素即可。
还拿上边那个例子,我们怎么在尾部添加一个元素4呢?
function Node(val){
this.val = val
this.next = null
}
let a = new Node(1)
let b = new Node(2)
let c = new Node(3)
let d = new Node(4)
a.next = b
b.next = c
c.next = d
console.log(a)
log:
怎么往中间添加呢,比如在1和2之间添加一个5
function Node(val){
this.val = val
this.next = null
}
let a = new Node(1)
let b = new Node(2)
let c = new Node(3)
let d = new Node(4)
let e = new Node(5)
a.next = b
b.next = c
c.next = d
//1和2之间添加一个元素5
a.next = e
e.next = b
console.log(a)
log
删除3呢:
链表经典例题:翻转链表
function Node(val){
this.val = val
this.next = null
}
let a = new Node(1)
let b = new Node(2)
let c = new Node(3)
a.next = b
b.next = c
let newVal = null
function reverse(head){
while(head){
//把第二个节点存起来
let temp = head.next
//把头结点的next置空
head.next = newVal
newVal = head
head = temp
}
return newVal
}
const cc = reverse(a)
console.log(cc)
log: