二叉树

相关概念

  • 父节点
  • 子节点
  • 兄弟节点
  • 叶子节点
  • 高度
  • 深度

二叉树

  • 顾名思义,每个节点最多只有两个“叉”,也就是两个子节点,分别为左子节点和右子节点。
  • 其中要求是最多,可以只有一个子节点,或者没有子节点。

满二叉树

叶子节点都在底部,除叶子节点外,其他节点都有两个子节点的二叉树,叫满二叉树。

完全二叉树

叶子节点都在最后两层,最后一层叶子节点都靠左排列,并且除了最后一层,其他层的子节点树都要达到最大,这种二叉树叫完成二叉树。

???当叶子节点都靠左的满二叉树,就是一种完全二叉树。????概念容易混淆。

二叉树的存储

基于指针或者引用的链式存储法

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)

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值