常见数据结构(go 简易实现)

前言

  1. 本文以最粗糙方式实现各种数据结构,一定有更优方式,读者可以自行扩展
  2. 如有错误之处欢迎批评指正

线性结构

数组

内存中顺序存储有序元素

特性:

  1. 随机访问高效,适合读多写少
  2. 插入删除需要移动元素,可能遇到扩容操作
操作描述时间复杂度
查询下标访问,随机读取O(1)
更新下标访问,随机读取,赋值O(1)
插入尾部插入
中间插入,后面元素右移
超范围插入,触发扩容copy
综合O(N)
O(1)
O(N)
O(N)
删除尾部删除
中间删除,后面元素左移
综合O(N)
O(1)
O(N)

链表

内存中非连续非顺序随机存储

特性:

  1. 修改操作时间复杂度低,适合写多读少

  2. 不支持下标访问,查询最坏情况O(N),理论容量无限

操作描述时间复杂度
查询链式递归查找O(N)
更新链式递归查找,赋值不考虑查找
O(1)
插入头部插入
中间插入
尾部插入
不考虑查找
O(1)
O(1)
O(1)
删除头部删除
中间删除
尾部删除
不考虑查找
O(1)
O(1)
O(1)

逻辑结构

基于数组和链表结构派生线性存储结构

特性

维护一个先入后出FILO的顺序线性结构,最早元素栈底,最新元素栈底

实现出栈入栈
数组+index查询尾O(1)
尾删O(1)
index–
查询尾O(1)
尾插O(1)
index++
链表+尾指针查询尾O(1)
尾删O(1)
尾指针更新
查询尾O(1)
尾插O(1)
尾指针更新
应用

代替递归

简易实现

数组

type arrayStack struct {
	data []interface{}
	index int
}

func NewArrayStack() *arrayStack {
	return &arrayStack{
		data:  make([]interface{},0),
		index: -1,
	}
}

func (a *arrayStack)Push(data interface{})  {
	a.data = append(a.data, data)
	a.index++
}

func (a *arrayStack)Pop() interface{} {
	if len(a.data)==0{
		return nil
	}
	r:=a.data[a.index]
	if a.index == 0 {
		a.data=make([]interface{},0)
	}else {
		a.data=a.data[:a.index]
	}
	a.index--
	return r
}


func TestArrayStack(t *testing.T) {

	node:=NewArrayStack()
	for i:=0;i<10;i++{
		node.Push(i)
	}
	for i:=0;i<11;i++{
		fmt.Printf("%v \n",node.Pop())
	}

}

/*
=== RUN   TestArrayStack
9 
8 
7 
6 
5 
4 
3 
2 
1 
0 
<nil> 
--- PASS: TestArrayStack (0.00s)
PASS

Process finished with exit code 0
*/

链表

type singleNode struct {
	data interface{}
	pre *singleNode
}

type linkStack struct {
	data *singleNode
	head *singleNode
}

func NewLinkStack() *linkStack {
	return &linkStack{}
}

func (a *linkStack)Push(data interface{})  {
	if a.data==nil{
		a.data = &singleNode{
			data: data,
			pre: nil,
		}
		a.head = a.data
	}else{
		a.head = &singleNode{
			data: data,
			pre: a.head,
		}
	}
}

func (a *linkStack)Pop() interface{} {
	if a.head==nil{
		return nil
	}
	var r interface{}
	r = a.head.data
	if a.head.pre!=nil {
		a.head = a.head.pre
	}else{
		a.head = nil
	}
	return r
}

func TestLinkStack(t *testing.T) {

	node:=NewLinkStack()
	for i:=0;i<10;i++{
		node.Push(i)
	}
	for i:=0;i<11;i++{
		fmt.Printf("%v \n",node.Pop())
	}

}
/*
=== RUN   TestLinkStack
9 
8 
7 
6 
5 
4 
3 
2 
1 
0 
<nil> 
--- PASS: TestLinkStack (0.00s)
PASS

Process finished with exit code 0
*/

队列

特性

维护一个先入先出FIFO的顺序线性结构,最早元素队头,最新元素队尾

实现出队入队
环形数组+队头index+队尾index查询队头O(1)
队头index–
查询队尾O(1)
队尾index++
链表+头指针+尾指针查询头O(1)
头删O(1)
头指针更新
查询尾O(1)
尾插O(1)
尾指针更新
应用

双端队列,结合栈和队列特性

优先队列,基于二叉堆实现

简易实现

数组

type arrayQueue struct {
	data []interface{}
	pre  int
	next int
}

func NewArrayQueue() *arrayQueue {
	return &arrayQueue{
		data:  make([]interface{},1024),
		pre: -1,
		next:-1,
	}
}

func (a *arrayQueue)Push(data interface{})  {
	a.next = (a.next + 1) % 1024
	a.data[a.next] = data
}

func (a *arrayQueue)Pop() interface{} {
	if a.pre == a.next{
		return  nil
	}
	a.pre = (a.pre + 1) % 1024
	return a.data[a.pre]
}

func TestNewArrayQueue(t *testing.T)  {
	m:=NewArrayQueue()
	for i:=0;i<10;i++{
		m.Push(i)
	}

	for i:=0;i<11;i++{
		fmt.Printf("%v \n",m.Pop())
	}
}
/*
=== RUN   TestNewArrayQueue
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
<nil> 
--- PASS: TestNewArrayQueue (0.00s)
PASS

Process finished with exit code 0
*/

链表

type linkQueue struct {
	data *singleNode
	tail *singleNode
}


func NewLinkQueue() *linkQueue {
	return &linkQueue{}
}

func (a *linkQueue)Push(data interface{})  {
	if a.data==nil{
		a.data = &singleNode{
			data: data,
			next: nil,
		}
		a.tail = a.data
	}else{
		a.tail.next =  &singleNode{
			data: data,
			next: nil,
		}
		a.tail = a.tail.next
	}

}

func (a *linkQueue)Pop() interface{} {
	if a.data==nil {
		return nil
	}
	var r interface{}
	r = a.data.data
	if a.data.next!=nil {
		a.data = a.data.next
	}else {
		a.data = nil
		a.tail = nil
	}
	return r
}

func TestNewLinkQueue(t *testing.T)  {
	m:=NewLinkQueue()
	for i:=0;i<10;i++{
		m.Push(i)
	}

	for i:=0;i<11;i++{
		fmt.Printf("%v \n",m.Pop())
	}
}
/*
=== RUN   TestNewLinkQueue
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
<nil> 
--- PASS: TestNewLinkQueue (0.00s)
PASS

Process finished with exit code 0
*/

哈希表

维护一个键(Key)与值(Value)映射关系存储结构,也叫做散列表

  • Capacity,当前hash表容量
  • LoadFactor,当前负载因子默认0.75,衡量hash冲突概率的经验值
  • Size,当前元素个数
底层是数组+链表结构,key进行hash,定位到数组下标。
- 如果hash冲突:
1.拉链法将key当前下标链式存储。
2.开放地址法将key往后寻找合适位置存储。
- 如果size>=Capacity*LoadFactor:
1.扩容底层数组
2.rehash重新放置key
操作描述时间复杂度
查询hashkey,锁定数组index,有限长的链表查询接近O(1)
更新查询,赋值不考虑查找
接近O(1)
插入hashkey,锁定数组index,链表尾插,可能触发扩容不考虑扩容
接近O(1)
删除hashkey,锁定数组index,有限长的链表查询,链表删除不考虑查找
接近O(1)
简易实现
type bucket struct {
	key   int
	value interface{}
	next  *bucket
}

type m struct {
	buckets []*bucket
}

func NewMap() *m {
	return &m{buckets: make([]*bucket, 1024)}

}

func (m *m) Put(key int, v interface{}) {
	index := key % 1024
	if f := m.buckets[index]; f != nil {
		p := f.next
		for ; p != nil; p = p.next {
			if p.key == key {
				p.value = v
				break
			}
		}
		p.next = &bucket{
			key:   key,
			value: v,
			next:  nil,
		}
	} else {
		m.buckets[index] = &bucket{
			key:   key,
			value: v,
			next:  nil,
		}
	}
}

func (m *m) Get(key int) interface{} {
	index := key % 1024
	if f := m.buckets[index]; f != nil {
		if f.key == key {
			return f.value
		}
		p := f.next
		for ; p != nil; p = p.next {
			if p.key == key {
				return p.value
			}
		}
	}
	return nil
}


