树
相关概念
- 父节点
- 子节点
- 兄弟节点
- 叶子节点
- 高度
- 深度
- 层
二叉树
- 顾名思义,每个节点最多只有两个“叉”,也就是两个子节点,分别为左子节点和右子节点。
- 其中要求是最多,可以只有一个子节点,或者没有子节点。
满二叉树
叶子节点都在底部,除叶子节点外,其他节点都有两个子节点的二叉树,叫满二叉树。
完全二叉树
叶子节点都在最后两层,最后一层叶子节点都靠左排列,并且除了最后一层,其他层的子节点树都要达到最大,这种二叉树叫完成二叉树。
???当叶子节点都靠左的满二叉树,就是一种完全二叉树。????概念容易混淆。
二叉树的存储
基于指针或者引用的链式存储法
type Tree struct {
Data interface{}
LeftNode *Tree
RightNode *Tree
}
基于数组的顺序存储法
- 把根节点存储在下标为i=1的位置,左子节点为2*i=2,右子节点为2*i+1=3的位置,以此类推,左节点的左孩子节点为2*2=4,左节点的右孩子为2*2+1=5。
- 相反,如果节点X存储在数组的i位置,下标2*i就是它的左孩子,下标2*i+1就是它的右孩子。i/2就是它的父节点。
- 通常,只要知道根节点存储的位置(方便计算,根节点存储在数组下标为1的位置),通过计算,就可以把整颗树串起来。
- 完全二叉树仅仅浪费数组下标为0的位置。
- 非完全二叉树会浪费比较多得内存。
如果一颗树是完全二叉树,那用数组存储是最节省内存的一种方式。因为数组的存储并不像链式存储那样,要额外维护左右两个子节点的指针。
其实,“堆”就是一种完全二叉树,最常用的存储方式就是数组。
二叉树的遍历
代码实现
简单版
package main
import "fmt"
type Tree struct {
Data interface{}
LeftNode *Tree
RightNode *Tree
}
var res []interface{}
func (t *Tree) PreOrder() []interface{} {
if t.Data != nil {
res = append(res, t.Data)
}
if t.LeftNode != nil {
t.LeftNode.PreOrder()
}
if t.RightNode != nil {
t.RightNode.PreOrder()
}
return res
}
func (t *Tree) InOrder() []interface{} {
if t.LeftNode != nil {
t.LeftNode.InOrder()
}
if t.Data != nil {
res = append(res, t.Data)
}
if t.RightNode != nil {
t.RightNode.InOrder()
}
return res
}
func (t *Tree) PostOrder() []interface{} {
if t.LeftNode != nil {
t.LeftNode.PostOrder()
}
if t.RightNode != nil {
t.RightNode.PostOrder()
}
if t.Data != nil {
res = append(res, t.Data)
}
return res
}
func main() {
node1 := Tree{
Data: 1,
LeftNode: nil,
RightNode: nil,
}
node2 := Tree{
Data: 2,
LeftNode: nil,
RightNode: nil,
}
node3 := Tree{
Data: 3,
LeftNode: nil,
RightNode: nil,
}
node4 := Tree{
Data: 4,
LeftNode: nil,
RightNode: nil,
}
node5 := Tree{
Data: 5,
LeftNode: nil,
RightNode: nil,
}
node1.LeftNode = &node2
node1.RightNode = &node3
node2.LeftNode = &node4
node2.RightNode = &node5
res = node1.PreOrder()
fmt.Println(res)
res = nil
res = node1.InOrder()
fmt.Println(res)
res = nil
res = node1.PostOrder()
fmt.Println(res)
}
标准版
package main
import "fmt"
type Tree struct {
Data interface{}
LeftChild *Tree
rightChild *Tree
}
var res []interface{}
func (this *Tree) PreOrder() {
if this.Data != nil {
res = append(res, this.Data)
}
if this.LeftChild != nil {
this.LeftChild.PreOrder()
}
if this.rightChild != nil {
this.rightChild.PreOrder()
} else {
return
}
}
func (this *Tree) InOrder() {
if this.LeftChild != nil {
this.LeftChild.InOrder()
}
if this.Data != nil {
res = append(res, this.Data)
} else {
return
}
if this.rightChild != nil {
this.rightChild.InOrder()
}
}
func (this *Tree) PostOrder() {
if this.LeftChild != nil {
this.LeftChild.PostOrder()
}
if this.rightChild != nil {
this.rightChild.PostOrder()
}
if this.Data != nil {
res = append(res, this.Data)
} else {
return
}
}
func main() {
node1 := Tree{
Data: 1,
LeftChild: nil,
rightChild: nil,
}
node2 := Tree{
Data: 2,
LeftChild: nil,
rightChild: nil,
}
node3 := Tree{
Data: 3,
LeftChild: nil,
rightChild: nil,
}
node4 := Tree{
Data: 4,
LeftChild: nil,
rightChild: nil,
}
node5 := Tree{
Data: 5,
LeftChild: nil,
rightChild: nil,
}
node1.LeftChild = &node2
node1.rightChild = &node3
node2.LeftChild = &node4
node2.rightChild = &node5
node1.PreOrder()
fmt.Println(res)
res = []interface{}{}
node1.InOrder()
fmt.Println(res)
res = []interface{}{}
node1.PostOrder()
fmt.Println(res)
}
时间复杂度
从前中后序遍历,可以看出,每个节点最多访问一次,所以时间复杂度为:O(n)