作者:wp_725133 | 来源:互联网 | 2023-09-08 18:02
在Go语言中我们可以直接使用container标准库完成链表和堆操作,非常方便,我们不需要自己去实现这些方法,本文向大家介绍container库的使用方法,希望对你有帮助。一、双向
在 Go 语言中我们可以直接使用 container 标准库完成链表和堆操作,非常方便,我们不需要自己去实现这些方法,本文向大家介绍 container 库的使用方法,希望对你有帮助。
一、双向链表 1. Element Element 中保存了链表的所有信息,我们来看一下源码:
type Element struct { next, prev * Elementlist * ListValue interface { } } type List struct { root Element len int }
2. 生成一个链表 生成一个链表很简单,我们通过下面的函数可以获得一个 List 对象的指针:
func New() *List
然后我们对链表进行初始化:
func (l *List) Init() *List
Init会清空 List 链表中的数据,生成一个全新的链表,因此我们也可以使用 Init 方法来清空一个链表
。
3. 链表的增删改查 插入链表
func ( l * List) PushFront ( v interface { } ) * Elementfunc ( l * List) PushFrontList ( other * List) func ( l * List) PushBack ( v interface { } ) * Elementfunc ( l * List) PushBackList ( other * List) func ( l * List) InsertBefore ( v interface { } , mark * Element) * Elementfunc ( l * List) InsertAfter ( v interface { } , mark * Element) * Element
查询链表
func ( e * Element) Next ( ) * Elementfunc ( e * Element) Prev ( ) * Elementfunc ( l * List) Front ( ) * Elementfunc ( l * List) Back ( ) * Element
删除链表
func ( l * List) Remove ( e * Element) interface { }
修改链表
func ( l * List) MoveToFront ( e * Element) func ( l * List) MoveToBack ( e * Element) func ( l * List) MoveBefore ( e, mark * Element) func ( l * List) MoveAfter ( e, mark * Element)
其他功能
func ( l * List) Len ( ) int
4. 我们实现一个反向链表的功能 题目描述: 反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
func reverseList ( l * list. List) * list. List { head := l. Front ( ) for head. Next ( ) != nil { if head. Next ( ) == nil { break } l. MoveToFront ( head. Next ( ) ) } return l}
二、环形链表 1. Ring type Ring struct { next, prev * RingValue interface { } }
2. 环形链表的初始化 我们可以通过 New 函数初始化一个有 n 个节点的环形链表
func New(n int) *Ring
3. 环形链表管理 查看链表长度
func ( r * Ring) Len ( ) int
返回链表下一个元素
func ( r * Ring) Next ( ) * Ring
返回链表的上一个元素
func ( r * Ring) Prev ( ) * Ring
返回指定位置的元素
func ( r * Ring) Move ( n int ) * Ring
连接两个环形链表
func ( r * Ring) Link ( s * Ring) * Ring
删除环形链表中的元素
func ( r * Ring) Unlink ( n int ) * Ring
管理链表中的元素
func ( r * Ring) Do ( f func ( interface { } ) )
4. 举个例子 计算环形链表上所有值的和:
package mainimport ( "container/ring" "fmt" ) type SumInt struct { Value int } func ( s * SumInt) add ( i interface { } ) { s. Value += i. ( int ) } func main ( ) { r := ring. New ( 10 ) for i := 0 ; i < 10 ; i++ { r. Value = ir = r. Next ( ) } sum := SumInt{ } r. Do ( sum. add) fmt. Println ( sum. Value) }
三、堆 堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
1. 构建堆需要满足的条件 container/heap 标准库中定义了对(最小)堆进行操作的接口:
type Interface interface { sort. InterfacePush ( x interface { } ) Pop ( ) interface { } } type Interface interface { Len ( ) int Less ( i, j int ) bool Swap ( i, j int ) }
任何实现了本接口的类型都可以用于构建最小堆。最小堆,是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于其左子节点和右子节点的值。
最小堆可以通过heap.Init建立,数据是递增顺序或者空的话也是最小堆。最小堆的约束条件是:
!h.Less(j, i) for 0 <= i
2. 最小堆管理 插入元素
func Push ( h Interface, x interface { } )
删除堆中最小元素
func Pop ( h Interface) interface { }
删除堆中第一个元素
func Remove ( h Interface, i int ) interface { }
修改指定的元素
func Fix ( h Interface, i int )
3. 通过最小堆实现排序 package mainimport ( "container/heap" "fmt" ) type myHeap [ ] int func ( h * myHeap) Len ( ) int { return len ( * h) } func ( h * myHeap) Swap ( i, j int ) { ( * h) [ i] , ( * h) [ j] = ( * h) [ j] , ( * h) [ i] } func ( h * myHeap) Less ( i, j int ) bool { return ( * h) [ i] < ( * h) [ j] } func ( h * myHeap) Push ( v interface { } ) { * h = append ( * h, v. ( int ) ) } func ( h * myHeap) Pop ( ) ( v interface { } ) { * h, v = ( * h) [ : len ( * h) - 1 ] , ( * h) [ len ( * h) - 1 ] return } func ( h myHeap) printHeap ( ) { n := 1 levelCount := 1 for n <= h. Len ( ) { fmt. Println ( h[ n- 1 : n- 1 + levelCount] ) n += levelCountlevelCount *= 2 } } func main ( ) { data := [ 7 ] int { 13 , 12 , 45 , 23 , 11 , 9 , 20 } aHeap := new ( myHeap) for i := 0 ; i < len ( data) ; i++ { aHeap. Push ( data[ i] ) } aHeap. printHeap ( ) heap. Init ( aHeap) fmt. Println ( "排序后: " ) aHeap. printHeap ( ) }
四、单链表 官方的标准库中并没有实现单链表,这里我们来写一个单链表。
1. 定义 List 结构体 type Node struct { Value interface { } Next * Node } type List struct { Head * Node Length int }
2. 实现链表的增删改查 func ( l * List) Init ( ) * List { l. Head = new ( Node) l. Length = 0 return l} func New ( ) * List { return new ( List) . Init ( ) } func ( l * List) Len ( ) int { return l. Length} func ( l * List) Insert ( i int , value interface { } ) { if l. Len ( ) < i- 1 { return } head := l. Headfor ; i > 1 ; i-- { head = head. Next} Next := new ( Node) l. Length++ Next. Value = valueif head. Next == nil { head. Next = Nextreturn } Next. Next = head. Nexthead. Next = Nextreturn } func ( l * List) Delete ( i int ) { if l. Len ( ) < i { return } head := l. Headfor ; i > 1 ; i-- { head = head. Next} l. Length-- if head. Next == nil { head. Next = nil return } head. Next = head. Next. Nextreturn } func ( l * List) Get ( i int ) interface { } { if l. Len ( ) < i { return nil } head := l. Headfor ; i > 1 ; i-- { head = head. Next} return head. Next. Value} func ( l * List) Pop ( ) { head := l. Headnext := head. Nextfor next. Next != nil { head = head. Nextnext = head. Next} head. Next = nil l. Length-- return } func ( l * List) Push ( value interface { } ) { head := l. Headfor head. Next != nil { head = head. Next} head. Next = new ( Node) head. Next. Value = valuel. Length++ return } func ( l * List) Print ( ) { head := l. Headfor head. Next != nil { head = head. Nextfmt. Print ( head. Value, " " ) } fmt. Println ( ) }
3. 测试 func main ( ) { L := New ( ) for i := 1 ; i < 6 ; i++ { L. Push ( i) } fmt. Print ( " 初始化链表: " ) L. Print ( ) fmt. Print ( " 在链表末尾添加10: " ) L. Push ( 10 ) L. Print ( ) fmt. Print ( " 删除链表末尾元素: " ) L. Pop ( ) L. Print ( ) fmt. Print ( "查看第三个节点的值: " ) fmt. Println ( L. Get ( 3 ) ) fmt. Print ( "在第三个节点插入30: " ) L. Insert ( 3 , 30 ) L. Print ( ) fmt. Print ( "删除第三个节点的值: " ) L. Delete ( 3 ) L. Print ( ) }
Output:
$ go run main.go初始化链表: 1 2 3 4 5在链表末尾添加10: 1 2 3 4 5 10删除链表末尾元素: 1 2 3 4 5 查看第三个节点的值: 3 在第三个节点插入30: 1 2 30 3 4 5 删除第三个节点的值: 1 2 3 4 5