diff --git a/structures/Heap.go b/structures/Heap.go new file mode 100644 index 00000000..b8881fb8 --- /dev/null +++ b/structures/Heap.go @@ -0,0 +1,30 @@ +package structures + +// intHeap 实现了 heap 的接口 +type intHeap []int + +func (h intHeap) Len() int { + return len(h) +} + +func (h intHeap) Less(i, j int) bool { + return h[i] < h[j] +} + +func (h intHeap) Swap(i, j int) { + h[i], h[j] = h[j], h[i] +} + +func (h *intHeap) Push(x interface{}) { + // Push 使用 *h,是因为 + // Push 增加了 h 的长度 + *h = append(*h, x.(int)) +} + +func (h *intHeap) Pop() interface{} { + // Pop 使用 *h ,是因为 + // Pop 减短了 h 的长度 + res := (*h)[len(*h)-1] + *h = (*h)[:len(*h)-1] + return res +} diff --git a/structures/Heap_test.go b/structures/Heap_test.go new file mode 100644 index 00000000..8e6a30c4 --- /dev/null +++ b/structures/Heap_test.go @@ -0,0 +1,30 @@ +package structures + +import ( + "container/heap" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_intHeap(t *testing.T) { + ast := assert.New(t) + + ih := new(intHeap) + heap.Init(ih) + + heap.Push(ih, 1) + heap.Pop(ih) + + begin, end := 0, 10 + for i := begin; i < end; i++ { + heap.Push(ih, i) + ast.Equal(0, (*ih)[0], "插入 %d 后的最小值却是 %d,ih=%v", i, (*ih)[0], (*ih)) + } + + for i := begin; i < end; i++ { + fmt.Println(i, *ih) + ast.Equal(i, heap.Pop(ih), "Pop 后 ih=%v", (*ih)) + } +} diff --git a/structures/Interval.go b/structures/Interval.go new file mode 100644 index 00000000..aaa667f7 --- /dev/null +++ b/structures/Interval.go @@ -0,0 +1,30 @@ +package structures + +// Interval 提供区间表示 +type Interval struct { + Start int + End int +} + +// Interval2Ints 把 Interval 转换成 整型切片 +func Interval2Ints(i Interval) []int { + return []int{i.Start, i.End} +} + +// IntervalSlice2Intss 把 []Interval 转换成 [][]int +func IntervalSlice2Intss(is []Interval) [][]int { + res := make([][]int, 0, len(is)) + for i := range is { + res = append(res, Interval2Ints(is[i])) + } + return res +} + +// Intss2IntervalSlice 把 [][]int 转换成 []Interval +func Intss2IntervalSlice(intss [][]int) []Interval { + res := make([]Interval, 0, len(intss)) + for _, ints := range intss { + res = append(res, Interval{Start: ints[0], End: ints[1]}) + } + return res +} diff --git a/structures/Interval_test.go b/structures/Interval_test.go new file mode 100644 index 00000000..aeb83704 --- /dev/null +++ b/structures/Interval_test.go @@ -0,0 +1,59 @@ +package structures + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Interval2Ints(t *testing.T) { + ast := assert.New(t) + + actual := Interval2Ints(Interval{Start: 1, End: 2}) + expected := []int{1, 2} + ast.Equal(expected, actual) +} + +func Test_IntervalSlice2Intss(t *testing.T) { + ast := assert.New(t) + + actual := IntervalSlice2Intss( + []Interval{ + Interval{ + Start: 1, + End: 2, + }, + Interval{ + Start: 3, + End: 4, + }, + }, + ) + expected := [][]int{ + []int{1, 2}, + []int{3, 4}, + } + + ast.Equal(expected, actual) +} +func Test_Intss2IntervalSlice(t *testing.T) { + ast := assert.New(t) + + expected := []Interval{ + Interval{ + Start: 1, + End: 2, + }, + Interval{ + Start: 3, + End: 4, + }, + } + actual := Intss2IntervalSlice([][]int{ + []int{1, 2}, + []int{3, 4}, + }, + ) + + ast.Equal(expected, actual) +} diff --git a/structures/ListNode.go b/structures/ListNode.go new file mode 100644 index 00000000..d2e3a4a9 --- /dev/null +++ b/structures/ListNode.go @@ -0,0 +1,78 @@ +package structures + +import ( + "fmt" +) + +// ListNode 是链接节点 +// 这个不能复制到*_test.go文件中。会导致Travis失败 +type ListNode struct { + Val int + Next *ListNode +} + +// List2Ints convert List to []int +func List2Ints(head *ListNode) []int { + // 链条深度限制,链条深度超出此限制,会 panic + limit := 100 + + times := 0 + + res := []int{} + for head != nil { + times++ + if times > limit { + msg := fmt.Sprintf("链条深度超过%d,可能出现环状链条。请检查错误,或者放宽 l2s 函数中 limit 的限制。", limit) + panic(msg) + } + + res = append(res, head.Val) + head = head.Next + } + + return res +} + +// Ints2List convert []int to List +func Ints2List(nums []int) *ListNode { + l := &ListNode{} + t := l + for _, v := range nums { + t.Next = &ListNode{Val: v} + t = t.Next + } + return l.Next +} + +// GetNodeWith returns the first node with val +func (l *ListNode) GetNodeWith(val int) *ListNode { + res := l + for res != nil { + if res.Val == val { + break + } + res = res.Next + } + return res +} + +// Ints2ListWithCycle returns a list whose tail point to pos-indexed node +// head's index is 0 +// if pos = -1, no cycle +func Ints2ListWithCycle(nums []int, pos int) *ListNode { + head := Ints2List(nums) + if pos == -1 { + return head + } + c := head + for pos > 0 { + c = c.Next + pos-- + } + tail := c + for tail.Next != nil { + tail = tail.Next + } + tail.Next = c + return head +} diff --git a/structures/ListNode_test.go b/structures/ListNode_test.go new file mode 100644 index 00000000..ed1df4f6 --- /dev/null +++ b/structures/ListNode_test.go @@ -0,0 +1,68 @@ +package structures + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_l2s(t *testing.T) { + ast := assert.New(t) + ast.Equal([]int{}, List2Ints(nil), "输入nil,没有返回[]int{}") + + one2three := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 2, + Next: &ListNode{ + Val: 3, + }, + }, + } + ast.Equal([]int{1, 2, 3}, List2Ints(one2three), "没有成功地转换成[]int") + + limit := 100 + overLimitList := Ints2List(make([]int, limit+1)) + ast.Panics(func() { List2Ints(overLimitList) }, "转换深度超过 %d 限制的链条,没有 panic", limit) +} + +func Test_s2l(t *testing.T) { + ast := assert.New(t) + ast.Nil(Ints2List([]int{}), "输入[]int{},没有返回nil") + + ln := Ints2List([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}) + i := 1 + for ln != nil { + ast.Equal(i, ln.Val, "对应的值不对") + ln = ln.Next + i++ + } +} + +func Test_getNodeWith(t *testing.T) { + ast := assert.New(t) + // + ln := Ints2List([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}) + val := 10 + node := &ListNode{ + Val: val, + } + tail := ln + for tail.Next != nil { + tail = tail.Next + } + tail.Next = node + expected := node + actual := ln.GetNodeWith(val) + ast.Equal(expected, actual) +} + +func Test_Ints2ListWithCycle(t *testing.T) { + ast := assert.New(t) + ints := []int{1, 2, 3} + l := Ints2ListWithCycle(ints, -1) + ast.Equal(ints, List2Ints(l)) + + l = Ints2ListWithCycle(ints, 1) + ast.Panics(func() { List2Ints(l) }) +} diff --git a/structures/NestedInteger.go b/structures/NestedInteger.go new file mode 100644 index 00000000..0a944f39 --- /dev/null +++ b/structures/NestedInteger.go @@ -0,0 +1,37 @@ +package structures + +// NestedInteger is the interface that allows for creating nested lists. +// You should not implement it, or speculate about its implementation +type NestedInteger struct { + Num int + Ns []*NestedInteger +} + +// IsInteger Return true if this NestedInteger holds a single integer, rather than a nested list. +func (n NestedInteger) IsInteger() bool { + return n.Ns == nil +} + +// GetInteger Return the single integer that this NestedInteger holds, if it holds a single integer +// The result is undefined if this NestedInteger holds a nested list +// So before calling this method, you should have a check +func (n NestedInteger) GetInteger() int { + return n.Num +} + +// SetInteger Set this NestedInteger to hold a single integer. +func (n *NestedInteger) SetInteger(value int) { + n.Num = value +} + +// Add Set this NestedInteger to hold a nested list and adds a nested integer to it. +func (n *NestedInteger) Add(elem NestedInteger) { + n.Ns = append(n.Ns, &elem) +} + +// GetList Return the nested list that this NestedInteger holds, if it holds a nested list +// The list length is zero if this NestedInteger holds a single integer +// You can access NestedInteger's List element directly if you want to modify it +func (n NestedInteger) GetList() []*NestedInteger { + return n.Ns +} diff --git a/structures/NestedInterger_test.go b/structures/NestedInterger_test.go new file mode 100644 index 00000000..bf1727b5 --- /dev/null +++ b/structures/NestedInterger_test.go @@ -0,0 +1,30 @@ +package structures + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_NestedInteger(t *testing.T) { + ast := assert.New(t) + + n := NestedInteger{} + + ast.True(n.IsInteger()) + + n.SetInteger(1) + ast.Equal(1, n.GetInteger()) + + elem := NestedInteger{Num: 1} + + expected := NestedInteger{ + Num: 1, + Ns: []*NestedInteger{&elem}, + } + n.Add(elem) + + ast.Equal(expected, n) + + ast.Equal(expected.Ns, n.GetList()) +} diff --git a/structures/Point.go b/structures/Point.go new file mode 100644 index 00000000..4e5e4c7e --- /dev/null +++ b/structures/Point.go @@ -0,0 +1,27 @@ +package structures + +// Point 定义了一个二维坐标点 +type Point struct { + X, Y int +} + +// Intss2Points 把 [][]int 转换成 []Point +func Intss2Points(points [][]int) []Point { + res := make([]Point, len(points)) + for i, p := range points { + res[i] = Point{ + X: p[0], + Y: p[1], + } + } + return res +} + +// Points2Intss 把 []Point 转换成 [][]int +func Points2Intss(points []Point) [][]int { + res := make([][]int, len(points)) + for i, p := range points { + res[i] = []int{p.X, p.Y} + } + return res +} diff --git a/structures/Point_test.go b/structures/Point_test.go new file mode 100644 index 00000000..9282179e --- /dev/null +++ b/structures/Point_test.go @@ -0,0 +1,78 @@ +package structures + +import ( + "reflect" + "testing" +) + +func Test_Intss2Points(t *testing.T) { + type args struct { + points [][]int + } + tests := []struct { + name string + args args + want []Point + }{ + { + "测试 [][]int 转换成 []Point ", + args{ + [][]int{ + {1, 0}, + {2, 0}, + {3, 0}, + {4, 0}, + {5, 0}, + }, + }, + []Point{ + Point{X: 1, Y: 0}, + Point{X: 2, Y: 0}, + Point{X: 3, Y: 0}, + Point{X: 4, Y: 0}, + Point{X: 5, Y: 0}, + }, + }, + } + for _, tt := range tests { + if got := Intss2Points(tt.args.points); !reflect.DeepEqual(got, tt.want) { + t.Errorf("%q. intss2Points() = %v, want %v", tt.name, got, tt.want) + } + } +} + +func Test_Points2Intss(t *testing.T) { + type args struct { + points []Point + } + tests := []struct { + name string + args args + want [][]int + }{ + { + "测试 [][]int 转换成 []Point ", + args{ + []Point{ + Point{X: 1, Y: 0}, + Point{X: 2, Y: 0}, + Point{X: 3, Y: 0}, + Point{X: 4, Y: 0}, + Point{X: 5, Y: 0}, + }, + }, + [][]int{ + {1, 0}, + {2, 0}, + {3, 0}, + {4, 0}, + {5, 0}, + }, + }, + } + for _, tt := range tests { + if got := Points2Intss(tt.args.points); !reflect.DeepEqual(got, tt.want) { + t.Errorf("%q. Points2Intss() = %v, want %v", tt.name, got, tt.want) + } + } +} diff --git a/structures/PriorityQueue.go b/structures/PriorityQueue.go new file mode 100644 index 00000000..01677463 --- /dev/null +++ b/structures/PriorityQueue.go @@ -0,0 +1,54 @@ +package structures + +// This example demonstrates a priority queue built using the heap interface. + +import ( + "container/heap" +) + +// entry 是 priorityQueue 中的元素 +type entry struct { + key string + priority int + // index 是 entry 在 heap 中的索引号 + // entry 加入 Priority Queue 后, Priority 会变化时,很有用 + // 如果 entry.priority 一直不变的话,可以删除 index + index int +} + +// PQ implements heap.Interface and holds entries. +type PQ []*entry + +func (pq PQ) Len() int { return len(pq) } + +func (pq PQ) Less(i, j int) bool { + return pq[i].priority < pq[j].priority +} + +func (pq PQ) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] + pq[i].index = i + pq[j].index = j +} + +// Push 往 pq 中放 entry +func (pq *PQ) Push(x interface{}) { + temp := x.(*entry) + temp.index = len(*pq) + *pq = append(*pq, temp) +} + +// Pop 从 pq 中取出最优先的 entry +func (pq *PQ) Pop() interface{} { + temp := (*pq)[len(*pq)-1] + temp.index = -1 // for safety + *pq = (*pq)[0 : len(*pq)-1] + return temp +} + +// update modifies the priority and value of an entry in the queue. +func (pq *PQ) update(entry *entry, value string, priority int) { + entry.key = value + entry.priority = priority + heap.Fix(pq, entry.index) +} diff --git a/structures/PriorityQueue_test.go b/structures/PriorityQueue_test.go new file mode 100644 index 00000000..e171464b --- /dev/null +++ b/structures/PriorityQueue_test.go @@ -0,0 +1,53 @@ +package structures + +import ( + "container/heap" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_priorityQueue(t *testing.T) { + ast := assert.New(t) + + // Some items and their priorities. + items := map[string]int{ + "banana": 2, "apple": 1, "pear": 3, + } + + // Create a priority queue, put the items in it, and + // establish the priority queue (heap) invariants. + pq := make(PQ, len(items)) + i := 0 + for value, priority := range items { + pq[i] = &entry{ + key: value, + priority: priority, + index: i, + } + i++ + } + heap.Init(&pq) + + // Insert a new item and then modify its priority. + it := &entry{ + key: "orange", + priority: 5, + } + heap.Push(&pq, it) + pq.update(it, it.key, 0) + + // Some items and their priorities. + expected := []string{ + "orange", + "apple", + "banana", + "pear", + } + + // Take the items out; they arrive in decreasing priority order. + for pq.Len() > 0 { + it := heap.Pop(&pq).(*entry) + ast.Equal(expected[it.priority], it.key) + } +} diff --git a/structures/Queue.go b/structures/Queue.go new file mode 100644 index 00000000..69431c66 --- /dev/null +++ b/structures/Queue.go @@ -0,0 +1,33 @@ +package structures + +// Queue 是用于存放 int 的队列 +type Queue struct { + nums []int +} + +// NewQueue 返回 *kit.Queue +func NewQueue() *Queue { + return &Queue{nums: []int{}} +} + +// Push 把 n 放入队列 +func (q *Queue) Push(n int) { + q.nums = append(q.nums, n) +} + +// Pop 从 q 中取出最先进入队列的值 +func (q *Queue) Pop() int { + res := q.nums[0] + q.nums = q.nums[1:] + return res +} + +// Len 返回 q 的长度 +func (q *Queue) Len() int { + return len(q.nums) +} + +// IsEmpty 反馈 q 是否为空 +func (q *Queue) IsEmpty() bool { + return q.Len() == 0 +} diff --git a/structures/Queue_test.go b/structures/Queue_test.go new file mode 100644 index 00000000..9b10a39b --- /dev/null +++ b/structures/Queue_test.go @@ -0,0 +1,27 @@ +package structures + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Queue(t *testing.T) { + ast := assert.New(t) + + q := NewQueue() + ast.True(q.IsEmpty(), "检查新建的 q 是否为空") + + start, end := 0, 100 + + for i := start; i < end; i++ { + q.Push(i) + ast.Equal(i-start+1, q.Len(), "Push 后检查 q 的长度。") + } + + for i := start; i < end; i++ { + ast.Equal(i, q.Pop(), "从 q 中 pop 出数来。") + } + + ast.True(q.IsEmpty(), "检查 Pop 完毕后的 q 是否为空") +} diff --git a/structures/Stack.go b/structures/Stack.go new file mode 100644 index 00000000..452c2485 --- /dev/null +++ b/structures/Stack.go @@ -0,0 +1,33 @@ +package structures + +// Stack 是用于存放 int 的 栈 +type Stack struct { + nums []int +} + +// NewStack 返回 *kit.Stack +func NewStack() *Stack { + return &Stack{nums: []int{}} +} + +// Push 把 n 放入 栈 +func (s *Stack) Push(n int) { + s.nums = append(s.nums, n) +} + +// Pop 从 s 中取出最后放入 栈 的值 +func (s *Stack) Pop() int { + res := s.nums[len(s.nums)-1] + s.nums = s.nums[:len(s.nums)-1] + return res +} + +// Len 返回 s 的长度 +func (s *Stack) Len() int { + return len(s.nums) +} + +// IsEmpty 反馈 s 是否为空 +func (s *Stack) IsEmpty() bool { + return s.Len() == 0 +} diff --git a/structures/Stack_test.go b/structures/Stack_test.go new file mode 100644 index 00000000..b0c6c60a --- /dev/null +++ b/structures/Stack_test.go @@ -0,0 +1,27 @@ +package structures + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Stack(t *testing.T) { + ast := assert.New(t) + + s := NewStack() + ast.True(s.IsEmpty(), "检查新建的 s 是否为空") + + start, end := 0, 100 + + for i := start; i < end; i++ { + s.Push(i) + ast.Equal(i-start+1, s.Len(), "Push 后检查 q 的长度。") + } + + for i := end - 1; i >= start; i-- { + ast.Equal(i, s.Pop(), "从 s 中 pop 出数来。") + } + + ast.True(s.IsEmpty(), "检查 Pop 完毕后的 s 是否为空") +} diff --git a/structures/TreeNode.go b/structures/TreeNode.go new file mode 100644 index 00000000..fa041b28 --- /dev/null +++ b/structures/TreeNode.go @@ -0,0 +1,219 @@ +package structures + +import ( + "fmt" +) + +// TreeNode is tree's node +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +// NULL 方便添加测试数据 +var NULL = -1 << 63 + +// Ints2TreeNode 利用 []int 生成 *TreeNode +func Ints2TreeNode(ints []int) *TreeNode { + n := len(ints) + if n == 0 { + return nil + } + + root := &TreeNode{ + Val: ints[0], + } + + queue := make([]*TreeNode, 1, n*2) + queue[0] = root + + i := 1 + for i < n { + node := queue[0] + queue = queue[1:] + + if i < n && ints[i] != NULL { + node.Left = &TreeNode{Val: ints[i]} + queue = append(queue, node.Left) + } + i++ + + if i < n && ints[i] != NULL { + node.Right = &TreeNode{Val: ints[i]} + queue = append(queue, node.Right) + } + i++ + } + + return root +} + +// GetTargetNode 返回 Val = target 的 TreeNode +// root 中一定有 node.Val = target +func GetTargetNode(root *TreeNode, target int) *TreeNode { + if root == nil || root.Val == target { + return root + } + + res := GetTargetNode(root.Left, target) + if res != nil { + return res + } + return GetTargetNode(root.Right, target) +} + +func indexOf(val int, nums []int) int { + for i, v := range nums { + if v == val { + return i + } + } + + msg := fmt.Sprintf("%d 不存在于 %v 中", val, nums) + panic(msg) +} + +// PreIn2Tree 把 preorder 和 inorder 切片转换成 二叉树 +func PreIn2Tree(pre, in []int) *TreeNode { + if len(pre) != len(in) { + panic("preIn2Tree 中两个切片的长度不相等") + } + + if len(in) == 0 { + return nil + } + + res := &TreeNode{ + Val: pre[0], + } + + if len(in) == 1 { + return res + } + + idx := indexOf(res.Val, in) + + res.Left = PreIn2Tree(pre[1:idx+1], in[:idx]) + res.Right = PreIn2Tree(pre[idx+1:], in[idx+1:]) + + return res +} + +// InPost2Tree 把 inorder 和 postorder 切片转换成 二叉树 +func InPost2Tree(in, post []int) *TreeNode { + if len(post) != len(in) { + panic("inPost2Tree 中两个切片的长度不相等") + } + + if len(in) == 0 { + return nil + } + + res := &TreeNode{ + Val: post[len(post)-1], + } + + if len(in) == 1 { + return res + } + + idx := indexOf(res.Val, in) + + res.Left = InPost2Tree(in[:idx], post[:idx]) + res.Right = InPost2Tree(in[idx+1:], post[idx:len(post)-1]) + + return res +} + +// Tree2Preorder 把 二叉树 转换成 preorder 的切片 +func Tree2Preorder(root *TreeNode) []int { + if root == nil { + return nil + } + + if root.Left == nil && root.Right == nil { + return []int{root.Val} + } + + res := []int{root.Val} + res = append(res, Tree2Preorder(root.Left)...) + res = append(res, Tree2Preorder(root.Right)...) + + return res +} + +// Tree2Inorder 把 二叉树转换成 inorder 的切片 +func Tree2Inorder(root *TreeNode) []int { + if root == nil { + return nil + } + + if root.Left == nil && root.Right == nil { + return []int{root.Val} + } + + res := Tree2Inorder(root.Left) + res = append(res, root.Val) + res = append(res, Tree2Inorder(root.Right)...) + + return res +} + +// Tree2Postorder 把 二叉树 转换成 postorder 的切片 +func Tree2Postorder(root *TreeNode) []int { + if root == nil { + return nil + } + + if root.Left == nil && root.Right == nil { + return []int{root.Val} + } + + res := Tree2Postorder(root.Left) + res = append(res, Tree2Postorder(root.Right)...) + res = append(res, root.Val) + + return res +} + +// Equal return ture if tn == a +func (tn *TreeNode) Equal(a *TreeNode) bool { + if tn == nil && a == nil { + return true + } + + if tn == nil || a == nil || tn.Val != a.Val { + return false + } + + return tn.Left.Equal(a.Left) && tn.Right.Equal(a.Right) +} + +// Tree2ints 把 *TreeNode 按照行还原成 []int +func Tree2ints(tn *TreeNode) []int { + res := make([]int, 0, 1024) + + queue := []*TreeNode{tn} + + for len(queue) > 0 { + size := len(queue) + for i := 0; i < size; i++ { + nd := queue[i] + if nd == nil { + res = append(res, NULL) + } else { + res = append(res, nd.Val) + queue = append(queue, nd.Left, nd.Right) + } + } + queue = queue[size:] + } + + i := len(res) + for i > 0 && res[i-1] == NULL { + i-- + } + + return res[:i] +} diff --git a/structures/TreeNode_test.go b/structures/TreeNode_test.go new file mode 100644 index 00000000..dc75bf04 --- /dev/null +++ b/structures/TreeNode_test.go @@ -0,0 +1,166 @@ +package structures + +import ( + "reflect" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + // 同一个 TreeNode 的不同表达方式 + // 1 + // / \ + // 2 3 + // / \ / \ + // 4 5 6 7 + LeetCodeOrder = []int{1, 2, 3, 4, 5, 6, 7} + preOrder = []int{1, 2, 4, 5, 3, 6, 7} + inOrder = []int{4, 2, 5, 1, 6, 3, 7} + postOrder = []int{4, 5, 2, 6, 7, 3, 1} +) + +func Test_Ints2TreeNode(t *testing.T) { + ast := assert.New(t) + + expected := PreIn2Tree(preOrder, inOrder) + actual := Ints2TreeNode(LeetCodeOrder) + ast.Equal(expected, actual) + + actual = Ints2TreeNode([]int{}) + ast.Nil(actual) +} + +func Test_preIn2Tree(t *testing.T) { + ast := assert.New(t) + + actual := Tree2Postorder(PreIn2Tree(preOrder, inOrder)) + expected := postOrder + ast.Equal(expected, actual) + + ast.Panics(func() { PreIn2Tree([]int{1}, []int{}) }) + + ast.Nil(PreIn2Tree([]int{}, []int{})) +} + +func Test_inPost2Tree(t *testing.T) { + ast := assert.New(t) + + actual := Tree2Preorder(InPost2Tree(inOrder, postOrder)) + expected := preOrder + ast.Equal(expected, actual) + + ast.Panics(func() { InPost2Tree([]int{1}, []int{}) }) + + ast.Nil(InPost2Tree([]int{}, []int{})) +} + +func Test_tree2Ints(t *testing.T) { + ast := assert.New(t) + root := PreIn2Tree(preOrder, inOrder) + + ast.Equal(preOrder, Tree2Preorder(root)) + ast.Nil(Tree2Preorder(nil)) + + ast.Equal(inOrder, Tree2Inorder(root)) + ast.Nil(Tree2Inorder(nil)) + + ast.Equal(postOrder, Tree2Postorder(root)) + ast.Nil(Tree2Postorder(nil)) +} + +func Test_indexOf(t *testing.T) { + ast := assert.New(t) + + ast.Equal(1, indexOf(1, []int{0, 1, 2, 3})) + + ast.Panics(func() { indexOf(0, []int{1, 2, 3}) }) +} + +func Test_TreeNode_Equal(t *testing.T) { + type args struct { + a *TreeNode + } + tests := []struct { + name string + fields args + args args + want bool + }{ + + { + "相等", + args{Ints2TreeNode([]int{1, 2, 3, 4, 5})}, + args{Ints2TreeNode([]int{1, 2, 3, 4, 5})}, + true, + }, + + { + "不相等", + args{Ints2TreeNode([]int{1, 2, 3, 4, 5})}, + args{Ints2TreeNode([]int{1, 2, 3, NULL, 5})}, + false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tn := tt.fields.a + if got := tn.Equal(tt.args.a); got != tt.want { + t.Errorf("TreeNode.Equal() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_GetTargetNode(t *testing.T) { + ints := []int{3, 5, 1, 6, 2, 0, 8, NULL, NULL, 7, 4} + root := Ints2TreeNode(ints) + + type args struct { + root *TreeNode + target int + } + tests := []struct { + name string + args args + want *TreeNode + }{ + + { + "找到 root.Right.Right", + args{ + root: root, + target: 8, + }, + root.Right.Right, + }, + + { + "找到 root.Left.Left", + args{ + root: root, + target: 6, + }, + root.Left.Left, + }, + + // + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := GetTargetNode(tt.args.root, tt.args.target); !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetTargetNode() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_Tree2ints(t *testing.T) { + ast := assert.New(t) + + root := PreIn2Tree(preOrder, inOrder) + actual := LeetCodeOrder + expected := Tree2ints(root) + ast.Equal(expected, actual) +}