func TestNewMap(t *testing.T)  {
	m:=NewMap()
	for i:=0;i<10240;i+=1000{
		m.Put(i,i)
	}

	for i:=0;i<20000;i+=1000{
		fmt.Printf("%v \n",m.Get(i))
	}
}
/*
=== RUN   TestNewMap
0 
1000 
2000 
3000 
4000 
5000 
6000 
7000 
8000 
9000 
10000 
<nil> 
<nil> 
<nil> 
<nil> 
<nil> 
<nil> 
<nil> 
<nil> 
<nil> 
--- PASS: TestNewMap (0.00s)
PASS

Process finished with exit code 0
*/

非线形结构

树是n(n>=0)个节点的有限集。
n = 0, 空树
1. 根节点:有且只有一个
2. 子树: n>2,根节点外其余节点可以划分m(m>0)个有限集,每个有限集又是一个树结构
3. 叶子节点:没有子树的节点
4. 父节点: 上一级节点
5. 子节点: 下一级节点
6. 兄弟节点: 同父节点的节点

二叉树

每个节点只有两个子节点的树,左边为左孩子,右边为右孩子,左边有限集为左子树,右边有限集为右子树

分类

  • 满二叉树:所有非叶子节点都有左右孩子,所有叶子节点都在同一层级上。
  • 完全二叉树:叶子节点层级上缺少右侧节点的满二叉树
  • 稀疏二叉树:非上面两种二叉树,不适合用数组实现,浪费空间。
  • 二叉搜索树(二叉排序树):左子树所有节点小于根节点,右子树所有节点大于根节点,左右子树也是二叉搜索树。
    • 均匀 O(logN)
    • 不均匀O(N),需要自平衡

遍历

  1. 前序遍历(深度优先):根->左->右
  2. 中序遍历(深度优先):左->根->右
  3. 后序遍历(深度优先):左->右->根
  4. 层序遍历(广度优先):层1->左->右->…->层n,前序+队列可以实现
// 遍历框架
func traverse(node){
  if node == nil{
    return
  }
  //前序位置
  traverse(node.left)
  //中序位置
  traverse(node.rigtht)
  //后序位置
}

// 层序遍历框架
func traverse(node){
  queue:=newQueue()
  queue.put(node)
  for ;len(queue)!=nil;{
    node = queue.pop()
    // 层序遍历位置
    if node.left!=nil {
      queue.put(node.left)
    }
    if node.rigtht!=nil {
      queue.put(node.rigtht)
    }
  }
} 
简易实现

数组

package test

import "fmt"

type arrayTree []interface{}

func NewArrayTree(data []interface{}) *arrayTree {
	a := &arrayTree{}
	*a = append(*a, data...)
	return a
}

func (a *arrayTree) traverse(index int)  {
	if index >len(*a)-1{
		return
	}
	fmt.Printf("前序 %v \n",(*a)[index])
	// 左节点
	a.traverse(2*index+1)
	fmt.Printf("中序 %v \n",(*a)[index])
	// 右节点
	a.traverse(2*index+2)
	fmt.Printf("后序 %v \n",(*a)[index])
}

func (a *arrayTree) traverse2(index int)  {
	if index >len(*a)-1{
		return
	}
	m:=NewLinkQueue()
	m.Push(index)
	for ;m.data!=nil;{
		if v ,ok:=m.Pop().(int);ok{
			fmt.Printf("层序遍历 %v \n",(*a)[v])
			if v*2+1<len(*a){
				m.Push(v*2+1)
			}
			if v*2+2<len(*a){
				m.Push(v*2+2)
			}
		}
	}
}


func TestNewArrayTree(t *testing.T) {
	tree :=NewArrayTree([]interface{}{1,2,3,4,5,6,7,8,9})
	tree.traverse(0)
  tree.traverse2(0)
}

/*
=== RUN   TestNewArrayTree
前序 1
前序 2
前序 4
前序 8
前序 9
前序 5
前序 3
前序 6
前序 7
--- PASS: TestNewArrayTree (0.00s)
PASS

Process finished with exit code 0

=== RUN   TestNewArrayTree
中序 8
中序 4
中序 9
中序 2
中序 5
中序 1
中序 6
中序 3
中序 7
--- PASS: TestNewArrayTree (0.00s)
PASS

Process finished with exit code 0

=== RUN   TestNewArrayTree
后序 8
后序 9
后序 4
后序 5
后序 2
后序 6
后序 7
后序 3
后序 1
--- PASS: TestNewArrayTree (0.00s)
PASS

Process finished with exit code 0

=== RUN   TestNewArrayTree
层序遍历 1 
层序遍历 2 
层序遍历 3 
层序遍历 4 
层序遍历 5 
层序遍历 6 
层序遍历 7 
层序遍历 8 
层序遍历 9 
--- PASS: TestNewArrayTree (0.00s)
PASS

Process finished with exit code 0
*/

链表

type LinkTree struct {
	data interface{}
	left *LinkTree
	right *LinkTree
}

func NewLinkTree(data []interface{},index int) *LinkTree {
	if len(data)==0 || index > len(data)-1{
		return nil
	}
	node := &LinkTree{
		data:  data[index],
		left:  nil,
		right: nil,
	}
	node.left = NewLinkTree(data,index*2+1)
	node.right = NewLinkTree(data,index*2+2)
	return node
}

func (a *LinkTree) traverse(node *LinkTree)  {
	if node == nil{
		return
	}
	//fmt.Printf("前序 %v \n",node.data)
	// 左节点
	a.traverse(node.left)
	//fmt.Printf("中序 %v \n",node.data)
	// 右节点
	a.traverse(node.right)
	fmt.Printf("后序 %v \n",node.data)
}

func (a *LinkTree) traverse2(node *LinkTree)  {
	if node == nil{
		return
	}
	m:=NewLinkQueue()
	m.Push(node)
	for ;m.data!=nil;{
		if v ,ok:=m.Pop().(*LinkTree);ok{
			fmt.Printf("层序遍历 %v \n",v.data)
			if v.left!=nil{
				m.Push(v.left)
			}
			if v.right!=nil{
				m.Push(v.right)
			}
		}
	}
}

func TestNewLinkTree(t *testing.T) {
	tree :=NewLinkTree([]interface{}{1,2,3,4,5,6,7,8,9},0)
	tree.traverse(tree)
  tree.traverse2(tree)
}

/*
=== RUN   TestNewLinkTree
前序 1
前序 2
前序 4
前序 8
前序 9
前序 5
前序 3
前序 6
前序 7
--- PASS: TestNewLinkTree (0.00s)
PASS

Process finished with exit code 0
*/

/*
=== RUN   TestNewLinkTree
中序 8
中序 4
中序 9
中序 2
中序 5
中序 1
中序 6
中序 3
中序 7
--- PASS: TestNewLinkTree (0.00s)
PASS

Process finished with exit code 0
*/

/*
=== RUN   TestNewLinkTree
后序 8
后序 9
后序 4
后序 5
后序 2
后序 6
后序 7
后序 3
后序 1
--- PASS: TestNewLinkTree (0.00s)
PASS

Process finished with exit code 0

=== RUN   TestNewLinkTree
层序遍历 1 
层序遍历 2 
层序遍历 3 
层序遍历 4 
层序遍历 5 
层序遍历 6 
层序遍历 7 
层序遍历 8 
层序遍历 9 
--- PASS: TestNewLinkTree (0.00s)
PASS
*/

二叉堆

本质上是完全二叉树,根节点是堆顶,根节点为最大值最大堆,反之最小堆。
操作描述时间复杂度
插入从最后位置插入,上浮(平均是层数一半)O(log(N))
删除从堆顶删除,下沉(平均是层数一半)O(log(N))
构建所有非叶子节点下沉O(N)
简易实现

数组

package test

type arrayHeap []int

func NewArrayHeap(arr []int) *arrayHeap {
	h := arrayHeap(arr)
	for i := (len(arr) - 2) / 2; i >= 0; i-- {
		h.adjustDown(i, len(arr))
	}
	return &h
}

func (h *arrayHeap) Push(v int) {
	*h = append(*h, v)
	h.adjustUp()
}

func (h *arrayHeap) Pop() int {
	l := len([]int(*h))
	r := (*h)[0]
	if l > 1 {
		(*h)[l-1], (*h)[0] = (*h)[0], (*h)[l-1]
		*h = (*h)[:l-1]
		h.adjustDown(0, l-1)
	} else {
		*h = make([]int, 0)
	}
	return r
}

func (h *arrayHeap) adjustUp() {
	childIndex := len([]int(*h)) - 1
	parentIndex := (childIndex - 1) / 2
	for childIndex > 0 && (*h)[childIndex] < (*h)[parentIndex] {
		(*h)[childIndex], (*h)[parentIndex] = (*h)[parentIndex], (*h)[childIndex]
		childIndex = parentIndex
		parentIndex = (childIndex - 1) / 2
	}
}

