1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use crate::PriorityQueue;

/// A [PriorityQueueDecKey] is a more advanced [PriorityQueue] with additional features
/// mainly related to accessing or modifying already pushed nodes such as:
/// * checking if a node is present in the queue,
/// * getting the key of an alrady pushed node,
/// * decreasing or updating the key of an already pushed node.
///
/// This is often achieved by additional memory requirement; hence, it is separated from the [PriorityQueue].
///
/// Another fundamental difference of [PriorityQueueDecKey] from [PriorityQueue] is that
/// it behaves as a set enabled by the `contains` method.
/// In other words,
/// * the same node can be pushed to a [PriorityQueue] an arbitrary number of times with same or different keys;
/// * on the other hand, a node can only be pushed to the [PriorityQueueDecKey] only once; however, the node in the queue can be mutated.
///
/// The [PriorityQueue] requires more space to handle a problem with lots of decrease key operations;
/// [PriorityQueueDecKey] aims to be memory efficient in such situations.
/// On the other hand, [PriorityQueue] could be preferable where number of such upadtes is limited
/// due to its lack of additional checks and tracking.
pub trait PriorityQueueDecKey<N, K>: PriorityQueue<N, K>
where
    N: Clone,
    K: PartialOrd + Clone,
{
    /// Returns whether the given `node` is in the queue or not.
    fn contains(&self, node: &N) -> bool;

    /// Returns the key of the given `node` if it is in the queue;
    /// returns None otherwise.
    fn key_of(&self, node: &N) -> Option<K>;

    /// Decreases key of the `node` which is already in the queue to the given `decreased_key`.
    /// This method is commonly use to increase priority of a node;
    /// rather than to re-insert it to keep the size of the queue smaller.
    ///
    /// # Panics
    /// This method panics if:
    /// * the `node` is not in the queue; or
    /// * `decreased_key` is strictly larget than key of the `node` in the queue.
    ///
    /// # See also
    /// Note that the following methods have minor but important differences
    /// making them suitable for different cases/algorithms:
    /// `decrease_key`, `update_key`, `try_decrease_key`, `decrease_key_or_push`, `update_key_or_push` and `try_decrease_key_or_push`.
    fn decrease_key(&mut self, node: &N, decreased_key: &K);
    /// Updates key of the `node` which is already in the queue as the given `new_key`;
    /// and returns whether the node's key is strictly decreased or not.
    ///
    /// # Panics
    /// This method panics if:
    /// * the `node` is not in the queue.
    ///
    /// # See also
    /// Note that the following methods have minor but important differences
    /// making them suitable for different cases/algorithms:
    /// `decrease_key`, `update_key`, `try_decrease_key`, `decrease_key_or_push`, `update_key_or_push` and `try_decrease_key_or_push`.
    fn update_key(&mut self, node: &N, new_key: &K) -> bool;
    /// This method:
    /// * when `new_key` is strictly less than the `node`'s current key:
    ///     * decreases the key of the node to the given `new_key`, and
    ///     * returns true;
    /// * otherwise:
    ///     * does not change the queue, and
    ///     * returns false.
    ///
    /// In brief, the method returns whether the key of the `node` is decreased or not.
    ///
    /// # Panics
    /// This method panics if:
    /// * the `node` is not in the queue.
    ///
    /// # See also
    /// Note that the following methods have minor but important differences
    /// making them suitable for different cases/algorithms:
    /// `decrease_key`, `update_key`, `try_decrease_key`, `decrease_key_or_push`, `update_key_or_push` and `try_decrease_key_or_push`.
    fn try_decrease_key(&mut self, node: &N, new_key: &K) -> bool {
        let old_key = self.key_of(node).expect("node must exist on the heap.");
        if new_key < &old_key {
            self.decrease_key(node, new_key);
            true
        } else {
            false
        }
    }

    /// This method
    /// * when the `node` is present in the queue:
    ///     * decreases its key to the given new `key` which is expected to be less than or equal to the current key, and
    ///     * returns true;
    /// * otherwise:
    ///     * pushes the `node` with the given `key` to the queue, and
    ///     * returns false.
    ///
    /// In brief, the method returns whether the key of the `node` is decreased or not.
    ///
    /// # Panics
    /// This method panics if:
    /// * the `node` is in the queue; however, its current key is strictly less than the provided `key`.
    ///
    /// # See also
    /// Note that the following methods have minor but important differences
    /// making them suitable for different cases/algorithms:
    /// `decrease_key`, `update_key`, `try_decrease_key`, `decrease_key_or_push`, `update_key_or_push` and `try_decrease_key_or_push`.
    fn decrease_key_or_push(&mut self, node: &N, key: &K) -> bool {
        if self.contains(node) {
            self.decrease_key(node, key);
            true
        } else {
            self.push(node.clone(), key.clone());
            false
        }
    }
    /// This method
    /// * when the `node` is present in the queue:
    ///     * updates its key to the given new `key`, and
    ///     * returns whether the update operation strictly decreased the node's key or not;
    /// * otherwise:
    ///     * pushes the `node` with the given `key` to the queue, and
    ///     * returns false.
    ///
    /// In brief, the method returns whether the key of the `node` is decreased or not.
    ///
    /// # See also
    /// Note that the following methods have minor but important differences
    /// making them suitable for different cases/algorithms:
    /// `decrease_key`, `update_key`, `try_decrease_key`, `decrease_key_or_push`, `update_key_or_push` and `try_decrease_key_or_push`.
    fn update_key_or_push(&mut self, node: &N, key: &K) -> bool {
        if self.contains(node) {
            self.update_key(node, key)
        } else {
            self.push(node.clone(), key.clone());
            false
        }
    }
    /// This method
    /// * when the `node` is present in the queue:
    ///     * when the new `key` is strictly less than the `node`'s current key:
    ///         * decreases the key of the node to the given `key`, and
    ///         * returns true;
    ///     * otherwise:
    ///         * does not change the queue, and
    ///         * returns false;
    /// * otherwise:
    ///     * pushes the `node` with the given `key` to the queue, and
    ///     * returns false.
    ///
    /// In brief, the method returns whether the key of the `node` is decreased or not.
    ///
    /// # See also
    /// Note that the following methods have minor but important differences
    /// making them suitable for different cases/algorithms:
    /// `decrease_key`, `update_key`, `try_decrease_key`, `decrease_key_or_push`, `update_key_or_push` and `try_decrease_key_or_push`.
    fn try_decrease_key_or_push(&mut self, node: &N, key: &K) -> bool {
        if self.contains(node) {
            self.try_decrease_key(node, key)
        } else {
            self.push(node.clone(), key.clone());
            false
        }
    }

    /// Removes the `node` from the queue; and returns its current key.
    ///
    /// # Panics
    /// This method panics if:
    /// * the `node` is not in the queue.
    fn remove(&mut self, node: &N) -> K;
}