一、二叉树就是这么简单
首先,我们来讲讲什么是树:
树是一种非线性的数据结构,相对于线性的数据结构(链表、数组)而言,树的平均运行时间更短(往往与树相关的排序时间复杂度都不会高)
在现实生活中,我们一般的树长这个样子的:
但是在编程的世界中,我们一般把树“倒”过来看,这样容易我们分析:
二.二叉树的递归定义
1.要么二叉树没有根节点,是一棵空树。
2.要么二叉树由根节点、左子树、右子树组成,且左子树和右子树都是二叉树。可以参考上面的图,每个节点都有2个子树,最下面的叶子节点,子树为nil
三.根据递归定义,用链式存储,实现
树由节点组成,每个节点的数据结构是这样的
一个数据、两个指针(如果有节点就指向节点、没有节点就指向nil)
二叉树每个结点有两条出边,因此指针域有两个——分别指向左子树和右子树的根结点地址,因此右把这种链表叫做二叉链表。其定义方式如下:
// 二叉树结构定义
type node struct {
data int // 数据域
left *node // 指向左子树的根结点
right *node // 指向右子树的根结点
}
如果需要新建结点,可以使用下面的函数
func NewNode(data int) *node {
return &node{data: data}
}
四.二叉树的基本操作
二叉树的常用操作有以下几个:
二叉树的建立、
以及二叉树结点的查找、修改、插入与删除。本节主要介绍二叉树结点 查找、修改、插入、建树的通用思想。
1. 二叉树结点的查找
查找操作是指在给定数据域的条件下,在二叉树中找到所有数据域为给定数据域的结点
可以使用递归来完成查找修改操作。
1.先判断当前结点是否是需要查找的结点:
2.如果不是,则分别往该结点的左孩子和右孩子递归,直到当前结点为 NULL 为止。对于有序的二叉树,左子节点小于当前节点,右子节点大于当前节点
func (nd *node) Search(dt int) *node {
if nd == nil {
return nil
}
//1
if dt == nd.data {
return nd
}
//2 大于当前节点,递归右边
if dt > nd.data {
return nd.right.Search(dt)
}
//2 大于当前节点,递归左边
if dt < nd.data {
return nd.left.Search(dt)
}
return nil
}
2. 二叉树结点的插入
把数据插入到指定的位置,这里的数据唯一不重复。
1.先判断当前结点和插入的值的比较,如果等于,就跳过:
2.如果数据大于本节点,就插入到右孩子,如果右孩子为nil,直接插入,有值继续比较插入
3.如果数据小于本节点,就插入到左孩子,如果左孩子为nil,直接插入,有值继续比较插入对于有序的二叉树,左子节点小于当前节点,右子节点大于当前节点
func (nd *node) Insert(newNode *node) {
//1
if newNode.data == nd.data {
return
}
//2
if newNode.data > nd.data {
if nd.right == nil {
nd.right = newNode
} else {
nd.right.Insert(newNode)
}
} else { //3 小于 继续比较插入到 左孩子
if nd.left == nil {
nd.left = newNode
} else {
nd.left.Insert(newNode)
}
}
}
3. 二叉树创建
root := data.NewNode(250)
for i := 0; i < 14; i++ {
n := rand.Intn(500)
t.Log("i=", i, "的随机数是", n)
root.Insert(data.NewNode(n))
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。