github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/algorithm/datastructures/minheap/heap.go (about)

     1  // go sdk中的container包下已经有了heap堆的结构,此处实现按照java的思路实现
     2  package minheap
     3  
     4  //比较大小 相等返回0 , 当前这个数小返回负数 ,当前数大返回正数
     5  type CompareFunc func(v1, v2 interface{}) int
     6  
     7  type Heap struct {
     8  	data    []interface{} //存储的数据
     9  	cmpFunc CompareFunc   // 比较函数
    10  }
    11  
    12  func NewHeap(f CompareFunc) *Heap {
    13  	return &Heap{cmpFunc: f}
    14  }
    15  
    16  /*
    17  heapifyd 是时间复杂度是 O(n) 级别
    18  排序复杂度是 O(nlogn) , 非稳定性排序
    19  */
    20  func (h *Heap) Heapify(d ...interface{}) {
    21  	// 思路: 跳过叶子节点,对最小的父节点进行下沉操作,一直到根部
    22  	// 最小的叶子节点的服节点就 parent(len()-1)
    23  	if d == nil || len(d) == 0 {
    24  		return
    25  	}
    26  	h.data = make([]interface{}, len(d))
    27  	copy(h.data, d)
    28  	for i := parent(h.Len() - 1); i >= 0; i-- {
    29  		h.siftDown(i)
    30  	}
    31  }
    32  
    33  func (h *Heap) Len() int {
    34  	if h.data == nil {
    35  		return 0
    36  	}
    37  	return len(h.data)
    38  }
    39  
    40  func (h *Heap) Poll() interface{} {
    41  	//1. 取出队头元素
    42  	//2. 将对尾元素,移到顶部
    43  	//3. 移除尾部
    44  	//4. 对头部下沉
    45  	if h.Len() == 0 {
    46  		return nil
    47  	}
    48  	ret := h.Peek()
    49  	h.swap(0, h.Len()-1)
    50  	h.data = h.data[:h.Len()-1]
    51  	h.siftDown(0)
    52  	return ret
    53  }
    54  
    55  // 移除对应的元素
    56  func (h *Heap) Remove(e interface{}, eqFunc func(e, b interface{}) bool) interface{} {
    57  	// 1 找到对应元素
    58  	var find interface{}
    59  	var fi int
    60  	for i := 0; i < h.Len(); i++ {
    61  		if eqFunc(e, h.data[i]) {
    62  			find = h.data[i]
    63  			fi = i
    64  			break
    65  		}
    66  	}
    67  	if find == nil {
    68  		//没有找到
    69  		return nil
    70  	} else {
    71  		// 与最后一个值进行替换
    72  		h.swap(fi, h.Len()-1)
    73  		h.data = h.data[:h.Len()-1] //移除最后一个
    74  		// 下沉下标
    75  		h.siftDown(fi)
    76  		return find
    77  	}
    78  }
    79  
    80  func (h *Heap) Peek() interface{} {
    81  	if h.Len() == 0 {
    82  		return nil
    83  	}
    84  	return h.data[0]
    85  }
    86  
    87  func (h *Heap) Add(e interface{}) {
    88  	h.data = append(h.data, e)
    89  	h.siftUp(h.Len() - 1)
    90  }
    91  
    92  // 上浮
    93  func (h *Heap) siftUp(i int) {
    94  	ci := i
    95  	pi := parent(ci)
    96  	for ci > 0 && h.cmpFunc(h.data[ci], h.data[pi]) < 0 {
    97  		h.swap(pi, ci)
    98  		ci = pi
    99  		pi = parent(ci)
   100  	}
   101  }
   102  
   103  // 下沉
   104  func (h *Heap) siftDown(i int) {
   105  	ci := i
   106  	dataLen := h.Len() // 数据大小
   107  	for leftChild(ci) < dataLen {
   108  		mi := leftChild(ci)                                            //  较小值的孩子的下标
   109  		if mi+1 < dataLen && h.cmpFunc(h.data[mi], h.data[mi+1]) > 0 { // mi + 1 表示右边下标
   110  			// 右孩子的值小些
   111  			mi += 1
   112  		}
   113  		if h.cmpFunc(h.data[ci], h.data[mi]) <= 0 {
   114  			// 已经比孩子小了不用下沉
   115  			break
   116  		}
   117  		h.swap(mi, ci)
   118  		ci = mi
   119  	}
   120  }
   121  
   122  func (h *Heap) swap(i, j int) {
   123  	h.data[i], h.data[j] = h.data[j], h.data[i]
   124  }
   125  
   126  // 返回完全二叉堆的数组表示中,一个索引所表示的元素的父亲节点的索引
   127  func parent(index int) int {
   128  	if index <= 0 {
   129  		return -1 //表示没有父节点索引
   130  	}
   131  	return (index - 1) / 2
   132  }
   133  
   134  // 左孩子下标
   135  func leftChild(index int) int {
   136  	return index*2 + 1
   137  }
   138  
   139  // 右孩子下标
   140  func rightChild(index int) int {
   141  	return index*2 + 2
   142  }