type ListNode struct {
val int
next ListNode
}
type TreeNode struct {
val int
left TreeNode
right TreeNode
}
图:图中的关系不再是 parent 和 children 的关系了,而是邻居的关系,这里也没有层级结构了,每个节点都是平等的。
type GraphNode struct {
val int
neithbors []int
}
解决广度优先搜索问题,我们会使用队列这么一个FIFO的数据结构
用它解决哪些问题:
无序的顺序表,插入和删除效率还可以,查找慢;
有序的顺序表,查找还行,插入和删除是个问题,那就就引入。。。动;
动态查找表:在查找时插入或删除都比较高效。
BinarySearchTree 采取二叉链表作为二叉排序树(二叉搜索树)的存储结构。
中序遍历二叉排序树可得到一个关键字的有序序列
搜索,插入,删除的复杂度等于树高,O(log(n))
/*
[用list包实现栈、队列的push 和 pop](https://studygolang.com/articles/11932)
二叉树前序遍历(递归、非递归)
二叉树中序遍历(递归、非递归)
二叉树后序遍历(递归、非递归)
二叉树层次遍历(打印行号)
*/
package tree
import "fmt"
type Item interface {}
//节点
type Node struct {
Value Item
left *Node
right *Node
}
//接下来实现以下方法
//
type ItemBinarySearchTreer interface {
Insert(key int, value Item)
Min() *Item
Max() *Item
Search(key Item) bool
InOrderTraverse(f func(item Item))
PreOrderTraverse(f func(item Item))
PostOrderTraverse(f func(item Item))
String()
}
type ItermBinarySearchTree struct {
Root *Node
}
// 先序
func (bst *ItermBinarySearchTree)PreOrderTraverse(f func(item Item)){
preOrdertraver(bst.Root,f)
}
func preOrdertraver(n *Node, f func(item Item)){
if n != nil{
f(n.Value)
preOrdertraver(n.left,f)
preOrdertraver(n.right,f)
}
}
//中序
func (bst *ItermBinarySearchTree)InOrderTraverse(f func(item Item)){
inOrderTraverse(bst.Root, f)
}
func inOrderTraverse(n *Node, f func(item Item)){
if n != nil{
inOrderTraverse(n.left,f)
f(n.Value)
inOrderTraverse(n.right,f)
}
}
//后序
func(bst *ItermBinarySearchTree)PostOrderTraverse(f func(item Item)){
postOrdertraver(bst.Root,f)
}
func postOrdertraver(n *Node, f func(item Item)){
if n != nil{
postOrdertraver(n.left, f)
postOrdertraver(n.right, f)
f(n.Value)
}
}
//非递归
type seqStack struct {
data [100]*Node
tag [100]int //后续 用
top int //数组下标
}
//前序,非递归
func (bst *ItermBinarySearchTree)PreOrderTraverse1()(result []Item){
return preOrdertraver1(bst.Root)
}
func preOrdertraver1(node *Node)(result []Item){
var s seqStack
s.top = -1
if node == nil{
panic("no data here")
}else{
for node != nil || s.top != -1{
for node != nil{
result = append(result,node.Value)
s.top++
s.data[s.top] = node
node = node.left
}
s.top--
node = s.data[s.top]
node = node.right
}
}
}
//中序遍历,非递归
func (bst *ItermBinarySearchTree)InOrderTraverse1()(result []Item){
return inOrderTraverse1(bst.Root)
}
func inOrderTraverse1(node *Node)(result []Item){
var s seqStack
s.top = -1
if node == nil{
panic("no data here")
}else{
for node != nil && s.top != -1{
for node != nil {
s.top++
s.data[s.top] = node
node = node.left
}
s.top--
node = s.data[s.top]
result = append(result,node.Value)
node = node.right
}
}
return
}
//后续,非递归
func (bst *ItermBinarySearchTree)PostOrderTraverse1()(result []Item){
return postOrdertraver1(bst.Root)
}
func postOrdertraver1(node *Node)(result []Item){
var s seqStack
s.top = -1
if node == nil{
panic("no data here")
}else{
for node != nil || s.top != -1{
for node != nil{
s.top++
s.data[s.top] = node
s.tag[s.top] = 0
node = node.left
}
if s.tag[s.top] == 0{
node = s.data[s.top]
s.tag[s.top] = 1
node = node.right
}else{
for s.tag[s.top] == 1{
node = s.data[s.top]
s.top--
result = append(result, node.Value)
if s.top < 0{break}
}
node = nil
}
}
}
return
}
//广度优先排序 从左到右 从右到左都可以
import "fmt"
import "container/list"
type MyQueue struct {
List *list.List
}
type BinaryTree struct {
Value interface{}
Left *BinaryTree
Right *BinaryTree
}
func (queue *MyQueue) pop() interface{} {
if elem := queue.List.Front(); elem != nil {
queue.List.Remove(elem)
return elem.Value
}
return nil
}
func (queue *MyQueue) push(elem interface{}) {
queue.List.PushBack(elem)
}
func levelOrder(node *BinaryTree) {
var nlast *BinaryTree
last := node
level := 1
queue := MyQueue{List: list.New()}
fmt.Println(fmt.Sprintf("-----this is %d level-----", level))
queue.push(node)
for queue.List.Len() > 0 {
node := queue.pop().(*BinaryTree)
if node.Left != nil {
queue.push(node.Left)
nlast = node.Left
}
if node.Right != nil {
queue.push(node.Right)
nlast = node.Right
}
fmt.Println(node.Value)
if last == node && (node.Left != nil || node.Right != nil) {
last = nlast
level++
fmt.Println()
fmt.Println(fmt.Sprintf("-----this is %d level-----", level))
}
}
}
//最小值,根据二叉搜索树的特性,最小值在树的最左边
func (bst *ItermBinarySearchTree)Min()*Item{
n := bst.Root
if n == nil{return nil}
for {
if n.left == nil{return &n.Value}
n = n.left
}
}
//最大值,根据二叉搜索树的特性,最大值在树的最右边
func (bst *ItermBinarySearchTree)Max()*Item{
n := bst.Root
if n == nil{return nil}
for{
if n.right == nil{return &n.Value}
n = n.right
}
}
/*
二叉搜索树,查找元素
指针f指向n的双亲,其初始值为nil
若查找成功,p指向该数据元素节点,并返回True
否则p指向查找路径上访问的最后一个节点并返回False
*/
func (bst *ItermBinarySearchTree)Search(key Item)bool{
return search(bst.Root,key)
}
func search(n *Node, key Item)bool{
if n == nil{
return false
} else if key == n.Value{
return true
} else if key < n.Value{
return search(n.left,key)
} else if key > n.Value{
return search(n.right,key)
}
}
// 二叉搜索树,插入元素
func (bst *ItermBinarySearchTree)Insert(key int,value Item){
n := &Node{key,value,nil,nil}
if bst.Root == nil{
bst.Root = n
}else {
insertNode(bst.Root,n)
}
}
// 递归插入
func insertNode(node ,newNode *Node){
if newNode.Value < node.Value{
if node.left == nil{
node.left = newNode
}else {
insertNode(node.left,newNode)
}
}else if newNode.Value > node.Value{
if node.right == nil{
node.right = newNode
}else {
insertNode(node.right,newNode)
}
}
}
// 非递归 插入
func insertNode1(node ,key Item)bool{
var s,p *Node
if (!search(node,key,nil,p)){
s.Value = key
s.left = s.right =nil
if (!p){
node = s //插入的s为新的根节点
}else if key < p.Value{
p.left = s
}else {
p.right = s
}
return true
}else{
return false //树中已有关键字相同的节点,不再插入
}
}
//二叉搜索树,删除元素
func (bst *ItermBinarySearchTree)Delete(key Item)bool{
return delete(bst.Root,key)
}
func deleteBST(n *Node, key Item)bool{
if n == nil{
return false
}else if key == n.Key{
return delete(n,key)
}else if key < n.Key{
return deleteBST(n.left,key)
}else if key > n.Key{
return deleteBST(n.right,key)
}
}
/*
删除节点p,并重接它的左或右子树
1、叶子节点
2、仅左或右子树的节点
3、左右节点都有,递归方式对二叉排序树T查找key,找到时删除
*/
func delete(p *Node)bool{
var q,s *Node{}
if *p.right == nil{ //右子树为空只需重接它的左子树
*p = *p.left
}else if *p.left == nil{ //左子树为空只需重接它的右子树
*p = *p.right
}else{ //左右子树均为空
q = p
s = *p.left
for s.right{ //左转,然后向右到尽头
q = s
s = s.right
}
*p.Value = *s.Value
if q != p{
q.right = s.left //重接q的右子树
}else{
q.left = s.left //重接p的左子树
}
}
return true
}
// stringfy
func(bst *ItermBinarySearchTree)Sting(){
fmt.Println("----------------")
stringfy(bst.Root,0)
fmt.Println("----------------")
}
func stringfy(n *Node, level int){
if n != nil{
format := ""
for i:=0;i<level;i++{
format += " "
}
format += "-----["
level ++
stringfy(n.left,level)
fmt.Println(n.Value)
stringfy(n.right,level)
}
}
package main
//Blance Factor 平衡因子=节点的左子树深度-节点的右子树深度
/*
平衡二叉树实现原理:在构建二叉排序树中,每当有一个节点插入时,
检查平衡性,找出最小不平衡树
保证二叉排序特性,调整不平衡树中各节点间的链接关系
*/
/*
旋转
最小不平衡树的根节点与它的子节点符号都是相同的、
不统一就把它们先转到符号统一,再旋转
*/
type Status bool
type Item interface {
}
type BiTNode struct{
data Item
bf int
lchild *BiTNode
rchild *BiTNode
}
/*
对以p为根的二叉排序树做右旋转处理
处理之后p指向新的树根节点,即旋转处理之前的左子树的根节点
*/
func RRotate(p *BiTNode){
var L BiTNode
L = *p.lchild
*p.lchild = L.rchild
L.rchild = *p
*p = L
}
/*
对以p为根的二叉排序树做左旋转处理
处理之后p指向新的树根节点,即旋转处理之前的右子树的根节点
*/
func LRotate(p *BiTNode){
var R BiTNode
R = *p.rchild
*p.rchild = R.lchild
R.lchild = *p
*p = R
}
/*
平衡旋转
*/
const LH = 1
const EH = 0
const RH = -1
/*
对以p为根的二叉排序树做左旋转处理
处理之后p指向新的树根节点,即旋转处理之前左子树的右子树的根节点
*/
func LBalanceRotate(p *BiTNode){
var L,Lr BiTNode
L = *p.lchild
switch L.bf {
case LH:
*p.bf = L.bf = EH
RRotate(p)
break
case RH: //新节点插在p左子树的右子树上,要做双旋转处理
Lr = L.rchild //Lr表示p左子树的右子树
switch Lr.bf { //修改p及其左孩子的平衡因子
case LH:
*p.bf = RH
L.bf = EH
break
case EH:
*p.bf = L.bf = EH
break
case LH:
*p.bf = EH
L.bf = LH
break
}
Lr.bf = EH
LRotate(*p.lchild)
RRotate(p)
}
}
/*
对以p为根的二叉排序树做右旋转处理
处理之后p指向新的树根节点,即旋转处理之前的右子树的左子树根节点
*/
func RBalanceRotate(p *BiTNode){
var R,Rl BiTNode
R = *p.lchild
switch R.bf {
case LH:
*p.bf = R.bf = EH
RRotate(p)
break
case RH:
Rl = R.rchild
switch Rl.bf {
case RH:
*p.bf = RH
R.bf = EH
break
case EH:
*p.bf = R.bf = EH
break
case LH:
*p.bf = EH
R.bf = LH
break
}
Rl.bf = EH
RRotate(*p.rchild)
LRotate(p)
}
}
/*
若插入不存在和e有相同关键字的节点,则插入
成功返回1 失败返回0
若导致失衡,则做平衡处理,布尔变量taller反应p长高与否
*/
func InsertAVL(p *BiTNode,e Item, taller *Status)bool{
if (!*p){
//树中存在和e相同关键字的节点
p := BiTNode{e,EH,nil,nil}
*taller = true
}else{
if (e == *p.data){
*taller = false
return false
}
if (e < *p.data){
//需在p的左子树中进行搜索
if (!InsertAVL(*p.lchild,e,taller)){
return false
}
if taller{//已插入到p的左子树
switch *p.bf {
case LH: //原本左子树比右子树高
LBalanceRotate(p)
*taller = false
break
case EH: //原本左右子树等高
*p.bf = LH
*taller = true
break
case RH: //原本右子树比左子树高
*p.bf = EH
*taller = true
break
}
}
}else{
//需在p的右子树中进行搜索
if (!InsertAVL(*p.rchild,e,taller)){
return false
}
if taller{//已插入到p的右子树
switch *p.bf {
case LH: //原本左子树比右子树高
*p.bf = EH
*taller = true
break
case EH: //原本左右子树等高
*p.bf = RH
*taller = true
break
case RH: //原本右子树比左子树高
LBalanceRotate(p)
*taller = false
break
}
}
}
}
return true
}
【一篇看懂红黑树】
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
我们需要记录每一层的信息,但是记录的顺序有区分
tricky,都从左向右记录,但是记录方式不一样,一种记录方式是从列表的尾部加入,另一种是从链表的头部加入
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
//递归
func ZigzagLevelOrder(root *TreeNode)[][]int{
if root == nil{
return nil
}
res := make([][]int,0,10)
var dfs func(root *TreeNode,level int)
dfs = func(root *TreeNode,level int){
if root == nil{return}
if level >= len(res){
res = append(res,[]int{})
}
if level&1 == 0{
res[level] = append(res[level],root.Val)
}else{
res[level] = append([]int{root.Val},res[level]...)
}
dfs(root.Left,level+1)
dfs(root.Right,level+1)
}
dfs(root,0)
return res
}
//非递归
func ZigzagLevelOrder(root *TreeNode)[][]int{
result := make([][]int,0,10)
if root == nil{
return result
}
queue := list.New()
queue.PushBack(root)
isReverse := false
for queue.Len() != 0{
size := queue.Len()
curLevel := []int{}
for i:=0; i<size; i++{
cur := queue.Front().Value
curr := cur.(TreeNode)
if curr.Left != nil{
queue.PushBack(curr.Left)
}
if curr.Right != nil{
queue.PushBack(curr.Right)
}
if isReverse{
curLevel = append([]int{curr.Val},curLevel...)
}else{
curLevel = append(curLevel,curr.Val)
}
}
isReverse = !isReverse
result = append(result,curLevel)
}
return result
}
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
使用广度优先搜索方法,将 n 依次减去比 n 小的所有平方数,直至 n = 0 ,此时的层数即为最后的结果。
输入: [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]], 1
输出: 11
解释:
员工 1 自身的重要度是 5,他有两个直系下属 2 和 3 ,而且 2 和 3 的重要度均为 3 。因此员工 1 的总重要度是 5 + 3 + 3
= 11。
•一个员工最多有一个直系领导,但是可以有多个直系下属
•员工数量不超过 2000。
利用哈希表来存储员工的信息,找到指定 id 的员工后,采用广度优先遍历算法来遍历编号为 id 的员工及其下属员工
删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果。
输入: "(a)())()"
输出: ["(a)()()", "(a())()"]
所谓有效的括号,那么字符串中的左右括号数应该相同,而且每个右括号左边一定有其对应的左括号。这里很容易想到使用一个栈来模拟匹配过程,若栈为空说明该串是符合题意的。