pi_wtree/
fast_wtree.rs

1//! 权重树,不支持索引查询和删除,因此具有相比于wtree::WeightTree更快的速度
2
3use std::fmt::{Debug, Formatter, Result as FResult};
4use std::mem::transmute_copy;
5use std::ptr::write;
6
7#[derive(Debug)]
8pub struct Item<T>{
9    elem: T,
10    count: usize, //自身权重值
11    amount: usize, //自身权重值 和 子节点权重值的总和
12}
13
14pub struct WeightTree<T>(Vec<Item<T>>);
15
16impl<T> WeightTree<T> {
17
18	/// 构建一颗权重树
19	pub fn new() -> Self{
20        WeightTree(Vec::new())
21	}
22
23	/// 创建一颗权重树, 并初始容量
24	pub fn with_capacity(capacity: usize) -> Self{
25		WeightTree(Vec::with_capacity(capacity))
26	}
27
28    /// 取到权重树中任务的总权重
29	pub fn amount(&self) -> usize{
30		match self.0.len(){
31			0 => 0,
32			_ => self.0[0].amount
33		}
34	}
35
36	/// 长度
37    pub fn len(&self) -> usize{
38		self.0.len()
39	}
40
41	/// 清空权重树
42	pub fn clear(&mut self) {
43		self.0.clear();
44	}
45
46	/// 插入元素,返回该元素的位置
47	pub fn push(&mut self, elem: T, weight: usize){
48		let len = self.0.len();
49		self.0.push(Item{
50			elem: elem,
51			count: weight,
52			amount: weight,
53		});
54		self.up(len)
55	}
56
57	/// 指定一个权重,弹出一个任务
58	pub fn pop(&mut self, weight: usize) -> (T, usize){
59		let index = self.find(weight, 0);
60	    self.delete(index)
61	}
62
63	//指定一个权重,尝试弹出一个任务, 如果指定权重大于权重树所有任务权重的总和,返回None
64	pub fn try_pop(&mut self, weight: usize) -> Option<(T, usize)>{
65		match self.0.len(){
66			0 => None,
67			_ => match self.0[0].amount <= weight{
68					true => None,
69					false => {
70                        let index = self.find(weight, 0);
71                        Some(self.delete(index))
72                    }
73				}
74		}
75	}
76
77	//根据权重查询任务
78	#[inline]
79	fn find(&mut self, mut weight: usize, cur_index:usize) -> usize{
80		let cur_weight = self.0[cur_index].count;
81		match weight < cur_weight{
82			true => {//如果当前节点的权重比指定权重值大,应该直接返回该节点的索引
83				return cur_index;
84			},
85			false => {//否则
86				weight = weight - cur_weight;
87				let left_index = (cur_index << 1) + 1;
88				match self.0[left_index].amount <= weight{ //比较左节点及其所有子节点权重和与指定权重的大小
89					true => {
90						//如果指定权重更大, 则左节点及其所有子节点的权重都不可能超过指定权重, 从新计算指定权重, 在下一步从右节点中找节点
91						weight = weight - self.0[left_index].amount;
92						return self.find(weight, left_index + 1);//从右节点中找
93					},
94					false => return self.find(weight, left_index)//如果指定权重更小,则可以从左节点中找到需要的元素
95				};
96				
97			}
98		};
99	}
100
101	// 删除任务
102	#[inline]
103	fn delete(&mut self, index: usize) -> (T, usize){
104        let len = self.0.len();
105		let (index_count, index_amount) = {
106			let e = &self.0[index];
107			(e.count, e.amount)
108		};
109		// 优化算法: TODO
110		if index + 1 < len{//如果需要移除的元素不是堆底元素, 需要将该元素位置设置为栈底元素并下沉
111			let last = len - 1;
112			let (last_count, last_amount) = {
113				let e = &self.0[last];
114				(e.count, e.amount)
115			};
116			self.0.swap(last, index);
117			self.0[index].count = index_count;
118			self.0[index].amount = index_amount;
119			self.0[last].count = last_count;
120			self.0[last].amount = last_amount;
121			self.up_update(index, last_count);
122			self.up_update(last, 0);
123			self.down(index);
124		}else{
125			self.up_update(index, 0);
126		}
127		let elem = self.0.pop().unwrap();
128		(elem.elem, index_count)
129	}
130
131	//上朔,更新当前节点和其父节点的权值  使用时应该保证index不会溢出
132	fn up_update(&mut self, mut cur: usize, weight: usize) -> usize{
133		let arr = &mut self.0;
134		let old_count = arr[cur].count;
135		{
136			let elem = &mut arr[cur];
137			elem.count = weight;
138			elem.amount = elem.amount - old_count + weight;
139		}
140		if cur > 0{
141			let mut parent = (cur - 1) >> 1;
142
143            let mut elem: Item<T> = unsafe{ transmute_copy(&arr[cur])};
144			while weight > arr[parent].count{
145				let new_amount = elem.amount;
146				elem.amount = arr[parent].amount - old_count + weight;
147				//println!("up_update---------------parent{}, {},{},{}, {}",new_amount, arr[cur].count,arr[parent].count, cur, arr[cur].amount);
148				arr[parent].amount = new_amount - elem.count + arr[parent].count;
149                let src = arr.as_mut_ptr();
150                unsafe{src.wrapping_offset(parent as isize).copy_to(src.wrapping_offset(cur as isize), 1)};
151				
152				// 往上迭代
153				cur = parent;
154				if parent == 0{
155					break;
156				}
157				parent = (cur - 1) >> 1;
158			}
159            unsafe{write(arr.as_mut_ptr().wrapping_offset(cur as isize), elem)};
160
161			let mut i = cur;
162			while i > 0{
163				i = (i - 1) >> 1;//parent
164				//println!("up_update1---i:{}, count:{}, amount:{}", i, arr[i].amount, arr[i].amount, );
165				// if (arr[i].amount + weight) < old_count {
166				// 	println!("up_update1---i:{}, count:{}, amount:{}, weight:{}", i, old_count, arr[i].amount, weight);
167				// }
168				arr[i].amount = arr[i].amount + weight - old_count;
169			}
170		}
171		cur
172	}
173
174	//上朔, 使用时应该保证index不会溢出
175	fn up(&mut self, mut cur: usize){
176		let arr = &mut self.0;
177		if cur > 0{
178			let mut parent = (cur - 1) >> 1;
179
180            let mut elem: Item<T> = unsafe{ transmute_copy(&arr[cur])};
181            while elem.count > arr[parent].count {
182                let ew = elem.amount;
183                elem.amount = arr[parent].amount + elem.count;
184                arr[parent].amount = ew + arr[parent].count - elem.count;
185                let src = arr.as_mut_ptr();
186                unsafe{src.wrapping_offset(parent as isize).copy_to(src.wrapping_offset(cur as isize), 1)};
187                
188                // 往上迭代
189                cur = parent;
190                if parent == 0{
191                    break;
192                }
193                parent = (cur - 1) >> 1;
194            }
195            unsafe{write(arr.as_mut_ptr().wrapping_offset(cur as isize), elem)};
196
197            let w = arr[cur].count;
198			let mut i = cur;
199			while i > 0{
200				i = (i - 1) >> 1;//parent
201				arr[i].amount += w;
202			}
203		}
204	}
205
206	/**
207	 * 下沉
208	 * Panics if index is out of bounds.
209	 */
210	fn down(&mut self, index: usize) -> usize {
211		
212		let mut cur = index;
213		let arr = &mut self.0;
214		let mut left = (cur << 1) + 1;
215		let mut right = left + 1;
216		let len = arr.len();
217        let mut elem: Item<T> = unsafe{ transmute_copy(&arr[cur])};
218		while left < len {
219			
220			// 选择左右孩子的最较大值作为比较
221			let mut child = left;
222			if right < len && arr[right].count > arr[left].count {
223				child = right;
224			}
225			//println!("left{}, len{}", left, len);
226			match arr[cur].count >= arr[child].count{
227				true => break,
228				false => {
229					let cw = arr[child].amount;
230					arr[child].amount = elem.amount;
231					elem.amount = cw - arr[child].count + elem.count;
232                    let src = arr.as_mut_ptr();
233                    unsafe{src.wrapping_offset(child as isize).copy_to(src.wrapping_offset(cur as isize), 1)};
234					// 往下迭代
235					cur = child;
236					left = (cur << 1) + 1;
237					right = left + 1;
238				}
239			}
240		}
241        unsafe{write(arr.as_mut_ptr().wrapping_offset(cur as isize), elem)};
242		cur
243	}
244}
245
246impl<T: Debug> Debug for WeightTree<T> where T: Debug {
247    fn fmt(&self, fmt: &mut Formatter) -> FResult {
248        write!(fmt,
249               "WeightTree({:?})",
250               self.0,
251        )
252    }
253}
254
255#[cfg(test)]
256use rand::Rng;
257
258#[test]
259fn test_effic(){
260	let mut weight_tree: WeightTree<u32> = WeightTree::new();
261	let max = 100000;
262	let now = std::time::Instant::now();
263	for i in 0..max{
264		weight_tree.push(i, (i+1) as usize);
265	}
266	println!("fast_wtree: push max_heap time{:?}",  std::time::Instant::now() - now);
267
268	let now = std::time::Instant::now();
269	for _ in 0..max{
270		rand::thread_rng().gen_range(0, 100000);
271	}
272	println!("fast_wtree: rand time{:?}",  std::time::Instant::now() - now);
273
274
275	let now = std::time::Instant::now();
276	for _ in 0..max{
277		let r = rand::thread_rng().gen_range(0, weight_tree.amount());
278		weight_tree.pop(r);
279	}
280	println!("fast_wtree: remove_by_weight time{:?}",  std::time::Instant::now() - now);
281
282	//let r = rand::thread_rng().gen_range(0, amount);
283}
284