func (h *arrayHeap) adjustDown(parentIndex int, l int) {
	childIndex := 2*parentIndex + 1
	for childIndex < l {
		if childIndex+1 < l && (*h)[childIndex+1] < (*h)[childIndex] {
			childIndex++
		}
		if (*h)[parentIndex] < (*h)[childIndex] {
			break
		}
		(*h)[childIndex], (*h)[parentIndex] = (*h)[parentIndex], (*h)[childIndex]
		parentIndex = childIndex
		childIndex = 2*parentIndex + 1
	}
}

func TestNewArrayHeap(t *testing.T) {
	h := NewArrayHeap([]int{9,3,7,4,5,2,8,6,1})
	fmt.Printf("%v \n",h)
	i:=h.Pop()
	fmt.Printf("%v \n",h)
	h.Push(i)
	fmt.Printf("%v \n",h)
}

/*
=== RUN   TestNewArrayHeap
&[1 3 2 4 5 7 8 6 9] 
&[2 3 7 4 5 9 8 6] 
&[1 2 7 3 5 9 8 6 4] 
--- PASS: TestNewArrayHeap (0.00s)
PASS

Process finished with exit code 0
*/

优先队列

最大堆/最小堆结合队列FIFO特性,保证出队列的都是最大值/最小值

图由有限顶点(vertex),有限边(edge)集合组成
1.有向图      边存在方向。 入节点数目 入度;出节点数目 出度
2.无向图      边不存在方向
3.带权图      边存在权重
4.稀疏/稠密图  e<nlog2n
实现优点缺点
邻接矩阵边和顶点兼顾,可以使用矩阵运算浪费空间
邻接表存储空间更优,更接近树结构无法兼顾不存在边

遍历

  1. 深度优先遍历:首节点->相邻节点
  2. 广度优先遍历:首节点->所有相邻节点-> 下一层所有相邻节点 。深度遍历+队列实现
// 遍历框架
func DFS(*graph){
  visited := make(map[*graph]bool)
  dfs(*graph,visited)
}

// 深度优遍历
func dfs(*gragh,visited){
  if gragh == nil{
    return
  }
  visited[*graph] = true
  // dfs遍历位置
  for edge:=range graph.edges{
    if !visited[*edge]{
      dfs(*edge)
    }
  }
}


// 遍历框架
func BFS(*graph){
  visited := make(map[*graph]bool)
  bfs(*graph,visited)
}

// 广度优先遍历
func bfs(*graph,visited){
  if gragh == nil{
    return
  }
  visited[*graph] = true
  queue:=newQueue()
  queue.put(gragh)
  for queue.isEmpty() {
    node = queue.pop()
    // bfs遍历位置
    for edge:=range node.edges{
      if !visited[*edge]{
          visited[*edge] = true
          queue.put(edge)
      }
 		}
  }
} 

简易实现

邻接表

package test

import "fmt"

type graph struct {
	key string
	edges map[string]*graph
}


func NewGraph(ns []string,edges [][2]string) *graph {
	g:=&graph{edges:make(map[string]*graph)}
	for _,n :=range ns{
		if _,ok:=g.edges[n];!ok{
			g.edges[n] = &graph{
				key:   n,
				edges: make(map[string]*graph),
			}
		}
	}
	for _,edge:=range edges{
		g.edges[edge[0]].edges[edge[1]]=g.edges[edge[1]]
	}
	return g
}

// 遍历框架
func DFS(g *graph){
	visited := make(map[*graph]bool)
	g.dfs(visited)
}

// 深度优遍历
func (g *graph)dfs(visited map[*graph]bool){
	if g == nil{
		return
	}
	visited[g] = true
	// dfs遍历位置
	fmt.Printf("dfs %v \n",g.key)
	for _,edge:=range g.edges{
		if !visited[edge]{
			edge.dfs(visited)
		}
	}
}


// 遍历框架
func BFS(g *graph){
	visited := make(map[*graph]bool)
	g.bfs(visited)
}

// 广度优先遍历
func (g *graph)bfs(visited map[*graph]bool){
	if g == nil{
		return
	}
	visited[g] = true
	queue:=NewArrayQueue()
	queue.Push(g)
	for len(queue.data)!=0 {
		if node,ok := queue.Pop().(*graph);ok{
			// bfs遍历位置
			fmt.Printf("bfs %v \n",node.key)
			for _,edge:=range node.edges{
				if !visited[edge]{
					visited[edge] = true
					queue.Push(edge)
				}
			}
		}else{
			break
		}

	}
}

func (g *graph)Print(m map[*graph]bool)  {
	if g.key !=""{
		fmt.Printf("%v->",g.key)
	}
	for _, e := range g.edges {
		if _,ok:=m[e];!ok{
            e.Print(m)
            m[e]=true
		}
		if g.key !=""{
			fmt.Printf("%v->",e.key)
		}
	}
	fmt.Printf("\n")
}

func TestNewGraph(t *testing.T) {
	g:=NewGraph([]string{"1","2","3","4","5","6"},[][2]string{[2]string{"1","2"},[2]string{"1","3"},[2]string{"2","4"},[2]string{"2","5"}})
	g.Print(make(map[*graph]bool))
	DFS(g)
	BFS(g)
}

/*
=== RUN   TestNewGraph
5->
6->
1->2->4->
4->5->
2->3->
3->

dfs  
dfs 2 
dfs 4 
dfs 5 
dfs 3 
dfs 6 
dfs 1 
bfs  
bfs 1 
bfs 2 
bfs 3 
bfs 4 
bfs 5 
bfs 6 
--- PASS: TestNewGraph (0.00s)
PASS

Process finished with exit code 0
*/

邻接矩阵

type graph2 struct {
	data map[string]map[string]bool
}

func NewGraph2(ns []string,edges [][2]string) *graph2 {
	g:=&graph2{data:make(map[string]map[string]bool)}
	for _,n :=range ns{
		g.data[n]=make(map[string]bool)
	}
	for _,edge:=range edges{
		g.data[edge[0]][edge[1]]=true
	}
	return g
}

// 遍历框架
func DFS2(g *graph2){
	visited := make(map[string]bool)
	for node, edges := range g.data {
		if !visited[node] {
			g.dfs(node, edges, visited)
		}
	}
}

// 深度优遍历
func (g *graph2)dfs(key string,edges map[string]bool,visited map[string]bool){
	visited[key] = true
	// dfs遍历位置
	fmt.Printf("dfs %v \n",key)
	for k,f:=range edges{
		if !visited[k]&&f{
			g.dfs(k,g.data[k],visited)
		}
	}
}


// 遍历框架
func BFS2(g *graph2){
	visited := make(map[string]bool)
	for node, _ := range g.data {
		if !visited[node] {
			g.bfs(node, visited)
		}
	}
}

// 广度优先遍历
func (g *graph2)bfs(key string,visited map[string]bool){
	queue:=NewArrayQueue()
	visited[key] = true
	queue.Push(key)
	for len(queue.data)!=0 {
		if node,ok := queue.Pop().(string);ok{
			// bfs遍历位置
			fmt.Printf("bfs %v \n",node)
			for k,f:=range g.data[key]{
				if !visited[k]&&f{
					visited[k] = true
					queue.Push(k)
				}
			}
		}else{
			break
		}

	}
}


func (g *graph2)Print(m map[string]bool)  {
	for key, edges := range g.data {
		fmt.Printf("%v: \n",key)
		for e, f := range edges {
			if _,ok:=m[e];!ok&&f{
				fmt.Printf("%v - >%v \n",key,e)
				m[e]=true
			}
		}
		fmt.Printf("\n")
	}

}

func TestNewGraph(t *testing.T) {
	g:=NewGraph2([]string{"1","2","3","4","5","6"},[][2]string{[2]string{"1","2"},[2]string{"1","3"},[2]string{"2","4"},[2]string{"2","5"}})
	g.Print(make(map[string]bool))
	DFS2(g)
	BFS2(g)
}

/*
=== RUN   TestNewGraph
6: 

1: 
1 - >2 
1 - >3 

2: 
2 - >4 
2 - >5 

3: 

4: 

5: 
dfs 4 
dfs 5 
dfs 6 
dfs 1 
dfs 2 
dfs 3 
bfs 3 
bfs 4 
bfs 5 
bfs 6 
bfs 1 
bfs 2 
--- PASS: TestNewGraph (0.00s)
PASS

Process finished with exit code 0
*/
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mars'Ares

请我喝杯咖啡吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值