switch to 0 based index
This commit is contained in:
		
							parent
							
								
									f85fd63c74
								
							
						
					
					
						commit
						afc077c8a6
					
				
					 2 changed files with 38 additions and 28 deletions
				
			
		|  | @ -1,6 +1,5 @@ | ||||||
| package priority_queue | package priority_queue | ||||||
| 
 | 
 | ||||||
| // TODO: change name to "keyed priority queue" |  | ||||||
| type IndexPriorityQueue[T any] interface { | type IndexPriorityQueue[T any] interface { | ||||||
| 	top() T                 // get item with biggest priority | 	top() T                 // get item with biggest priority | ||||||
| 	topKey() int            // get key of an item with biggest priority | 	topKey() int            // get key of an item with biggest priority | ||||||
|  | @ -23,7 +22,9 @@ type indexPriorityQueue[T any] struct { | ||||||
| 	pq []int | 	pq []int | ||||||
| 	// "reverse" for pq. Maps item key to priority | 	// "reverse" for pq. Maps item key to priority | ||||||
| 	// qp[key] = priority index, qp[pq[key]] = pq[qp[key]] = key | 	// qp[key] = priority index, qp[pq[key]] = pq[qp[key]] = key | ||||||
| 	qp   []int | 	qp []int | ||||||
|  | 	// "less" function. Depending on desired order first element | ||||||
|  | 	// not necessary less than a second | ||||||
| 	less func(T, T) bool | 	less func(T, T) bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -31,10 +32,9 @@ type indexPriorityQueue[T any] struct { | ||||||
| // TODO: can we construct queue without bounded index size? | // TODO: can we construct queue without bounded index size? | ||||||
| func NewIPQ[T any](less func(T, T) bool, indexSize int) IndexPriorityQueue[T] { | func NewIPQ[T any](less func(T, T) bool, indexSize int) IndexPriorityQueue[T] { | ||||||
| 	n := 0 | 	n := 0 | ||||||
| 	// TODO: switch to 0 based index | 	items := make([]T, indexSize) | ||||||
| 	items := make([]T, indexSize+1) | 	pq := make([]int, indexSize) | ||||||
| 	pq := make([]int, indexSize+1) | 	qp := make([]int, indexSize) | ||||||
| 	qp := make([]int, indexSize+1) |  | ||||||
| 
 | 
 | ||||||
| 	for i := range qp { | 	for i := range qp { | ||||||
| 		qp[i] = -1 | 		qp[i] = -1 | ||||||
|  | @ -48,42 +48,35 @@ func NewIPQ[T any](less func(T, T) bool, indexSize int) IndexPriorityQueue[T] { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (q *indexPriorityQueue[T]) top() T { | func (q *indexPriorityQueue[T]) top() T { | ||||||
| 	return q.items[q.pq[1]] | 	return q.items[q.pq[0]] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (q *indexPriorityQueue[T]) topKey() int { | func (q *indexPriorityQueue[T]) topKey() int { | ||||||
| 	return q.pq[1] | 	return q.pq[0] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (q *indexPriorityQueue[T]) insert(key int, item T) { | func (q *indexPriorityQueue[T]) insert(key int, item T) { | ||||||
| 	q.n++ |  | ||||||
| 	q.pq[q.n] = key | 	q.pq[q.n] = key | ||||||
| 	q.qp[key] = q.n | 	q.qp[key] = q.n | ||||||
| 	q.items[key] = item | 	q.items[key] = item | ||||||
| 	q.swim(q.n) | 	q.swim(q.n) | ||||||
|  | 	q.n++ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (q *indexPriorityQueue[T]) remove() T { | func (q *indexPriorityQueue[T]) remove() T { | ||||||
| 	topKey := q.topKey() | 	return q.removeKey(q.topKey()) | ||||||
| 	q.swap(1, q.n) |  | ||||||
| 	q.n-- |  | ||||||
| 	q.sink(1) |  | ||||||
| 	// TODO: need to remove actual item from items array |  | ||||||
| 	// to allow removed item to be GCed |  | ||||||
| 	q.qp[q.pq[q.n+1]] = -1 |  | ||||||
| 	return q.items[topKey] |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (q *indexPriorityQueue[T]) removeKey(key int) T { | func (q *indexPriorityQueue[T]) removeKey(key int) T { | ||||||
| 	pivot := q.qp[key] | 	pivot := q.qp[key] | ||||||
| 	q.swap(pivot, q.n) |  | ||||||
| 	q.n-- | 	q.n-- | ||||||
|  | 	q.swap(pivot, q.n) | ||||||
| 	q.swim(pivot) | 	q.swim(pivot) | ||||||
| 	q.sink(pivot) | 	q.sink(pivot) | ||||||
| 	// TODO: need to remove actual item from items array | 	// TODO: need to remove actual item from items array | ||||||
| 	// to prevent memory leak | 	// to prevent memory leak | ||||||
| 	q.qp[key] = -1 | 	q.qp[key] = -1 | ||||||
| 	q.pq[q.n+1] = -1 | 	q.pq[q.n] = -1 | ||||||
| 	return q.items[key] | 	return q.items[key] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -106,23 +99,40 @@ func (q *indexPriorityQueue[_]) contains(key int) bool { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (q *indexPriorityQueue[T]) sink(parent int) { | func (q *indexPriorityQueue[T]) sink(parent int) { | ||||||
| 	for 2*parent <= q.n { | 
 | ||||||
| 		child := 2 * parent | 	for { | ||||||
| 		if child < q.n && q.less(q.items[q.pq[child]], q.items[q.pq[child+1]]) { | 		child := 2*parent + 1 | ||||||
|  | 
 | ||||||
|  | 		if child >= q.n { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if child+1 < q.n && q.less(q.items[q.pq[child]], q.items[q.pq[child+1]]) { | ||||||
| 			child++ | 			child++ | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		if !q.less(q.items[q.pq[parent]], q.items[q.pq[child]]) { | 		if !q.less(q.items[q.pq[parent]], q.items[q.pq[child]]) { | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		q.swap(parent, child) | 		q.swap(parent, child) | ||||||
|  | 
 | ||||||
| 		parent = child | 		parent = child | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (q *indexPriorityQueue[T]) swim(child int) { | func (q *indexPriorityQueue[T]) swim(child int) { | ||||||
| 	for child > 1 && q.less(q.items[q.pq[child/2]], q.items[q.pq[child]]) { | 	for { | ||||||
| 		q.swap(child/2, child) | 		parent := (child - 1) / 2 | ||||||
| 		child = child / 2 | 
 | ||||||
|  | 		if child <= 0 || q.less(q.items[q.pq[child]], q.items[q.pq[parent]]) { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		q.swap(parent, child) | ||||||
|  | 
 | ||||||
|  | 		child = parent | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -170,18 +170,18 @@ func TestMultiwayMerge(t *testing.T) { | ||||||
| 	expected := "AABBBCDEFFGHIIJNPQQZ" | 	expected := "AABBBCDEFFGHIIJNPQQZ" | ||||||
| 	actual := "" | 	actual := "" | ||||||
| 
 | 
 | ||||||
| 	pq := NewIPQ(func(t1, t2 string) bool { return t1 > t2 }, len(allStreams)+1) | 	pq := NewIPQ(func(t1, t2 string) bool { return t1 > t2 }, len(allStreams)) | ||||||
| 
 | 
 | ||||||
| 	for i, stream := range allStreams { | 	for i, stream := range allStreams { | ||||||
| 		rune, _, _ := stream.ReadRune() | 		rune, _, _ := stream.ReadRune() | ||||||
| 		pq.insert(i+1, string(rune)) | 		pq.insert(i, string(rune)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for !pq.isEmpty() { | 	for !pq.isEmpty() { | ||||||
| 		actual += string(pq.top()) | 		actual += string(pq.top()) | ||||||
| 		streamIndex := pq.topKey() | 		streamIndex := pq.topKey() | ||||||
| 		pq.remove() | 		pq.remove() | ||||||
| 		rune, _, err := allStreams[streamIndex-1].ReadRune() | 		rune, _, err := allStreams[streamIndex].ReadRune() | ||||||
| 		if err != io.EOF { | 		if err != io.EOF { | ||||||
| 			pq.insert(streamIndex, string(rune)) | 			pq.insert(streamIndex, string(rune)) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue