Golang achieve large root heap / stack small root / heap interfaces

heap

In the go, it is not like the java class provides a container can be used directly, but rather to provide an interface, you need to implement this interface in ways to customize a stack / collection, although it also increases flexibility, but also to increase the programmer's burden (and have to read the source code, or do not know how to call)

container/heap

heap Interface Definition

In heap.go defined by the interface as follows:

type Interface interface {
	sort.Interface
	Push(x interface{}) // add x as element Len()
	Pop() interface{}   // remove and return element Len() - 1.
}

It found that in addition to Push and Pop methods also need to implement the interface sort, sort the interface is defined as follows:

// Package sort provides primitives for sorting slices and user-defined
// collections.
package sort

// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
type Interface interface {
	// Len is the number of elements in the collection.
	Len() int
	// Less reports whether the element with
	// index i should sort before the element with index j.
	Less(i, j int) bool
	// Swap swaps the elements with indexes i and j.
	Swap(i, j int)
}

As the realization heap needs to implement its interface, so the function interface requires a clear written comments to facilitate the completion of the programmer, then one by one we analyze how the various functions should be completed.

Interface

heap body

//我们选取切片作为容器,所以定义类型intHeap为整数切片
type IntHeap []int
//在操作时都使用指针类型进行操作,防止值传递
h := &IntHeap{2, 1, 5}

Sort

Method three sort interface need to implement specific implementation is as follows:

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] }

Here Less function can decide whether big or small heap root root stack, which means if true i before j.

Push

push method, which is required to achieve official comment function written in a very simple, in fact, is really quite simple.

The final array can be added to x, the codes are as follows:

func (h *IntHeap) Push(x interface{}) {
	// Push and Pop use pointer receivers because they modify the slice's length,
	// not just its contents.
	*h = append(*h, x.(int))
}

You may be wondering if this was only achieved Push function, and there is no guarantee the nature of the heap ah, you just put this number into the final array. In fact, this is the official order to avoid writing too much code do we design, we are actually called when the Push heap.Push (H, 3) , which is a function of the heap.go, which is embodied as:

func Push(h Interface, x interface{}) {
	h.Push(x)
	up(h, h.Len()-1)
}
func up(h Interface, j int) {
	for {
		i := (j - 1) / 2 // parent
		if i == j || !h.Less(j, i) {
			break
		}
		h.Swap(i, j)
		j = i
	}
}

Floating up operations carried out by official functions.

Pop

func (h *IntHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

From the official comments, we just need to slice it becomes [0: n-1] can then get is how to ensure the minimum / maximum value of it, in view heap.go Pop function can be seen:

func Pop(h Interface) interface{} {
	n := h.Len() - 1
	h.Swap(0, n)
	down(h, 0, n)
	return h.Pop()
}
func down(h Interface, i0, n int) bool {
	i := i0
	for {
		j1 := 2*i + 1
		if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
			break
		}
		j := j1 // left child
		if j2 := j1 + 1; j2 < n && h.Less(j2, j1) {
			j = j2 // = 2*i + 2  // right child
		}
		if !h.Less(j, i) {
			break
		}
		h.Swap(i, j)
		i = j
	}
	return i > i0
}

Rootlets stack implementation example

In fact, the official has been given in the package specification implementations:

// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This example demonstrates an integer heap built using the heap interface.
package heap_test

import (
	"container/heap"
	"fmt"
)

// An IntHeap is a min-heap of ints.
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 and Pop use pointer receivers because they modify the slice's length,
	// not just its contents.
	*h = append(*h, x.(int))
}

func (h *IntHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

// This example inserts several ints into an IntHeap, checks the minimum,
// and removes them in order of priority.
func Example_intHeap() {
	h := &IntHeap{2, 1, 5}
	heap.Init(h)
	heap.Push(h, 3)
	fmt.Printf("minimum: %d\n", (*h)[0])
	for h.Len() > 0 {
		fmt.Printf("%d ", heap.Pop(h))
	}
	// Output:
	// minimum: 1
	// 1 2 3 5
}

The size of the root heap implementations

But if we also need large and small root root heap heap, do you want to achieve twice or define it twice? In fact due to the heap to provide enough flexible interface, we can make some changes according to their own needs, but also their own package structure to achieve such a priority queue, and so on. Here we show you how to complete large and small heap root root function with a heap data structure based on property values

type IntHeap struct {
	heap []int
	//true是小根堆,false是大根堆
	bool
}


func (h IntHeap) Len() int           { return len(h.heap) }
func (h IntHeap) Less(i, j int) bool {
	if h.bool{
		return h.heap[i] < h.heap[j]
	}else{
		return h.heap[i] > h.heap[j]
	}

} // 小根堆  > 大根堆
func (h IntHeap) Swap(i, j int)      { h.heap[i], h.heap[j] = h.heap[j], h.heap[i] }

func (h *IntHeap) Push(x interface{}) {
	h.heap = append(h.heap, x.(int))
}

func (h *IntHeap) Pop() interface{} {
	old := h
	n := len(old.heap)
	x := old.heap[n-1]
	h.heap = old.heap[0 : n-1]
	return x

}

When bool is true, it is a small heap root, otherwise it is a large root heap.

Published 16 original articles · won praise 3 · Views 1351

Guess you like

Origin blog.csdn.net/weixin_40631132/article/details/105208272