Skip to content

Commit 7cb46ba

Browse files
ClémentClément
authored andcommitted
Improving notes on priority queue.
1 parent 73e5593 commit 7cb46ba

4 files changed

Lines changed: 124 additions & 22 deletions

File tree

source/code/projects/PQueue_heap/PQueue/PQueue.cs

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ public void Clear()
4545
count = 0;
4646
}
4747

48-
4948
public TValue Peek()
5049
{
5150
if (IsEmpty()) throw new ApplicationException("Queue is empty, no most urgent value.");
@@ -71,7 +70,7 @@ public void Add(TPriority priorityP, TValue valueP)
7170
// and move the data at hole / 2 at hole.
7271
}
7372
// Once this is done, we can insert the new value.
74-
mArray[hole] = new Cell(priorityP, aValue);
73+
mArray[hole] = new Cell(priorityP, valueP);
7574
}
7675

7776
public TValue Extract()
@@ -80,43 +79,53 @@ public TValue Extract()
8079
throw new ApplicationException("Queue is empty, cannot extract from it.");
8180

8281
// Save the data to be returned.
83-
TValue value = mArray[1].Value;
82+
TValue cellValue = mArray[1].Value;
8483

85-
// put the last item in the tree in the root
84+
// Move the "rightmost" cell from the
85+
// last level to the root.
8686
mArray[1] = mArray[count];
87-
// We have one less element now
87+
// We have one less element now.
8888
count--;
8989

9090
// Move the lowest child up until we've found the right spot
91-
// for the item moved from the last level to the root.
91+
// for the cell moved from the last level to the root.
9292
PercolateDown(1);
93-
94-
return value;
93+
return cellValue;
9594
}
9695

97-
private void PercolateDown(int hole)
96+
private void PercolateDown(int indexP)
9897
{
98+
// "PercolateDown", starting at
99+
// indexP.
99100
int child;
100-
// save the hole's cell in a tmp spot
101-
Cell pTmp = mArray[hole];
101+
// Save the hole's cell.
102+
Cell cellValue = mArray[indexP];
102103

103-
// keep going down the tree until the last level
104-
for (; hole * 2 <= count; hole = child)
104+
bool found = false;
105+
// Keep going down the tree until the last level
106+
while(indexP * 2 <= count && !found)
105107
{
106-
child = hole * 2; // get right child
107-
// check right and left child and put lowest one in the child variable
108+
child = indexP * 2; // get right child
109+
// check right and left child and put lowest one in the child variable
108110
if (child != count && mArray[child + 1].Priority.CompareTo(mArray[child].Priority) < 0)
111+
{
109112
child++;
113+
}
110114
// put lowest child in hole
111-
if (mArray[child].Priority.CompareTo(pTmp.Priority) < 0)
115+
if (mArray[child].Priority.CompareTo(cellValue.Priority) < 0)
112116
{
113-
mArray[hole] = mArray[child];
117+
mArray[indexP] = mArray[child];
114118
}
115119
else
116-
break;
120+
{
121+
found = true;
122+
}
123+
// If we are not done,
124+
// we update the value for indexP.
125+
if (!found) { indexP = child; }
117126
}
118127
// found right spot of hole's original value, put it back into tree
119-
mArray[hole] = pTmp;
128+
mArray[indexP] = cellValue;
120129
}
121130

122131
/// <summary>
@@ -134,7 +143,7 @@ public override string ToString()
134143
string returned = "";
135144
for (int i = 1; i <= count; i++)
136145
{
137-
returned += mArray[i].Value.ToString() + "; ";
146+
returned += mArray[i].ToString() + "; ";
138147
}
139148
return returned;
140149
}

source/code/projects/PQueue_heap/PQueue/Program.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,35 @@ class Program
44
{
55
static void Main(string[] args)
66
{
7-
PQueue<int, string> myQueue = new PQueue<int, string>(5);
7+
8+
PQueue<int, int> heapEx = new PQueue<int, int>(7);
9+
for (int i = 6; i > 0; i--)
10+
{
11+
heapEx.Add(i, i);
12+
Console.WriteLine(heapEx);
13+
}
14+
heapEx.Add(-1, -1);
15+
Console.WriteLine(heapEx);
16+
17+
// Let us extract three values.
18+
for (int i = 0; i < 3; i++)
19+
{
20+
Console.WriteLine("Lowest priority:" + heapEx.Extract());
21+
Console.WriteLine(heapEx);
22+
}
23+
Console.WriteLine(heapEx);
24+
25+
/*
26+
*
27+
* Level 1: Resuscitation
28+
* Level 2: Emergent
29+
* Level 3: Urgent
30+
* Level 4: Semi-Urgent
31+
* Level 5: Non-urgent
32+
*/
33+
PQueue<int, string> myQueue = new PQueue<int, string>(5);
34+
myQueue.Add(3, "Abdominal pain ");
35+
Console.WriteLine(myQueue);
36+
837
}
938
}

