Fix Algorithm.doc
This commit is contained in:
parent
123be5a4f2
commit
5af13809b3
|
@ -7,7 +7,7 @@ For an edge-weighted graph, a _maximum weight matching_ is a matching that achie
|
||||||
the largest possible sum of weights of matched edges.
|
the largest possible sum of weights of matched edges.
|
||||||
|
|
||||||
The code in this repository is based on a variant of the blossom algorithm that runs in
|
The code in this repository is based on a variant of the blossom algorithm that runs in
|
||||||
_O(n \* m \* log(n))_ steps.
|
_O(n m log n)_ steps.
|
||||||
See the file [Algorithm.md](doc/Algorithm.md) for a detailed description.
|
See the file [Algorithm.md](doc/Algorithm.md) for a detailed description.
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ The folder [cpp/](cpp/) contains a header-only C++ implementation of maximum wei
|
||||||
|
|
||||||
**NOTE:**
|
**NOTE:**
|
||||||
The C++ code currently implements a slower algorithm that runs in _O(n<sup>3</sup>)_ steps.
|
The C++ code currently implements a slower algorithm that runs in _O(n<sup>3</sup>)_ steps.
|
||||||
I plan to eventually update the C++ code to implement the faster _O(n*m*log(n))_ algorithm.
|
I plan to eventually update the C++ code to implement the faster _O(n m log n)_ algorithm.
|
||||||
|
|
||||||
The C++ code is self-contained and can easily be linked into an application.
|
The C++ code is self-contained and can easily be linked into an application.
|
||||||
It is also reasonably efficient.
|
It is also reasonably efficient.
|
||||||
|
|
|
@ -82,7 +82,7 @@ It has also been shown to be quite fast in practice on several types of graphs
|
||||||
including random graphs [[7]](#mehlhorn_schafer2002).
|
including random graphs [[7]](#mehlhorn_schafer2002).
|
||||||
|
|
||||||
This algorithm is more difficult to implement than the older _O(n<sup>3</sup>)_ algorithm.
|
This algorithm is more difficult to implement than the older _O(n<sup>3</sup>)_ algorithm.
|
||||||
In particular, it requires a specialized data structure to implement mergeable priority queues.
|
In particular, it requires a specialized data structure to implement concatenable priority queues.
|
||||||
This increases the size and complexity of the code quite a bit.
|
This increases the size and complexity of the code quite a bit.
|
||||||
However, in my opinion the performance improvement is worth the extra effort.
|
However, in my opinion the performance improvement is worth the extra effort.
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ have _slack_.
|
||||||
An augmenting path that consists only of tight edges is _guaranteed_ to increase the weight
|
An augmenting path that consists only of tight edges is _guaranteed_ to increase the weight
|
||||||
of the matching as much as possible.
|
of the matching as much as possible.
|
||||||
|
|
||||||
While searching for an augmenting path, we simply restrict the search to tight edges,
|
While searching for an augmenting path, we restrict the search to tight edges,
|
||||||
ignoring all edges that have slack.
|
ignoring all edges that have slack.
|
||||||
Certain explicit actions of the algorithm cause edges to become tight or slack.
|
Certain explicit actions of the algorithm cause edges to become tight or slack.
|
||||||
How this works will be explained later.
|
How this works will be explained later.
|
||||||
|
@ -277,8 +277,8 @@ an odd-length alternating cycle.
|
||||||
The lowest common ancestor node in the alternating tree forms the beginning and end
|
The lowest common ancestor node in the alternating tree forms the beginning and end
|
||||||
of the alternating cycle.
|
of the alternating cycle.
|
||||||
In this case a new blossom must be created by shrinking the cycle.
|
In this case a new blossom must be created by shrinking the cycle.
|
||||||
If the two S-blossoms are in different alternating trees, the edge that links the blossoms
|
On the other hand, if the two S-blossoms are in different alternating trees,
|
||||||
is part of an augmenting path between the roots of the two trees.
|
the edge that links the blossoms is part of an augmenting path between the roots of the two trees.
|
||||||
|
|
||||||
![Figure 3](figures/graph3.png) <br>
|
![Figure 3](figures/graph3.png) <br>
|
||||||
*Figure 3: Growing alternating trees*
|
*Figure 3: Growing alternating trees*
|
||||||
|
@ -457,9 +457,9 @@ $$ \pi_{x,y} = u_x + u_y + \sum_{(x,y) \in B} z_B - w_{x,y} $$
|
||||||
|
|
||||||
An edge is _tight_ if and only if its slack is zero.
|
An edge is _tight_ if and only if its slack is zero.
|
||||||
Given the values of the dual variables, it is very easy to calculate the slack of an edge
|
Given the values of the dual variables, it is very easy to calculate the slack of an edge
|
||||||
which is not contained in any blossom: simply add the duals of its incident vertices and
|
which is not contained in any blossom: add the duals of its incident vertices and
|
||||||
subtract the weight.
|
subtract the weight.
|
||||||
To check whether an edge is tight, simply compute its slack and check whether it is zero.
|
To check whether an edge is tight, simply compute its slack and compare it to zero.
|
||||||
|
|
||||||
Calculating the slack of an edge that is contained in one or more blossoms is a little tricky,
|
Calculating the slack of an edge that is contained in one or more blossoms is a little tricky,
|
||||||
but fortunately we don't need such calculations.
|
but fortunately we don't need such calculations.
|
||||||
|
@ -492,7 +492,7 @@ At that point the maximum weight matching has been found.
|
||||||
When the matching algorithm is finished, the constraints can be checked to verify
|
When the matching algorithm is finished, the constraints can be checked to verify
|
||||||
that the matching is optimal.
|
that the matching is optimal.
|
||||||
This check is simpler and faster than the matching algorithm itself.
|
This check is simpler and faster than the matching algorithm itself.
|
||||||
It can therefore be a useful way to guard against bugs in the matching algorithm.
|
It can therefore be a useful way to guard against bugs in the algorithm.
|
||||||
|
|
||||||
### Rules for updating dual variables
|
### Rules for updating dual variables
|
||||||
|
|
||||||
|
@ -522,7 +522,7 @@ It then changes dual variables as follows:
|
||||||
- _z<sub>B</sub> ← z<sub>B</sub> − 2 * δ_ for every non-trivial T-blossom _B_
|
- _z<sub>B</sub> ← z<sub>B</sub> − 2 * δ_ for every non-trivial T-blossom _B_
|
||||||
|
|
||||||
Dual variables of unlabeled blossoms and their vertices remain unchanged.
|
Dual variables of unlabeled blossoms and their vertices remain unchanged.
|
||||||
Dual variables _z<sub>B</sub>_ of non-trivial sub-blossoms also remain changed;
|
Dual variables _z<sub>B</sub>_ of non-trivial sub-blossoms also remain unchanged;
|
||||||
only top-level blossoms have their _z<sub>B</sub>_ updated.
|
only top-level blossoms have their _z<sub>B</sub>_ updated.
|
||||||
|
|
||||||
Note that these rules ensure that no change occurs to the slack of any edge which is matched,
|
Note that these rules ensure that no change occurs to the slack of any edge which is matched,
|
||||||
|
@ -566,21 +566,21 @@ to an alternating tree, or expanding a blossom) that allow the algorithm to make
|
||||||
In fact, it is convenient to let the dual update mechanism drive the entire process of discovering
|
In fact, it is convenient to let the dual update mechanism drive the entire process of discovering
|
||||||
tight edges and growing alternating trees.
|
tight edges and growing alternating trees.
|
||||||
|
|
||||||
In my description of the search algorithm above, I stated that a tight edge between
|
In my description of the search algorithm above, I stated that upon discovery of a tight edge
|
||||||
a newly labeled S-vertex and an unlabeled vertex or a different S-blossom should be used to
|
between a newly labeled S-vertex and an unlabeled vertex or a different S-blossom, the edge should
|
||||||
grow the alternating tree or to create a new blossom or to form an augmenting path.
|
be used to grow the alternating tree or to create a new blossom or to form an augmenting path.
|
||||||
However, it turns out to be easier to postpone the use of such edges until the next delta step.
|
However, it turns out to be easier to postpone the use of such edges until the next delta step.
|
||||||
While scanning newly labeled S-vertices, edges to unlabeled vertices or different S-blossoms
|
While scanning newly labeled S-vertices, edges to unlabeled vertices or different S-blossoms
|
||||||
are discovered but not yet used.
|
are discovered but not yet used.
|
||||||
Such edges will merely be indexed in a suitable data structure.
|
Such edges are merely registered in a suitable data structure.
|
||||||
Even if the edge is tight, it will be indexed rather than used right away.
|
Even if the edge is tight, it is registered rather than used right away.
|
||||||
|
|
||||||
Once the scan completes, a delta step will be done.
|
Once the scan completes, a delta step will be done.
|
||||||
If any tight edges were discovered during the scan, the delta step will find that either
|
If any tight edges were discovered during the scan, the delta step will find that either
|
||||||
_δ<sub>2</sub> = 0_ or _δ<sub>3</sub> = 0_.
|
_δ<sub>2</sub> = 0_ or _δ<sub>3</sub> = 0_.
|
||||||
The corresponding step (growing the alternating tree, creating a blossom or augmenting
|
The corresponding step (growing the alternating tree, creating a blossom or augmenting
|
||||||
the matching) will occur at that point.
|
the matching) will occur at that point.
|
||||||
If no suitable tight edges exist, a real change of dual variables will occur.
|
If no suitable tight edges exist, a real (non-zero) change of dual variables will occur.
|
||||||
|
|
||||||
The search for an augmenting path becomes as follows:
|
The search for an augmenting path becomes as follows:
|
||||||
|
|
||||||
|
@ -590,7 +590,7 @@ The search for an augmenting path becomes as follows:
|
||||||
Add all vertices inside such blossoms to _Q_.
|
Add all vertices inside such blossoms to _Q_.
|
||||||
- Repeat until either an augmenting path is found or _δ<sub>1</sub> = 0_:
|
- Repeat until either an augmenting path is found or _δ<sub>1</sub> = 0_:
|
||||||
- Scan all vertices in Q as described earlier.
|
- Scan all vertices in Q as described earlier.
|
||||||
Build an index of edges to unlabeled vertices or other S-blossoms.
|
Register edges to unlabeled vertices or other S-blossoms.
|
||||||
Do not yet use such edges to change the alternating tree, even if the edge is tight.
|
Do not yet use such edges to change the alternating tree, even if the edge is tight.
|
||||||
- Calculate _δ_ and update dual variables as described above.
|
- Calculate _δ_ and update dual variables as described above.
|
||||||
- If _δ = δ<sub>1</sub>_, end the search.
|
- If _δ = δ<sub>1</sub>_, end the search.
|
||||||
|
@ -607,7 +607,7 @@ The search for an augmenting path becomes as follows:
|
||||||
- If _δ = δ<sub>4</sub>_, expand the corresponding T-blossom.
|
- If _δ = δ<sub>4</sub>_, expand the corresponding T-blossom.
|
||||||
|
|
||||||
It may seem complicated, but this is actually easier.
|
It may seem complicated, but this is actually easier.
|
||||||
The code that scans newly labeled S-vertices, no longer needs to treat tight edges specially.
|
The code that scans newly labeled S-vertices, no longer needs special treatment of tight edges.
|
||||||
|
|
||||||
In general, multiple updates of the dual variables are necessary during a single _stage_ of
|
In general, multiple updates of the dual variables are necessary during a single _stage_ of
|
||||||
the algorithm.
|
the algorithm.
|
||||||
|
@ -665,7 +665,7 @@ All vertices of sub-blossoms that got label S are inserted into _Q_.
|
||||||
|
|
||||||
The algorithm often needs to find the top-level blossom _B(x)_ that contains a given vertex _x_.
|
The algorithm often needs to find the top-level blossom _B(x)_ that contains a given vertex _x_.
|
||||||
|
|
||||||
A naive implementation may keep this information is an array where the element with
|
A naive implementation may keep this information in an array where the element with
|
||||||
index _x_ holds a pointer to blossom _B(x)_.
|
index _x_ holds a pointer to blossom _B(x)_.
|
||||||
Lookup in this array would be fast, but keeping the array up-to-date takes too much time.
|
Lookup in this array would be fast, but keeping the array up-to-date takes too much time.
|
||||||
There can be _O(n)_ stages, and _O(n)_ blossoms can be created or expanded during a stage,
|
There can be _O(n)_ stages, and _O(n)_ blossoms can be created or expanded during a stage,
|
||||||
|
@ -684,8 +684,8 @@ for example by storing a pointer to the blossom inside the queue instance.
|
||||||
|
|
||||||
When a new blossom is created, the concatenable queues of its sub-blossoms are merged
|
When a new blossom is created, the concatenable queues of its sub-blossoms are merged
|
||||||
to form one concatenable queue for the new blossom.
|
to form one concatenable queue for the new blossom.
|
||||||
Concatenating two queues produces a new queue that contains all members of the original queues.
|
The merged queue contains all vertices of the original queues.
|
||||||
This operation takes time _O(log n)_.
|
Merging a pair of queues takes time _O(log n)_.
|
||||||
To merge the queues of _k_ sub-blossoms, the concatenation step is repeated _k-1_ times,
|
To merge the queues of _k_ sub-blossoms, the concatenation step is repeated _k-1_ times,
|
||||||
taking total time _O(k log n)_.
|
taking total time _O(k log n)_.
|
||||||
|
|
||||||
|
@ -693,7 +693,7 @@ When a blossom is expanded, its concatenable queue is un-concatenated to recover
|
||||||
for the sub-blossoms.
|
for the sub-blossoms.
|
||||||
This also takes time _O(log n)_ for each sub-blossom.
|
This also takes time _O(log n)_ for each sub-blossom.
|
||||||
|
|
||||||
Implementation details of a concatenable queue will be discussed later in this document.
|
Implementation details of concatenable queues are discussed later in this document.
|
||||||
|
|
||||||
### Lazy updating of dual variables
|
### Lazy updating of dual variables
|
||||||
|
|
||||||
|
@ -775,8 +775,7 @@ _δ<sub>1</sub>_ is the minimum dual value of any S-vertex.
|
||||||
This value can be computed in constant time.
|
This value can be computed in constant time.
|
||||||
The dual value of an unmatched vertex is reduced by _δ_ during every delta step.
|
The dual value of an unmatched vertex is reduced by _δ_ during every delta step.
|
||||||
Since all vertex duals start with the same dual value _u<sub>start</sub>_,
|
Since all vertex duals start with the same dual value _u<sub>start</sub>_,
|
||||||
all unmatched vertices have dual value _u<sub>start</sub> - Δ_,
|
all unmatched vertices have dual value _δ<sub>1</sub> = u<sub>start</sub> - Δ_.
|
||||||
which is the minimum dual value among all vertices.
|
|
||||||
|
|
||||||
_δ<sub>3</sub>_ is half of the minimum slack of any edge between two different S-blossoms.
|
_δ<sub>3</sub>_ is half of the minimum slack of any edge between two different S-blossoms.
|
||||||
To compute this efficiently, we keep edges between S-blossoms in a priority queue.
|
To compute this efficiently, we keep edges between S-blossoms in a priority queue.
|
||||||
|
@ -836,15 +835,16 @@ This ensures that the priorities remain unchanged during delta steps.
|
||||||
The priorities also remain unchanged when the T-vertex becomes unlabeled or the unlabeled
|
The priorities also remain unchanged when the T-vertex becomes unlabeled or the unlabeled
|
||||||
vertex becomes a T-vertex.
|
vertex becomes a T-vertex.
|
||||||
|
|
||||||
At the middle level, every T-blossom or unlabeled top-level maintains a priority queue
|
At the middle level, every T-blossom or unlabeled top-level blossom maintains a priority queue
|
||||||
containing its vertices.
|
containing its vertices.
|
||||||
This is in fact the _concatenable priority queue_ instance that is maintained by every
|
This is in fact the _concatenable priority queue_ that is maintained by every top-level blossom
|
||||||
top-level blossom as described earlier in this document.
|
as was described earlier in this document.
|
||||||
The priority of each vertex in the queue is set to the minimum priority of any edge
|
The priority of each vertex in the mid-level queue is set to the minimum priority of any edge
|
||||||
in the low-level queue of that vertex.
|
in the low-level queue of that vertex.
|
||||||
If edges are added to (or removed from) the low-level queue, the priority of the corresponding
|
If edges are added to (or removed from) the low-level queue, the priority of the corresponding
|
||||||
vertex in the mid-level queue may change.
|
vertex in the mid-level queue may change.
|
||||||
If the low-level queue of a vertex is empty, that vertex has priority _Inf_ in the mid-level queue.
|
If the low-level queue of a vertex is empty, that vertex has priority _Infinity_
|
||||||
|
in the mid-level queue.
|
||||||
|
|
||||||
At the highest level, unlabeled top-level blossoms are tracked in one global priority queue.
|
At the highest level, unlabeled top-level blossoms are tracked in one global priority queue.
|
||||||
The priority of each blossom in this queue is set to the minimum slack of any edge
|
The priority of each blossom in this queue is set to the minimum slack of any edge
|
||||||
|
@ -862,7 +862,7 @@ The whole thing is a bit tricky, but it works.
|
||||||
|
|
||||||
### Re-using alternating trees
|
### Re-using alternating trees
|
||||||
|
|
||||||
According to [[5]], labels and alternating trees should be erased at the end of each stage.
|
According to [[5]](#galil1986), labels and alternating trees should be erased at the end of each stage.
|
||||||
However, the algorithm can be optimized by keeping some of the labels and re-using them
|
However, the algorithm can be optimized by keeping some of the labels and re-using them
|
||||||
in the next stage.
|
in the next stage.
|
||||||
The optimized algorithm erases _only_ the two alternating trees that are part of
|
The optimized algorithm erases _only_ the two alternating trees that are part of
|
||||||
|
@ -884,7 +884,7 @@ For S-blossoms that lose their labels, the modified vertex dual variables are up
|
||||||
|
|
||||||
The various priority queues also need updating.
|
The various priority queues also need updating.
|
||||||
Former T-blossoms must be removed from the priority queue for _δ<sub>4</sub>_.
|
Former T-blossoms must be removed from the priority queue for _δ<sub>4</sub>_.
|
||||||
Edges incident on former S-vertices must be removed from the priority queue for _δ<sub>3</sub>_.
|
Edges incident on former S-vertices must be removed from the priority queues for _δ<sub>3</sub>_ and _δ<sub>2</sub>_.
|
||||||
Finally, S-vertices that become unlabeled need to construct a proper priority queue
|
Finally, S-vertices that become unlabeled need to construct a proper priority queue
|
||||||
of incident edges to other S-vertices for _δ<sub>2</sub>_ tracking.
|
of incident edges to other S-vertices for _δ<sub>2</sub>_ tracking.
|
||||||
This involves visiting every incident edge of every vertex in each S-blossom that loses its label.
|
This involves visiting every incident edge of every vertex in each S-blossom that loses its label.
|
||||||
|
@ -894,8 +894,8 @@ This involves visiting every incident edge of every vertex in each S-blossom tha
|
||||||
Every stage of the algorithm either increases the number of matched vertices by 2 or
|
Every stage of the algorithm either increases the number of matched vertices by 2 or
|
||||||
ends the matching.
|
ends the matching.
|
||||||
Therefore the number of stages is at most _n/2_.
|
Therefore the number of stages is at most _n/2_.
|
||||||
Every stage runs in _O((n + m) log n)_ steps, therefore the complete algorithm runs in
|
Every stage runs in time _O((n + m) log n)_, therefore the complete algorithm runs in
|
||||||
_O(n (n + m) log n)_ steps.
|
time _O(n (n + m) log n)_.
|
||||||
|
|
||||||
Creating a blossom reduces the number of top-level blossoms by at least 2,
|
Creating a blossom reduces the number of top-level blossoms by at least 2,
|
||||||
thus limiting the number of simultaneously existing blossoms to _O(n)_.
|
thus limiting the number of simultaneously existing blossoms to _O(n)_.
|
||||||
|
@ -921,11 +921,11 @@ A blossom also becomes unlabeled at most once, at the end of the stage.
|
||||||
Changing the label of a blossom takes some simple bookkeeping, as well as operations
|
Changing the label of a blossom takes some simple bookkeeping, as well as operations
|
||||||
on priority queues (_δ<sub>4</sub>_ for T-blossoms, _δ<sub>2</sub>_ for unlabeled
|
on priority queues (_δ<sub>4</sub>_ for T-blossoms, _δ<sub>2</sub>_ for unlabeled
|
||||||
blossoms) which take time _O(log n)_ per blossom.
|
blossoms) which take time _O(log n)_ per blossom.
|
||||||
Assigning label S or removing label S also involves some work per vertex in the blossom,
|
Assigning label S or removing label S also involves work for the vertices in the blossom
|
||||||
but I account for that time separately below so I can ignore it here.
|
and their edges, but I account for that time separately below so I can ignore it here.
|
||||||
Blossom labeling thus takes total time _O(n log n)_ per stage.
|
Blossom labeling thus takes total time _O(n log n)_ per stage.
|
||||||
|
|
||||||
During each stage, an vertex becomes an S-vertex at most once, and an S-vertex becomes
|
During each stage, a vertex becomes an S-vertex at most once, and an S-vertex becomes
|
||||||
unlabeled at most once.
|
unlabeled at most once.
|
||||||
In both cases, the incident edges of the affected vertex are scanned and potentially
|
In both cases, the incident edges of the affected vertex are scanned and potentially
|
||||||
added to or removed from priority queues.
|
added to or removed from priority queues.
|
||||||
|
@ -946,7 +946,7 @@ Also in case of a T-blossom, some sub-blossoms will become S-blossoms and their
|
||||||
vertices become S-vertices, but I have already accounted for that cost above
|
vertices become S-vertices, but I have already accounted for that cost above
|
||||||
so I can ignore it here.
|
so I can ignore it here.
|
||||||
Expanding a blossom thus takes time _O(k log n)_.
|
Expanding a blossom thus takes time _O(k log n)_.
|
||||||
The number of blossom expansions during a stage is _O(n)_.
|
Any blossom is involved as a sub-blossom in an expanding blossom at most once per stage.
|
||||||
Blossom expansion thus takes total time _O(n log n)_ per stage.
|
Blossom expansion thus takes total time _O(n log n)_ per stage.
|
||||||
|
|
||||||
The length of an augmenting path is _O(n)_.
|
The length of an augmenting path is _O(n)_.
|
||||||
|
@ -1017,8 +1017,8 @@ Priority queues are used for a number of purposes:
|
||||||
- a separate priority queue per vertex to find the least-slack edge between that vertex
|
- a separate priority queue per vertex to find the least-slack edge between that vertex
|
||||||
and any S-vertex.
|
and any S-vertex.
|
||||||
|
|
||||||
This type of queue is implemented as a binary heap.
|
These queues are implemented as a binary heaps.
|
||||||
It supports the following operations:
|
This type of queue supports the following operations:
|
||||||
|
|
||||||
- _insert_ a new element with specified priority in time _O(log n)_;
|
- _insert_ a new element with specified priority in time _O(log n)_;
|
||||||
- find the element with _minimum_ priority in time _O(1)_;
|
- find the element with _minimum_ priority in time _O(1)_;
|
||||||
|
@ -1029,11 +1029,11 @@ It supports the following operations:
|
||||||
|
|
||||||
Each top-level blossom maintains a concatenable priority queue containing its vertices.
|
Each top-level blossom maintains a concatenable priority queue containing its vertices.
|
||||||
We use a specific type of concatenable queue that supports the following operations
|
We use a specific type of concatenable queue that supports the following operations
|
||||||
[[4]](#galil_micali_gabow1986) [[5]](#aho_hopcroft_ullman1974):
|
[[4]](#galil_micali_gabow1986) [[8]](#aho_hopcroft_ullman1974):
|
||||||
|
|
||||||
- _create_ a new queue containing 1 new element;
|
- _create_ a new queue containing 1 new element;
|
||||||
- find the element with _minimum_ priority in time _O(1)_;
|
- find the element with _minimum_ priority in time _O(1)_;
|
||||||
- _change_ the priority of a given element;
|
- _change_ the priority of a given element in time _O(log n)_;
|
||||||
- _merge_ two queues into one new queue in time _O(log n)_;
|
- _merge_ two queues into one new queue in time _O(log n)_;
|
||||||
- _split_ a queue, thus undoing the previous _merge_ step in time _O(log n)_.
|
- _split_ a queue, thus undoing the previous _merge_ step in time _O(log n)_.
|
||||||
|
|
||||||
|
@ -1052,7 +1052,7 @@ Each internal node also stores its height (distance to its leaf nodes).
|
||||||
Only leaf nodes have a priority.
|
Only leaf nodes have a priority.
|
||||||
However, each internal node maintains a pointer to the leaf node with minimum priority
|
However, each internal node maintains a pointer to the leaf node with minimum priority
|
||||||
within its subtree.
|
within its subtree.
|
||||||
As a consequence, the root of the tree has a pointer to the element with minimum priority.
|
As a consequence, the root of the tree has a pointer to the least-priority element in the queue.
|
||||||
To keep this information consistent, any change in the priority of a leaf node must
|
To keep this information consistent, any change in the priority of a leaf node must
|
||||||
be followed by updating the internal nodes along a path from the leaf node to the root.
|
be followed by updating the internal nodes along a path from the leaf node to the root.
|
||||||
The same must be done when the structure of the tree is adjusted.
|
The same must be done when the structure of the tree is adjusted.
|
||||||
|
@ -1060,7 +1060,7 @@ The same must be done when the structure of the tree is adjusted.
|
||||||
The left-to-right order of the leaf nodes is preserved during all operations, including _merge_
|
The left-to-right order of the leaf nodes is preserved during all operations, including _merge_
|
||||||
and _split_.
|
and _split_.
|
||||||
When trees _A_ and _B_ are merged, the sequence of leaf nodes in the merged tree will consist of
|
When trees _A_ and _B_ are merged, the sequence of leaf nodes in the merged tree will consist of
|
||||||
the leaf nodes _A_ followed by the leaf nodes of _B_.
|
the leaf nodes of _A_ followed by the leaf nodes of _B_.
|
||||||
Note that the left-to-right order of the leaf nodes is unrelated to the priorities of the elements.
|
Note that the left-to-right order of the leaf nodes is unrelated to the priorities of the elements.
|
||||||
|
|
||||||
To merge two trees, the root of the smaller tree is inserted as a child of an appropriate node
|
To merge two trees, the root of the smaller tree is inserted as a child of an appropriate node
|
||||||
|
@ -1087,7 +1087,6 @@ To do this, we assign a _name_ to each concatenable queue instance, which is sim
|
||||||
a pointer to the top-level blossom that maintains the queue.
|
a pointer to the top-level blossom that maintains the queue.
|
||||||
An extra operation is defined:
|
An extra operation is defined:
|
||||||
_find_ the name of the queue instance that contains a given element in time _O(log n)_.
|
_find_ the name of the queue instance that contains a given element in time _O(log n)_.
|
||||||
|
|
||||||
Implementing the _find_ operation is easy:
|
Implementing the _find_ operation is easy:
|
||||||
Starting at the leaf node that represents the element, follow _parent_ pointers
|
Starting at the leaf node that represents the element, follow _parent_ pointers
|
||||||
to the root of the tree.
|
to the root of the tree.
|
||||||
|
@ -1285,7 +1284,6 @@ changing all weights by the same amount doesn't change which of these matchings
|
||||||
7. <a id="mehlhorn_schafer2002"></a>
|
7. <a id="mehlhorn_schafer2002"></a>
|
||||||
Kurt Mehlhorn, Guido Schäfer, "Implementation of O(nm log(n)) Weighted Matchings in General Graphs: The Power of Data Structures", _Journal of Experimental Algorithmics vol. 7_, 2002.
|
Kurt Mehlhorn, Guido Schäfer, "Implementation of O(nm log(n)) Weighted Matchings in General Graphs: The Power of Data Structures", _Journal of Experimental Algorithmics vol. 7_, 2002.
|
||||||
([link](https://dl.acm.org/doi/10.1145/944618.944622))
|
([link](https://dl.acm.org/doi/10.1145/944618.944622))
|
||||||
([pdf](https://sci-hub.se/https://doi.org/10.1145/944618.944622))
|
|
||||||
|
|
||||||
8. <a id="aho_hopcroft_ullman1974"></a>
|
8. <a id="aho_hopcroft_ullman1974"></a>
|
||||||
Alfred V. Aho, John E. Hopcroft, Jeffrey D. Ullman,
|
Alfred V. Aho, John E. Hopcroft, Jeffrey D. Ullman,
|
||||||
|
|
Loading…
Reference in New Issue