考虑优先堆的一种应用场景——按优先级的任务调度队列:每个任务有一个优先级和唯一标号,该调度队列需要具有以下功能:
对于任务,考虑使用类封装,对于一个任务类需要以下特征:
同时需要具有以下方法:
定义了数据结构后,使用2D优先堆实现该优先队列,2D优先堆为完全二叉树,且任意一个节点的值小于其子节点的值。要实现场景中的几种功能,需要以下几种方法:
以上提到了两种另外需要实现的方法:
up.png
如图所示为一个上移方法,当某位置要插入一个比原先优先值小的任务时,可以调用上移方法使插入不破坏2d优先堆的性质,该方法的递归概括有以下几步,输入为待插入位置和待插入数据:
down.png
如图为一个下移方法的例子,当某位置要插入一个比原先优先值大的任务时,可以调用下移方法使其插入不破坏2d优先堆的性质,该方法的递归概括如下所示,输入为带插入位置和待插入数据:
通过接口实现一个打印固定字符串的任务,该任务类的执行打印了结构体中包含的data
字符串。
type PrintWork struct {
Index int
Priority int
data string
}
func (p *PrintWork) Execute() error {
fmt.Println(p.data)
return nil
}
func (p *PrintWork) ChangePriority(NewPriority int) {
p.Priority = NewPriority
}
func NewWork(index int, priorty int, data string) *Work {
return &Work{index, priorty, data}
}
该结构体包括一个长度为17的队列,第一个位置不使用,共16个可用的位置;一个指示下一个位置的int型变量next;一个标记堆容量的变量size
type WorkFIFO struct {
heap [17]Work
next int
size int
}
该结构体构造函数如下:
func NewWorkFIFO() *WorkFIFO {
temp := &WorkFIFO{}
for i := 0; i < 17; i++ {
temp.heap[i] = NewWork(0, 999, "")
}
temp.next = 1
temp.size = 17
return temp
}
上移方法主要用于数据插入和权值修改
func (w *WorkFIFO) UpFlow(data *Work, place int) error {
if place > w.next || place == 0 {
return errors.New("out of index")
} else if place == 1 {
w.heap[1] = data
return nil
} else if data.Priority >= w.heap[place/2].Priority {
w.heap[place] = data
return nil
}
w.heap[place] = w.heap[place/2]
return w.UpFlow(data, place/2)
}
下移方法主要用于数据弹出,删除和权值修改
func (w *WorkFIFO) DownFlow(data *Work, place int) error {
if place > w.next || place == 0 {
return errors.New("out of index")
} else if place*2 >= w.next {
w.heap[place] = data
return nil
} else if data.Priority <= w.heap[w.getMinSon(place)].Priority {
w.heap[place] = data
return nil
}
nextPlace := w.getMinSon(place)
w.heap[place] = w.heap[nextPlace]
return w.DownFlow(data, nextPlace)
}
func (w *WorkFIFO) getMinSon(place int) int {
if 2*place+1 >= w.next {
return 2 * place
} else if w.heap[2*place].Priority > w.heap[2*place+1].Priority {
return 2*place + 1
} else {
return 2 * place
}
}
插入方法将新的任务插入优先队列中,步骤为:
next
属性标记的位置next
标记的位置+1func (w *WorkFIFO) WorkInsert(data *Work) error {
if w.next > w.size {
return errors.New("heap is full")
}
err := w.UpFlow(data, w.next)
w.next++
return err
}
弹出方法为将优先级最高的任务弹出队列,步骤为:
next
-1的数据next
标记位置-1,弹出原根节点位置数据func (w *WorkFIFO) WorkPop() (*Work, error) {
if w.next <= 1 {
return nil, errors.New("heap is empty")
}
thisWork := w.heap[1]
w.next--
err := w.DownFlow(w.heap[w.next], 1)
return thisWork, err
}
删除方法为将指定任务(通过任务标号制定)从队列中删除,步骤为:
next
-1指向的任务插入待删除任务的位置并调用下移方法维持优先堆限制next
标记-1func (w *WorkFIFO) WorkDelete(index int) (*Work, error) {
for i := 1; i < w.next; i++ {
if w.heap[i].Index == index {
temp := w.heap[i]
err := w.DownFlow(w.heap[w.next-1], i)
w.next--
return temp, err
}
}
return nil, errors.New("work undefined")
}
修改优先级为修改指定任务(通过任务标号指定)的优先级,步骤为:
func (w *WorkFIFO) ChangePriority(index int, newPriority int) error {
for i := 0; i < w.next; i++ {
if w.heap[i].Index == index {
if w.heap[i].Priority > newPriority {
w.heap[i].ChangePriority(newPriority)
w.UpFlow(w.heap[i], i)
} else {
w.heap[i].ChangePriority(newPriority)
w.DownFlow(w.heap[i], i)
}
}
}
return errors.New("work undefined")
}