source/diag/gra/heap_example_1.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
%%% Heap example, represented as a complete binary tree
2+
3+
A((1))-->B((3))
4+
A-->C((2))
5+
B-->D((6))
6+
B-->E((4))
7+
C-->F((5))
8+
C-->H((null))

source/lectures/data/priority_queue.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Letting a greater priority means "more important" is called a *max-priority queu
2727
In both cases, a decision must be made if multiple elements have the same priority: we can decide arbitrarily, using the element value, take the "first one" in the structure, etc.
2828

2929
Exactly like a people waiting **at the ER**, priority queues implement a **"most-important-in-first-out"** principle.
30+
Our examples will use the [Emergency Severity Index](https://en.wikipedia.org/wiki/Emergency_Severity_Index), which ranges from 1 (most urgent) to 5 (less urgent).
31+
3032

3133
## Possible Implementation
3234

@@ -37,7 +39,6 @@ Here is an implementation of priority queues using arrays:
3739
```{download="./code/projects/PQueue_array.zip"}
3840
!include code/projects/PQueue_array/PQueue/PQueue.cs
3941
```
40-
4142
This implementation as the following performance:
4243

4344
- `Add` is $O(n)$, it may take $n$ steps to find an empty slot,
@@ -57,11 +58,66 @@ A maximally efficient implementation of priority queues is given by [heaps](http
5758

5859
Note that this is different from being a binary search tree.
5960

61+
#### Representing complete binary trees using arrays
62+
63+
A [binary heap](https://en.wikipedia.org/wiki/Binary_heap) is often [implemented as an array](https://en.wikipedia.org/wiki/Binary_heap#Heap_implementation).
64+
Consider the following binary tree (we will take the priority of the node to be its value in the following):
65+
66+
!include diag/gra/heap_example_1.md
67+
68+
It is a heap, but not a binary search tree. It can be represented as the following array:
69+
70+
Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
71+
--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
72+
Node |`null` | 1 | 3 | 2 | 6 | 4 | 5 | `null` |
73+
74+
The reason why we start at index 1 and not 0 is because it makes the following calculation easier^[The difference can be looked up [on wikipedia](https://en.wikipedia.org/wiki/Binary_heap#Heap_implementation), it is mostly a matter of substracting or adding 1 at various places.].
75+
Indeed, each element at index $i$ has
76+
77+
- its children at indices $2 \times i$ and $(2 \times i) + 1$,
78+
- its parent at index $\lfloor i/2 \rfloor$ for $\lfloor \cdot \rfloor$ the floor function (i.e., $\lfloor 1.5 \rfloor = 1$).
79+
80+
#### Inserting into a heap
81+
82+
To insert an element to a heap, we perform the following steps:
83+
84+
1. Add the element to the bottom level of the heap at the leftmost open space (or "start" a new level if the last level is full).
85+
2. Compare the added element with its parent; if they are in the correct order, stop.
86+
3. If not, swap the element with its parent and return to the previous step.
87+
88+
Imagine we want to insert $-1$ in our previous example, we would:
89+
90+
- Add $-1$ as the right child of $2$,
91+
- Swap $-1$ and $2$,
92+
- Swap $-1$ and $1$,
93+
- Be done.
94+
95+
In terms of array representation, we would obtain (with the values that changed **in bold**):
96+
97+
Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
98+
--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
99+
Node |`null` | **-1** | 3 | **1** | 6 | 4 | 5 | **2** |
100+
101+
102+
#### Deleting from a heap
103+
104+
Extracting the element with the lowest priority is easy: it is located at the root of the tree, or at index 1 in the array representation.
105+
The challenge is to restore "the heap property", which is done as follows:
106+
107+
1. Replace the root of the heap with the last element on the last level.
108+
2. Compare the new root with its children; if they are in the correct order, stop.
109+
3. If not, swap the element with one of its children and return to the previous step. (Swap with its smaller child in a min-heap and its larger child in a max-heap.)
110+
111+
The 2nd and 3rd steps are called "percolate-down".
112+
113+
60114
```{download="./code/projects/PQueue_heap.zip"}
61115
!include code/projects/PQueue_heap/PQueue/PQueue.cs
62116
```
63117

64118

119+
120+
65121
<!--
66122
67123
- Index 0 is unused.

0 commit comments

Comments
 (0)