├── .gitignore ├── README.pdf ├── assets ├── 1.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 14.png ├── 15.png ├── 16.png ├── 17.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── 9.png ├── submit.jpg ├── git_patch.jpg └── git_command.jpg ├── Cargo.toml ├── Dockerfile ├── src ├── lib.rs ├── tests.rs └── double_linked_list.rs ├── Cargo.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /README.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/README.pdf -------------------------------------------------------------------------------- /assets/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/1.png -------------------------------------------------------------------------------- /assets/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/10.png -------------------------------------------------------------------------------- /assets/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/11.png -------------------------------------------------------------------------------- /assets/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/12.png -------------------------------------------------------------------------------- /assets/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/13.png -------------------------------------------------------------------------------- /assets/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/14.png -------------------------------------------------------------------------------- /assets/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/15.png -------------------------------------------------------------------------------- /assets/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/16.png -------------------------------------------------------------------------------- /assets/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/17.png -------------------------------------------------------------------------------- /assets/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/2.png -------------------------------------------------------------------------------- /assets/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/3.png -------------------------------------------------------------------------------- /assets/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/4.png -------------------------------------------------------------------------------- /assets/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/5.png -------------------------------------------------------------------------------- /assets/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/6.png -------------------------------------------------------------------------------- /assets/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/7.png -------------------------------------------------------------------------------- /assets/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/8.png -------------------------------------------------------------------------------- /assets/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/9.png -------------------------------------------------------------------------------- /assets/submit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/submit.jpg -------------------------------------------------------------------------------- /assets/git_patch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/git_patch.jpg -------------------------------------------------------------------------------- /assets/git_command.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BUPT-OS/os_lab/HEAD/assets/git_command.jpg -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "linked_list" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | rand = "0.8.5" -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | ARG DEBIAN_FRONTEND=noninteractive 3 | # 换源 4 | RUN sed -i "s@http://.*archive.ubuntu.com@http://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list 5 | RUN sed -i "s@http://.*security.ubuntu.com@http://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list 6 | RUN apt-get update 7 | # 安装git 8 | RUN apt-get install git curl build-essential -y 9 | RUN export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static 10 | RUN export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup 11 | RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 12 | COPY . /linked_list 13 | WORKDIR /linked_list 14 | CMD bash -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod double_linked_list; 2 | #[cfg(test)] 3 | mod tests; 4 | 5 | #[test] 6 | fn run_part1() { 7 | use crate::tests::{test_back, test_front, test_len}; 8 | test_front(); 9 | test_back(); 10 | test_len(); 11 | 12 | use crate::tests::{test_for_loop, test_iter, test_iter_mut, test_rev_for_loop}; 13 | test_iter(); 14 | test_iter_mut(); 15 | test_for_loop(); 16 | test_rev_for_loop(); 17 | } 18 | 19 | #[test] 20 | fn run_part2() { 21 | use crate::tests::{ 22 | test_contains, test_find_mut, test_get, test_insert, test_remove, test_split, 23 | }; 24 | test_get(); 25 | test_remove(); 26 | test_insert(); 27 | test_contains(); 28 | test_split(); 29 | test_find_mut(); 30 | } 31 | 32 | #[test] 33 | fn run_part3() { 34 | use crate::tests::{test_merge_sort1, test_merge_sort2, test_merge_sort3}; 35 | test_merge_sort1(); 36 | test_merge_sort2(); 37 | test_merge_sort3(); 38 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "cfg-if" 7 | version = "1.0.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 10 | 11 | [[package]] 12 | name = "getrandom" 13 | version = "0.2.8" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 16 | dependencies = [ 17 | "cfg-if", 18 | "libc", 19 | "wasi", 20 | ] 21 | 22 | [[package]] 23 | name = "libc" 24 | version = "0.2.139" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" 27 | 28 | [[package]] 29 | name = "linked_list" 30 | version = "0.1.0" 31 | dependencies = [ 32 | "rand", 33 | ] 34 | 35 | [[package]] 36 | name = "ppv-lite86" 37 | version = "0.2.17" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 40 | 41 | [[package]] 42 | name = "rand" 43 | version = "0.8.5" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 46 | dependencies = [ 47 | "libc", 48 | "rand_chacha", 49 | "rand_core", 50 | ] 51 | 52 | [[package]] 53 | name = "rand_chacha" 54 | version = "0.3.1" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 57 | dependencies = [ 58 | "ppv-lite86", 59 | "rand_core", 60 | ] 61 | 62 | [[package]] 63 | name = "rand_core" 64 | version = "0.6.4" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 67 | dependencies = [ 68 | "getrandom", 69 | ] 70 | 71 | [[package]] 72 | name = "wasi" 73 | version = "0.11.0+wasi-snapshot-preview1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 76 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::double_linked_list::{LinkedList, MergeSort}; 2 | use rand::{distributions::Uniform, Rng}; 3 | #[test] 4 | pub fn test_front() { 5 | // 测试 front,push_front,pop_front 6 | let mut list = LinkedList::new(); 7 | assert_eq!(list.front(), None); 8 | for i in 0..1000 { 9 | list.push_front(i); 10 | assert_eq!(list.front(), Some(&i)); 11 | if i % 2 == 0 { 12 | assert_eq!(list.pop_front(), Some(i)); 13 | } 14 | } 15 | for i in (0..1000).rev() { 16 | if i % 2 != 0 { 17 | assert_eq!(list.pop_front(), Some(i)); 18 | } 19 | } 20 | } 21 | 22 | #[test] 23 | pub fn test_back() { 24 | // 测试 back,push_back,pop_back 25 | let mut list = LinkedList::new(); 26 | assert_eq!(list.back(), None); 27 | for i in 0..1000 { 28 | list.push_back(i); 29 | assert_eq!(list.back(), Some(&i)); 30 | if i % 2 == 0 { 31 | assert_eq!(list.pop_back(), Some(i)); 32 | } 33 | } 34 | for i in (0..1000).rev() { 35 | if i % 2 != 0 { 36 | assert_eq!(list.pop_back(), Some(i)); 37 | } 38 | } 39 | } 40 | 41 | #[test] 42 | pub fn test_len() { 43 | // 测试 len 44 | let mut list = LinkedList::new(); 45 | assert_eq!(list.len(), 0); 46 | let mut len = 0; 47 | for i in 0..500 { 48 | list.push_back(i); 49 | len += 1; 50 | assert_eq!(list.len(), len); 51 | } 52 | for i in 0..500 { 53 | list.push_front(i); 54 | len += 1; 55 | assert_eq!(list.len(), len); 56 | } 57 | } 58 | 59 | #[test] 60 | pub fn test_iter() { 61 | // 测试 iter 62 | let mut list = LinkedList::new(); 63 | for i in 0..1000 { 64 | list.push_back(i); 65 | } 66 | let mut iter = list.iter(); 67 | for i in 0..1000 { 68 | assert_eq!(iter.next(), Some(&i)); 69 | } 70 | } 71 | 72 | #[test] 73 | pub fn test_iter_mut() { 74 | // 测试 iter_mut 75 | let mut list = LinkedList::new(); 76 | for i in 0..1000 { 77 | list.push_back(i); 78 | } 79 | let mut iter = list.iter_mut(); 80 | for i in 0..1000 { 81 | let mut j = i; 82 | assert_eq!(iter.next(), Some(&mut j)); 83 | } 84 | } 85 | 86 | #[test] 87 | pub fn test_for_loop() { 88 | // 测试遍历 89 | let mut list = LinkedList::new(); 90 | for i in 0..1000 { 91 | list.push_back(i); 92 | } 93 | for (i, j) in list.iter().enumerate() { 94 | assert_eq!(i, *j); 95 | } 96 | for (i, j) in list.iter_mut().enumerate() { 97 | *j = i * 2; 98 | } 99 | for (i, j) in list.iter().enumerate() { 100 | assert_eq!(i * 2, *j); 101 | } 102 | } 103 | 104 | #[test] 105 | pub fn test_rev_for_loop() { 106 | // 测试双向迭代器 107 | let mut list = LinkedList::new(); 108 | for i in (0..1000).rev() { 109 | list.push_back(i); 110 | } 111 | for (i, j) in list.iter().rev().enumerate() { 112 | assert_eq!(i, *j); 113 | } 114 | } 115 | #[test] 116 | pub fn test_get() { 117 | // 测试get 118 | let mut list = LinkedList::new(); 119 | for i in 0..1000 { 120 | list.push_back(i); 121 | } 122 | for i in 0..1000 { 123 | assert_eq!(list.get(i), &i); 124 | } 125 | } 126 | 127 | #[test] 128 | pub fn test_insert() { 129 | // 测试insert 130 | let mut list = LinkedList::new(); 131 | list.push_front(0); 132 | list.push_back(20); 133 | for i in 1..20 { 134 | list.insert(i, i); 135 | } 136 | for (i, j) in list.iter().enumerate() { 137 | assert_eq!(i, *j); 138 | } 139 | } 140 | #[test] 141 | pub fn test_remove() { 142 | // 测试remove 143 | let mut list = LinkedList::new(); 144 | for i in 0..1000 { 145 | list.push_back(i); 146 | } 147 | for i in 0..(1000 - 42) { 148 | assert_eq!(list.remove(42), i + 42); 149 | assert_eq!(list.len(), 999 - i); 150 | } 151 | } 152 | 153 | #[test] 154 | pub fn test_contains() { 155 | let mut list = LinkedList::new(); 156 | for i in 0..1000 { 157 | list.push_back(i); 158 | } 159 | for i in 0..1000 { 160 | assert!(list.contains(&i)); 161 | } 162 | } 163 | 164 | #[test] 165 | pub fn test_find_mut() { 166 | // 测试find_mut 167 | use std::collections::HashSet; 168 | use rand::distributions::Uniform; 169 | use rand::Rng; 170 | use rand::prelude::Distribution; 171 | 172 | let mut list = LinkedList::new(); 173 | let rand_pos: i64 = rand::thread_rng().gen_range(0..1000); 174 | 175 | // FIXME: 此处生成的range范围应该和下标范围不能有重叠 176 | // let range = Uniform::from(100..1000000); 177 | let range = Uniform::from(1000..1000000); 178 | 179 | // FIXME: 生成没有重复的input 180 | // let input: Vec = rand::thread_rng().sample_iter(&range).take(1000).collect(); 181 | let mut input_set: HashSet = HashSet::new(); 182 | let mut rng = rand::thread_rng(); 183 | while input_set.len() != 1000 { 184 | input_set.insert(range.sample(&mut rng)); 185 | } 186 | let input: Vec = input_set.into_iter().collect(); 187 | 188 | 189 | list.extend(input.iter().cloned()); 190 | 191 | for i in 0..1000 { 192 | let v = input[((i + rand_pos) % 1000) as usize]; 193 | list.find_mut(|x| *x == v).map(|x| *x = i as i64); 194 | } 195 | 196 | let mut ans = 1000 - rand_pos; 197 | let mut index: usize = 0; 198 | while let Some(x) = list.pop_front() { 199 | if x != ans { 200 | println!("x: {}, ans: {}, index: {}", x, ans, index); 201 | } 202 | index += 1_usize; 203 | ans = (ans + 1) % 1000; 204 | } 205 | } 206 | 207 | #[test] 208 | pub fn test_split() { 209 | // 测试split 210 | { 211 | let mut list = LinkedList::new(); 212 | for i in 0..1000 { 213 | list.push_back(i); 214 | } 215 | let list2 = list.split_off(500); 216 | assert!(list2.len() == 500); 217 | assert!(list.len() == 500); 218 | for (i, j) in list.iter().enumerate() { 219 | assert_eq!(i, *j); 220 | } 221 | for (i, j) in list2.iter().enumerate() { 222 | assert_eq!(i + 500, *j); 223 | } 224 | let mut list3 = list.split_off(1); 225 | let _ = list3.split_off(498); 226 | for (i, j) in (1..498).zip(list3.iter()) { 227 | assert_eq!(i, *j); 228 | } 229 | } 230 | { 231 | let mut list = LinkedList::new(); 232 | "Hello,world!".chars().for_each(|c| list.push_back(c)); 233 | let part1 = "Hello,".chars().collect::>(); 234 | let part2 = "world!".chars().collect::>(); 235 | let list2 = list.split_off(6); 236 | for (i, j) in list.iter().zip(part1.iter()) { 237 | assert_eq!(*i, *j); 238 | } 239 | for (i, j) in list2.iter().zip(part2.iter()) { 240 | assert_eq!(*i, *j); 241 | } 242 | } 243 | } 244 | 245 | #[test] 246 | pub fn test_merge_sort1() { 247 | let input = vec![ 248 | 58, 14, 2, 87, 35, 29, 86, 60, 52, 45, 97, 90, 78, 37, 32, 89, 1, 27, 25, 34, 249 | ]; 250 | let mut solution = vec![ 251 | 58, 14, 2, 87, 35, 29, 86, 60, 52, 45, 97, 90, 78, 37, 32, 89, 1, 27, 25, 34, 252 | ]; 253 | solution.sort(); 254 | let mut list = LinkedList::new(); 255 | for i in input.iter() { 256 | list.push_back(*i); 257 | } 258 | list.merge_sort(); 259 | for (i, j) in list.iter().zip(solution.iter()) { 260 | assert_eq!(*i, *j); 261 | } 262 | } 263 | 264 | #[test] 265 | pub fn test_merge_sort2() { 266 | { 267 | let input = vec![1]; 268 | let mut solution = vec![1]; 269 | solution.sort(); 270 | let mut list = LinkedList::new(); 271 | for i in input.iter() { 272 | list.push_back(*i); 273 | } 274 | list.merge_sort(); 275 | for (i, j) in list.iter().zip(solution.iter()) { 276 | assert_eq!(*i, *j); 277 | } 278 | } 279 | { 280 | let input = vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; 281 | let mut solution = vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; 282 | solution.sort(); 283 | let mut list = LinkedList::new(); 284 | for i in input.iter() { 285 | list.push_back(*i); 286 | } 287 | list.merge_sort(); 288 | for (i, j) in list.iter().zip(solution.iter()) { 289 | assert_eq!(*i, *j); 290 | } 291 | } 292 | } 293 | 294 | #[test] 295 | pub fn test_merge_sort3() { 296 | let range = Uniform::from(0..1000000); 297 | for _ in 0..5 { 298 | let input: Vec = rand::thread_rng() 299 | .sample_iter(&range) 300 | .take(100000) 301 | .collect(); 302 | let mut output = input.clone(); 303 | output.sort(); 304 | let mut list = LinkedList::new(); 305 | for i in input.iter() { 306 | list.push_back(*i); 307 | } 308 | list.merge_sort(); 309 | for (i, j) in list.iter().zip(output.iter()) { 310 | assert_eq!(*i, *j); 311 | } 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /src/double_linked_list.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Ordering; 2 | use std::fmt::{self, Debug}; 3 | use std::hash::{Hash, Hasher}; 4 | use std::marker::PhantomData; 5 | 6 | /// 双链表 7 | pub struct LinkedList { 8 | // TODO: YOUR CODE HERE 9 | marker: PhantomData, // 可以去掉 10 | } 11 | 12 | /// 链表节点 13 | struct Node { 14 | // TODO: YOUR CODE HERE 15 | marker: PhantomData, // 可以去掉 16 | } 17 | 18 | /// 链表迭代器 19 | pub struct Iter<'a, T> { 20 | // TODO: YOUR CODE HERE 21 | marker: PhantomData<&'a T>, 22 | } 23 | 24 | /// 链表可变迭代器 25 | pub struct IterMut<'a, T> { 26 | // TODO: YOUR CODE HERE 27 | marker: PhantomData<&'a mut T>, 28 | } 29 | 30 | impl LinkedList { 31 | /// 创建一个空链表 32 | pub fn new() -> Self { 33 | // Self { 34 | // // TODO: YOUR CODE HERE 35 | // marker: PhantomData, 36 | // } 37 | unimplemented!() 38 | } 39 | 40 | /// 将元素插入到链表头部 41 | /// 42 | /// # Examples 43 | /// ``` 44 | /// use linked_list::double_linked_list::LinkedList; 45 | /// let mut list = LinkedList::new(); 46 | /// list.push_front(1); 47 | /// assert_eq!(list.front(), Some(&1)); 48 | /// ``` 49 | pub fn push_front(&mut self, _elem: T) { 50 | // TODO: YOUR CODE HERE 51 | unimplemented!() 52 | } 53 | 54 | /// 将元素插入到链表尾部 55 | /// 56 | /// # Examples 57 | /// ``` 58 | /// use linked_list::double_linked_list::LinkedList; 59 | /// let mut list = LinkedList::new(); 60 | /// list.push_back(1); 61 | /// assert_eq!(list.back(), Some(&1)); 62 | /// ``` 63 | pub fn push_back(&mut self, _elem: T) { 64 | // TODO: YOUR CODE HERE 65 | unimplemented!() 66 | } 67 | 68 | /// 将第一个元素返回 69 | /// 70 | /// # Examples 71 | /// ``` 72 | /// use linked_list::double_linked_list::LinkedList; 73 | /// let mut list = LinkedList::new(); 74 | /// list.push_front(1); 75 | /// assert_eq!(list.pop_front(), Some(1)); 76 | /// ``` 77 | pub fn pop_front(&mut self) -> Option { 78 | // TODO: YOUR CODE HERE 79 | unimplemented!() 80 | } 81 | 82 | /// 将最后一个元素返回 83 | /// 84 | /// # Examples 85 | /// ``` 86 | /// use linked_list::double_linked_list::LinkedList; 87 | /// let mut list = LinkedList::new(); 88 | /// list.push_back(1); 89 | /// assert_eq!(list.pop_back(), Some(1)); 90 | /// ``` 91 | pub fn pop_back(&mut self) -> Option { 92 | // TODO: YOUR CODE HERE 93 | unimplemented!() 94 | } 95 | 96 | /// 返回链表第一个元素的引用 97 | /// 98 | /// # Examples 99 | /// ``` 100 | /// use linked_list::double_linked_list::LinkedList; 101 | /// let mut list = LinkedList::new(); 102 | /// assert_eq!(list.front(), None); 103 | /// list.push_front(1); 104 | /// assert_eq!(list.front(), Some(&1)); 105 | /// ``` 106 | pub fn front(&self) -> Option<&T> { 107 | // TODO: YOUR CODE HERE 108 | unimplemented!() 109 | } 110 | 111 | /// 返回链表第一个元素的可变引用 112 | pub fn front_mut(&mut self) -> Option<&mut T> { 113 | // TODO: YOUR CODE HERE 114 | unimplemented!() 115 | } 116 | 117 | /// 返回链表最后一个元素的引用 118 | /// 119 | /// # Examples 120 | /// ``` 121 | /// use linked_list::double_linked_list::LinkedList; 122 | /// let mut list = LinkedList::new(); 123 | /// assert_eq!(list.back(), None); 124 | /// list.push_back(1); 125 | /// assert_eq!(list.back(), Some(&1)); 126 | /// ``` 127 | pub fn back(&self) -> Option<&T> { 128 | // TODO: YOUR CODE HERE 129 | unimplemented!() 130 | } 131 | 132 | /// 返回链表最后一个元素的可变引用 133 | pub fn back_mut(&mut self) -> Option<&mut T> { 134 | // TODO: YOUR CODE HERE 135 | unimplemented!() 136 | } 137 | 138 | /// 返回链表长度 139 | /// 140 | /// # Examples 141 | /// ``` 142 | /// use linked_list::double_linked_list::LinkedList; 143 | /// let mut list = LinkedList::new(); 144 | /// list.push_back(1); 145 | /// assert_eq!(list.len(), 1); 146 | /// ``` 147 | pub fn len(&self) -> usize { 148 | // TODO: YOUR CODE HERE 149 | unimplemented!() 150 | } 151 | 152 | /// 判断链表是否为空 153 | pub fn is_empty(&self) -> bool { 154 | self.len() == 0 155 | } 156 | 157 | /// 清空链表 158 | /// 159 | /// # Examples 160 | /// ``` 161 | /// use linked_list::double_linked_list::LinkedList; 162 | /// let mut list = LinkedList::new(); 163 | /// list.push_back(1); 164 | /// list.push_back(2); 165 | /// assert_eq!(list.len(), 2); 166 | /// list.clear(); 167 | /// assert_eq!(list.len(), 0); 168 | /// ``` 169 | pub fn clear(&mut self) { 170 | // Oh look it's drop again 171 | while self.pop_front().is_some() {} 172 | } 173 | 174 | /// 返回一个迭代器 175 | pub fn iter(&self) -> Iter { 176 | // Iter { 177 | // // TODO: YOUR CODE HERE 178 | // marker : PhantomData, 179 | // } 180 | unimplemented!(); 181 | } 182 | 183 | /// 返回一个可变迭代器 184 | pub fn iter_mut(&mut self) -> IterMut { 185 | // IterMut { 186 | // // TODO: YOUR CODE HERE 187 | // marker: PhantomData, 188 | // } 189 | unimplemented!(); 190 | } 191 | 192 | /// 获取链表中指定位置的元素 193 | /// 如果超出范围,使用panic!宏抛出异常 194 | /// ``` 195 | /// use linked_list::double_linked_list::LinkedList; 196 | /// let mut list = LinkedList::new(); 197 | /// list.push_back(1); 198 | /// assert_eq!(list.get(0), &1); 199 | /// ``` 200 | pub fn get(&self, _at: usize) -> &T { 201 | // TODO: YOUR CODE HERE 202 | unimplemented!(); 203 | } 204 | 205 | /// 获取链表中指定位置的可变元素 206 | pub fn get_mut(&mut self, _at: usize) -> &mut T { 207 | // TODO: YOUR CODE HERE 208 | unimplemented!(); 209 | } 210 | 211 | /// 将元素插入到**下标为i**的位置 212 | /// 如果超出范围,使用panic!宏抛出异常 213 | /// 214 | /// # Examples 215 | /// ``` 216 | /// use linked_list::double_linked_list::LinkedList; 217 | /// let mut list = LinkedList::new(); 218 | /// list.insert(0,1); 219 | /// list.insert(1,3); 220 | /// list.insert(1,2); 221 | /// assert_eq!(list.get(0), &1); 222 | /// assert_eq!(list.get(1), &2); 223 | /// assert_eq!(list.get(2), &3); 224 | /// ``` 225 | pub fn insert(&mut self, _at: usize, _data: T) { 226 | // TODO: YOUR CODE HERE 227 | unimplemented!(); 228 | } 229 | 230 | /// 移除链表中下标为i的元素 231 | /// 如果超出范围,使用panic!宏抛出异常 232 | /// 233 | /// # Examples 234 | /// ``` 235 | /// use linked_list::double_linked_list::LinkedList; 236 | /// let mut list = LinkedList::from_iter(vec![1,2,3]); 237 | /// assert_eq!(list.remove(1), 2); 238 | pub fn remove(&mut self, _at: usize) -> T { 239 | // TODO: YOUR CODE HERE 240 | unimplemented!(); 241 | } 242 | 243 | /// 将链表分割成两个链表,原链表为[0,at-1],新链表为[at,len-1]。 244 | /// 如果超出范围,使用panic!宏抛出异常 245 | /// 246 | /// # Examples 247 | /// ``` 248 | /// use linked_list::double_linked_list::LinkedList; 249 | /// let mut list = LinkedList::from_iter(vec![1,2,3,4,5]); 250 | /// let new = list.split_off(2); // list = [1,2], new = [3,4,5] 251 | /// assert_eq!(list.len(), 2); 252 | /// assert_eq!(list.pop_front(), Some(1)); 253 | /// assert_eq!(list.pop_front(), Some(2)); 254 | pub fn split_off(&mut self, _at: usize) -> LinkedList { 255 | // TODO: YOUR CODE HERE 256 | unimplemented!(); 257 | } 258 | 259 | /// 查找链表中第一个满足条件的元素 260 | /// 261 | /// # Examples 262 | /// ``` 263 | /// use linked_list::double_linked_list::LinkedList; 264 | /// let mut list = LinkedList::from_iter(vec![1,2,3]); 265 | /// assert_eq!(list.find_mut(|x| x % 2 == 0), Some(&mut 2)); 266 | /// assert_eq!(list.find_mut(|x| x % 4 == 0), None); 267 | /// ``` 268 | pub fn find_mut

(&mut self,predicate:P)->Option<&mut T> where P:Fn(&T) -> bool{ 269 | // TODO: YOUR CODE HERE 270 | unimplemented!(); 271 | } 272 | } 273 | 274 | impl LinkedList { 275 | /// 判断链表中是否包含某个元素 276 | /// 277 | /// # Examples 278 | /// ``` 279 | /// use linked_list::double_linked_list::LinkedList; 280 | /// let mut list = LinkedList::new(); 281 | /// list.push_back(1); 282 | /// assert_eq!(list.contains(&1), true); 283 | /// assert_eq!(list.contains(&2), false); 284 | /// ``` 285 | pub fn contains(&mut self, _data: &T) -> bool { 286 | // TODO: YOUR CODE HERE 287 | unimplemented!(); 288 | } 289 | } 290 | 291 | impl<'a, T> IntoIterator for &'a LinkedList { 292 | type IntoIter = Iter<'a, T>; 293 | type Item = &'a T; 294 | 295 | fn into_iter(self) -> Self::IntoIter { 296 | self.iter() 297 | } 298 | } 299 | 300 | impl<'a, T> IntoIterator for &'a mut LinkedList { 301 | type IntoIter = IterMut<'a, T>; 302 | type Item = &'a mut T; 303 | 304 | fn into_iter(self) -> Self::IntoIter { 305 | self.iter_mut() 306 | } 307 | } 308 | 309 | impl<'a, T> Iterator for Iter<'a, T> { 310 | type Item = &'a T; 311 | 312 | // 返回下一个元素,当没有元素可返回时,返回None 313 | fn next(&mut self) -> Option { 314 | // TODO: YOUR CODE HERE 315 | unimplemented!(); 316 | } 317 | 318 | // 返回(self.len, Some(self.len))即可 319 | fn size_hint(&self) -> (usize, Option) { 320 | // TODO: YOUR CODE HERE 321 | unimplemented!(); 322 | } 323 | } 324 | impl<'a, T> Iterator for IterMut<'a, T> { 325 | type Item = &'a mut T; 326 | 327 | fn next(&mut self) -> Option { 328 | // TODO: YOUR CODE HERE 329 | unimplemented!(); 330 | } 331 | 332 | fn size_hint(&self) -> (usize, Option) { 333 | // TODO: YOUR CODE HERE 334 | unimplemented!(); 335 | } 336 | } 337 | 338 | impl<'a, T> DoubleEndedIterator for Iter<'a, T> { 339 | // 返回前一个元素 340 | fn next_back(&mut self) -> Option { 341 | // TODO: YOUR CODE HERE 342 | unimplemented!(); 343 | } 344 | } 345 | 346 | impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { 347 | fn next_back(&mut self) -> Option { 348 | // TODO: YOUR CODE HERE 349 | unimplemented!(); 350 | } 351 | } 352 | 353 | /// 提供归并排序的功能 354 | pub trait MergeSort { 355 | /// 就地进行归并排序,按从小到大排序 356 | fn merge_sort(&mut self); 357 | } 358 | 359 | impl LinkedList { 360 | // 你可以在这里添加你需要的辅助函数 361 | } 362 | 363 | impl MergeSort for LinkedList { 364 | fn merge_sort(&mut self) { 365 | // TODO: YOUR CODE HERE 366 | unimplemented!(); 367 | } 368 | } 369 | 370 | impl Drop for LinkedList { 371 | fn drop(&mut self) { 372 | // Pop until we have to stop 373 | while self.pop_front().is_some() {} 374 | } 375 | } 376 | 377 | impl Default for LinkedList { 378 | fn default() -> Self { 379 | Self::new() 380 | } 381 | } 382 | 383 | impl Clone for LinkedList { 384 | fn clone(&self) -> Self { 385 | let mut new_list = Self::new(); 386 | for item in self { 387 | new_list.push_back(item.clone()); 388 | } 389 | new_list 390 | } 391 | } 392 | impl Extend for LinkedList { 393 | fn extend>(&mut self, iter: I) { 394 | for item in iter { 395 | self.push_back(item); 396 | } 397 | } 398 | } 399 | impl FromIterator for LinkedList { 400 | fn from_iter>(iter: I) -> Self { 401 | let mut list = Self::new(); 402 | list.extend(iter); 403 | list 404 | } 405 | } 406 | 407 | impl Debug for LinkedList { 408 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 409 | f.debug_list().entries(self).finish() 410 | } 411 | } 412 | 413 | impl PartialEq for LinkedList { 414 | fn eq(&self, other: &Self) -> bool { 415 | self.len() == other.len() && self.iter().eq(other) 416 | } 417 | } 418 | 419 | impl Eq for LinkedList {} 420 | 421 | impl PartialOrd for LinkedList { 422 | fn partial_cmp(&self, other: &Self) -> Option { 423 | self.iter().partial_cmp(other) 424 | } 425 | } 426 | 427 | impl Ord for LinkedList { 428 | fn cmp(&self, other: &Self) -> Ordering { 429 | self.iter().cmp(other) 430 | } 431 | } 432 | 433 | impl Hash for LinkedList { 434 | fn hash(&self, state: &mut H) { 435 | self.len().hash(state); 436 | for item in self { 437 | item.hash(state); 438 | } 439 | } 440 | } 441 | 442 | unsafe impl Send for LinkedList {} 443 | unsafe impl Sync for LinkedList {} 444 | 445 | unsafe impl<'a, T: Send> Send for Iter<'a, T> {} 446 | unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {} 447 | 448 | unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} 449 | unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} 450 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OS LAB 1 Rust与双链表 2 | 3 | 提交截止时间:2023年3月20日24时 4 | 5 | [TOC] 6 | 7 | ## 简介 8 | 9 | 在这个实验中,你需要自学**Rust**语言,并根据提示实现一个简单的**双链表**(可以使用Unsafe)。 10 | 11 | 这是一个单人项目,你需要**独立完成**项目。我们提供了若干测试用例,你的代码需要能够通过测试用例。作为我们评分的标准,你需要提交**代码**以及一份简短的**实验报告**。实验报告的内容可以包括下面的三个部分: 12 | 13 | * Rust学习心得 or 笔记 or 学习记录 14 | * 简要描述你的整体设计 15 | * 对Rust实现链表其他方法的探究 or 实验中遇到的困难 or 对本实验的内容和难度的反馈 16 | 17 | 共2页左右即可。 18 | 19 | 我们推荐你使用以下两本书进行学习: 20 | 21 | * [Rust圣经](https://course.rs/about-book.html) 22 | * [Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/#learn-rust-with-entirely-too-many-linked-lists)(中文版:[手把手带你实现链表](https://course.rs/too-many-lists/intro.html#手把手带你实现链表)) 23 | 24 | 前者你可以学习到Rust的基本语法,而后者可以帮助你完成这个lab。你可能并不需要完整地看完它们的全部内容。但是下面这些知识点你可能会用到: 25 | 26 | * [生命周期](https://course.rs/advance/lifetime/intro.html) 27 | * [迭代器](https://course.rs/advance/functional-programing/iterator.html) 28 | * [智能指针](https://course.rs/advance/smart-pointer/box.html) 29 | * [循环引用与自引用](https://course.rs/advance/circle-self-ref/intro.html) 30 | * [闭包 Closure](https://course.rs/advance/functional-programing/closure.html) 31 | * [使用 use 及受限可见性](https://course.rs/basic/crate-module/use.html) 32 | * [泛型和特征](https://course.rs/basic/trait/intro.html) 33 | * [标准库的双链表实现](https://rust-unofficial.github.io/too-many-lists/sixth.html) 34 | 35 | 如果你希望更深入的学习Rust,或者你觉得某方面的知识点没有理解,你还可以参考以下视频和文档: 36 | 37 | * [Rust 程序设计语言](https://kaisery.github.io/trpl-zh-cn/) 38 | * [通过例子学 Rust](https://rustwiki.org/zh-CN/rust-by-example/) 39 | * [清华计算机系大一学生2022暑期课程:Rust程序设计训练(有课程视频)](https://lab.cs.tsinghua.edu.cn/rust/) 40 | * [rust-lang/rustlings: Small exercises to get you used to reading and writing Rust code!](https://github.com/rust-lang/rustlings) 41 | 42 | ## 评分标准 43 | 44 | | 部分 | 子项 | 分值 | 45 | | ------ | ------------------------------------------------------------ | --------------------------------------------- | 46 | | Part 1 | - | `test_rev_for_loop``test_iter`5分,其余5个每个测试点4分,共30分 | 47 | | Part 2 | - | `test_get`,`test_remove`,`test_insert` 每个7分,其他(3个)每个8分,共45分 | 48 | | Part 3 | | 选做 | 49 | | 报告 | - | 25分 | 50 | | 总分 | | 100分 | 51 | 52 | 53 | 54 | ## 环境的搭建和项目说明 55 | 56 | 本小节将介绍如何搭建一个Rust环境,并运行项目中的测试。你可以直接参考[安装 Rust 环境 - Rust语言圣经(Rust Course)](https://course.rs/first-try/installation.html)搭建环境。 57 | 58 | ### Windows 下Rust的安装 59 | 60 | 点击链接[Rust安装包](https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe) 下载,或者在[Rust网站](https://www.rust-lang.org/learn/get-started)上面找到对应的链接。 61 | 62 | ![1](assets/2.png) 63 | 64 | 你可以选择1使用msvc版本,需要下载Microsoft C++ Build Tools(如果没装过VS Studio, 会自动安装,需要5GB空间);或者安装在msys上面(见[安装 Rust 环境 - Rust语言圣经(Rust Course)](https://course.rs/first-try/installation.html#在-windows-上安装-rustup))。 65 | 66 | 安装的流程一路按确定就可以: 67 | 68 | ![1](assets/9.png) 69 | 70 | ![1](assets/10.png) 71 | 72 | 自动安装完成后,旁边的控制台会打印类似这样的输出: 73 | 74 | ![1](assets/11.png) 75 | 76 | 输入1,默认安装即可。 77 | 78 | > 你可能会因为网络原因无法下载成功,这时可以切换源进行下载。编辑系统环境变量,添加下面两个环境变量: 79 | > 80 | > RUSTUP_DIST_SERVER= 81 | > RUSTUP_UPDATE_ROOT= 82 | > 83 | > ![1](assets/12.png) 84 | > 85 | > ![1](assets/13.png) 86 | > 87 | > 重新打开rustup-init.exe即可 88 | 89 | 安装成功时,会看到这样的界面: 90 | 91 | ![1](assets/14.png) 92 | 93 | 这里提示说我们要配置以下环境变量。在PATH里面添加`%USERPROFILE%\.cargo\bin` 94 | 95 | ![1](assets/15.png) 96 | 97 | ![1](assets/16.png) 98 | 99 | 最后,可以在命令行下面验证是否安装完成 100 | 101 | ![1](assets/17.png) 102 | 103 | ### Linux和Mac OS下的安装 104 | 105 | 命令行中输入下面这行即可: 106 | 107 | ```bash 108 | curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh 109 | ``` 110 | 111 | > 你可能会因为网络原因无法下载成功,你可以直接在浏览器内输入链接访问下载,也可以切换镜像地址,下面是中科大的镜像服务器: 112 | > 113 | > ```bash 114 | > export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static 115 | > export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup 116 | > curl https://sh.rustup.rs -sSf | sh 117 | > ``` 118 | > 119 | > 如果要让代理永久生效的话,可以把环境变量加入到`bashrc`里面: 120 | > 121 | > ```bash 122 | > echo 'export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static' >> ~/.bashrc 123 | > echo 'export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup' >> ~/.bashrc 124 | > ``` 125 | 126 | 当运行成功时,你会遇到选择数字的界面,选择1即可: 127 | 128 | ![1](assets/1.png) 129 | 130 | 最后,运行下面的命令配置shell: 131 | 132 | ```bash 133 | source "$HOME/.cargo/env" 134 | ``` 135 | 136 | 你可以输入`rustc -V`查看rust版本,以验证是否安装成功。 137 | 138 | ### IDE环境 139 | 140 | 推荐使用vscode作为IDE,也可以使用CLion。 141 | 142 | Vscode链接:[Windows](https://vscode.cdn.azure.cn/stable/1ad8d514439d5077d2b0b7ee64d2ce82a9308e5a/VSCodeUserSetup-x64-1.74.1.exe), [Mac OS](https://vscode.cdn.azure.cn/stable/e8a3071ea4344d9d48ef8a4df2c097372b0c5161/VSCode-darwin-universal.zip) 143 | 144 | 在Vsode Extensions中,找到rust-analyzer,Install即可 145 | 146 | ![1](assets/3.png) 147 | 148 | > 如果下载插件用时过久,可以尝试使用代理。参考这篇说明:[Visual Studio Code代理设置](https://device.harmonyos.com/cn/docs/documentation/guide/vscode_proxy-0000001074231144) 149 | 150 | ### 运行项目的测试 151 | 152 | 使用vscode打开项目的目录。打开src/tests.rs文件。如果插件运行正常,你会看到类似这样的按钮: 153 | 154 | ![1](assets/4.png) 155 | 156 | 点击Run Tests,就可以运行测试;如果你安装了gdb等调试器,在需要断点的行号位置点击一下,点击Debug就可以进行断点和调试了。 157 | 158 | 当测试失败时,你会看到红色的提示,以及对应调用栈。你可以找到错误的行号; 159 | 160 | ![1](assets/5.png) 161 | 162 | 而当测试通过时,你会看到绿色的提示。 163 | 164 | ![1](assets/6.png) 165 | 166 | 对于答案错误的情形,你还会看到期望的结果和输出的结果: 167 | 168 | ![1](assets/7.png) 169 | 170 | 在`src/libs.rs`中,我们提供了运行多个测试的函数,你可以点击`run tests`进行测试。或者使用cargo命令运行单元测试。 171 | 172 | ### 项目文件说明 173 | 174 | ``` 175 | . 176 | ├── Cargo.lock cargo生成的文件,用于管理依赖 177 | ├── Cargo.toml 用户配置包管理的地方 178 | ├── README.md 实验指导手册 markdown 版本 179 | ├── README.pdf 实验指导手册 pdf 版本 180 | ├── assets 实验指导手册的图片等资源 181 | └── src 项目源代码 182 | ├── double_linked_list.rs * 双链表的实现 (主要需要实现的部分) 183 | ├── lib.rs 管理对外接口;这里还提供了一些测试函数。 184 | └── tests.rs 测试用例 185 | ``` 186 | 187 | ### 需要实现的部分 188 | 189 | 你需要补全`src/double_linked_list.rs`中的代码,并让它通过对应的测试。我们已经在你需要补充的部分加上了`TODO: YOUR CODE HERE` 的标记,你可以在拓展中心安装`TODO Hightlight` 插件以得到一个醒目的标记。 190 | ![标记](assets/8.png) 191 | 当然,如果需要的话,你可以在其他地方添加代码。 192 | 193 | 在编写时,你需要先删掉`unimplemented`;对于`PhantomData`,你可以删掉也可以保留。 194 | 195 | 在一些函数中,参数的变量使用`_`作为前缀,表明这个函数没有被用到;当你用到这个参数时,建议把`_`前缀删掉。 196 | 197 | > `PhantomData` 的作用是什么? 198 | > 199 | > 在这里,我们主要用PhantomData来表示未使用的生命周期和类型参数。例如,迭代器中需要取链表元素的引用,这时候需要一个生命周期。而如果你用的是类似裸指针直接指向链表元素的方式,那结构体里就没有带引用的成员,不能加上`'a`的生命周期符号 200 | > 201 | > ``` 202 | > impl<'a, T> Iterator for Iter { 203 | > type Item = &'a T; 204 | > 205 | > // ..... 206 | > } 207 | > ``` 208 | > 209 | > 这时候编译器会提示说`the lifetime parameter 'a is not constrained by the impl trait, self type, or predicate`。 210 | > 211 | > 因此我们需要在Iter上面添加生命周期符号。`PhantomData` 就是这样一种解决方式。它是一种零成本抽象,本身不占空间,只是让编译器以为当前结构体会拥有一个生命周期为'a的成员,从而通过编译。你可以阅读[官方的文档和例子](https://doc.rust-lang.org/std/marker/struct.PhantomData.html)深入了解。 212 | > 213 | > 让编译器以为结构体拥有类型的所有权还可以让编译器进行drop check,感兴趣可以阅读这个关于Box实现的博客:[讲讲让我熬了几天夜的Drop Check](https://ng6qpa7sht.feishu.cn/docx/LGnVdlqwGoIUpuxUMWRcptEbndd) 214 | 215 | ## Part 1 链表的基本功能 216 | 217 | 在Rust实现一个安全,高效的双链表是比较复杂的。Rust 非常注重安全性和内存管理。在 Rust 中,你需要清楚地指定哪些对象可以使用哪些资源,以及在何时何地释放这些资源。这就是所谓的所有权(ownership)和借用(borrowing)机制。 218 | 219 | 为实现指针的效果,常见的工具有所有权,引用,智能指针。所有权不适用于链表,在所有权的情况下,前驱和后继不能互为owner。引用可能会出现生命周期有问题的情况。比如有时候需要后面的节点生命周期比前面长,有时候则要反过来。解决引用生命周期问题可以使用智能指针`Rc`(引用计数)。引用还有一个问题,就是不能对一个对象同时可变引用多次。这个问题使用`RefCell`(内部可变性)解决。`RefCell`告诉编译器这个结构体是不可变的(实际上内部是可变的)。因此,实现单链表的一个经典组合是`Rc>>`。但是放到双链表上面,这个组合会有一些问题。因为每个节点都有两个指针,因此会产生一个循环计数。如果用运行时检查可以解决部分问题,但是实现迭代器可能无法返回引用:[不太优秀的双端队列-迭代器](https://course.rs/too-many-lists/deque/iterator.html)。 220 | 221 | 目前的双链表的实现方案有很多: 222 | 223 | * 使用`Weak`智能指针。把两个`Rc>>`的一个指针换成弱指针。例如,这里把所有的prev指针换成了Weak的指针:[50行在stable,safe Rust实现双链表](https://play.rust-lang.org/?gist=71c6bc45ff92452d5a4397ddb2dbb3de&version=stable) 224 | 225 | * 使用`unsafe`,像C/C++那样手动管理指针。这也是`collections::Linkedlist`中的实现方案。具体来说,就是管理节点的时候就用box::from_raw/into_raw来添加节点,直接使用裸指针解引用来访问数据。 226 | * 使用`arena`([Region-based memory management](https://en.wikipedia.org/wiki/Region-based_memory_management))。`Arenas` 本质上是一种将预期生命周期相同的内存进行分组的模式。比如说有时需要在某个生命周期内分配一堆对象,之后这些对象将被全部销毁。这可以简单理解为一个堆空间。我们可以用类似C/C++中的方式new一个对象,然后显式地释放(不释放也可以,后面一起销毁)。这样就规避了Rust中声明周期的问题。关于`arena`的库,可以参考:[「译」Arenas in Rust](https://rustmagazine.github.io/rust_magazine_2021/chapter_3/arenas-in-rust.html#译arenas-in-rust)。同时,这里也有一个实现链表的例子:[基于slotmap实现链表](https://www.zhihu.com/question/54265676/answer/1679897001) 227 | * `crossbeam-epoch`: 这是一种基于epoch的无锁GC。相当于自动帮我们管理声明周期了,这也就没有之前的那么多问题了。 228 | * `GhostCell+StaticRc` : `GhostCell` 提供了一种零开销的内部可变机制,`StaticRc`则提供了零开销的共享所有权机制,可以结合二者实现安全零开销链表。 229 | 230 | 在这一部分,你可以阅读[Learning Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/)其中的An Ok Unsafe Queue和A Production Unsafe Deque章节来设计和实现你的链表。 231 | 232 | 首先,你需要完善`struct LinkedList` 和`struct Node` 的结构体,并完成下面的方法: 233 | 234 | * `new` 235 | * `len` 236 | * `front` 237 | * `front_mut` 238 | * `back` 239 | * `back_mut` 240 | 241 | 它们都仅需要几行代码就能完成。 242 | 243 | 接下来开始处理插入操作。 244 | 245 | * `push_front` 246 | * `pop_front` 247 | * `push_back` 248 | * `pop_back` 249 | 250 | 它们的语义和函数名相同,你也可以参考函数名上的注释。 251 | 252 | 如果你的实现正确,你应该可以通过: 253 | 254 | * `test_front` 255 | * `test_back` 256 | * `test_len` 257 | 258 | 3个测试。 259 | 260 | > 你可以在项目根目录打开一个命令行,运行`cargo test test_front`,`cargo test test_back`逐一运行测试,也可以通过vscode点击测试函数上的run test运行测试。 261 | > 262 | > 在lib.rs中,我们提供了一次运行多个测试的函数`test_part1`,你可以一次运行多个测试点。 263 | 264 | --- 265 | 266 | 接下来是迭代器部分。迭代器是一个维护链表迭代的数据结构。你可以先尝试实现一个单向的迭代器,这可能需要一个指向当前迭代数据的指针,数据的长度。完善`Iter`和`IterMut`之后,为链表提供一个返回迭代器的接口`iter`和`iter_mut` 267 | 268 | 然后我们为迭代器实现`Iterator trait` 。这个trait(可以认为是接口)要求我们实现`next`和`size_hint`两个函数。`next`返回一个元素,并把迭代器指针往后移动。`size_hint`需要返回元素下界和上界。`size_hint()` 主要用于优化,比如为迭代器的元素保留空间。你可以直接返回(链表长度,Some(链表长度))。 269 | 270 | 最后为链表实现反向的迭代。修改`Iter`使其包含一个反向的指针,然后为迭代器实现`DoubleEndedIterator` 的trait。 271 | 272 | 如果你的实现正确,你应该可以通过: 273 | 274 | * `test_iter` 275 | * `test_iter_mut` 276 | * `test_for_loop` 277 | * `test_rev_for_loop` 278 | 279 | 4个测试。 280 | 281 | ## Part 2 6个简单的链表操作 282 | 283 | 下面你需要自己实现6个简单的链表操作: 284 | 285 | * `get/get_mut` : 获取下标为at的元素的引用 286 | * `remove` : 删除下标为at的元素 287 | * `insert` : 插入一个元素到指定位置 288 | * `contains` : 判断链表内是否存在元素 289 | * `split_off`:将链表分割成两个链表,原链表为[0,at-1],新链表为[at,len-1] 290 | * `find_mut` : 找到链表中满足匹配条件的元素,返回它的引用 291 | 292 | 如果上面的表述不清楚,你可以参考这些函数上面的注释中的`examples`。 293 | 294 | 如果你的实现正确,你应该可以通过: 295 | 296 | * `test_get` 297 | * `test_remove` 298 | * `test_insert` 299 | * `test_contains` 300 | * `test_split` 301 | * `test_find_mut` 302 | 303 | 6个测试。 304 | 305 | ## Part 3 归并排序(选做) 306 | 307 | 在这一部分,你需要给链表写一个**就地**的归并排序。如果你忘了归并排序怎么写,你可以参考[leetcode 链表排序](https://leetcode.cn/problems/7WHec2/)的实现。 308 | 309 | 下面是递归实现的[伪代码](https://en.wikipedia.org/wiki/Merge_sort): 310 | 311 | ```pseudocode 312 | function merge_sort(list m) is 313 | // Base case. A list of zero or one elements is sorted, by definition. 314 | if length of m ≤ 1 then 315 | return m 316 | 317 | // Recursive case. First, divide the list into equal-sized sublists 318 | // consisting of the first half and second half of the list. 319 | // This assumes lists start at index 0. 320 | var left := empty list 321 | var right := empty list 322 | for each x with index i in m do 323 | if i < (length of m)/2 then 324 | add x to left 325 | else 326 | add x to right 327 | 328 | // Recursively sort both sublists. 329 | left := merge_sort(left) 330 | right := merge_sort(right) 331 | 332 | // Then merge the now-sorted sublists. 333 | return merge(left, right) 334 | 335 | function merge(left, right) is 336 | var result := empty list 337 | 338 | while left is not empty and right is not empty do 339 | if first(left) ≤ first(right) then 340 | append first(left) to result 341 | left := rest(left) 342 | else 343 | append first(right) to result 344 | right := rest(right) 345 | 346 | // Either left or right may have elements left; consume them. 347 | // (Only one of the following loops will actually be entered.) 348 | while left is not empty do 349 | append first(left) to result 350 | left := rest(left) 351 | while right is not empty do 352 | append first(right) to result 353 | right := rest(right) 354 | return result 355 | ``` 356 | 357 | 如果你需要为你的实现添加辅助函数,可以在`impl LinkedList`块中进行编写。 358 | 359 | 如果你的实现正确,你应该可以通过: 360 | 361 | * `test_merge_sort1` 362 | * `test_merge_sort2` 363 | * `test_merge_sort3` 364 | 365 | 3个测试 366 | 367 | ## 提交 368 | 369 | 你需要提交一个`git patch`到我们的平台上。报告可能会交到ucloud上面,也可能在同一平台。 370 | 371 | 在提交之前,你应该在本地运行测试,服务器上的测试数据和本地是相同的,只是为了检查你的完成情况。因此不必频繁提交。 372 | 373 | 首先需要安装一个git。 374 | 375 | 你可以在git官网找到对应的下载链接,双击安装包安装即可(中间的选项可以直接一路Next),如果使用debian,ubuntu,可以直接使用`sudo apt install -y git`来安装。 376 | 377 | 安装好git后,可以使用`git --version`查看git版本 378 | 379 | 接下来,切换到我们的项目下面,配置一下用户名和邮箱。 380 | 381 | ```bash 382 | git config user.name "<用户名>" 383 | git config user.email "<邮箱>" 384 | ``` 385 | 386 | 我们暂时不使用git中的邮箱作为判定账户的依据,因此这里随便填一个也可以。 387 | 388 | ### commit 389 | 390 | 首先,你需要为你的代码生成一个commit。一般来说,你只要提交`src/double_linked_list.rs`的修改。 391 | 392 | 你可以使用命令行或者vscode来实现这个操作。 393 | 394 | #### 命令行 395 | 396 | 在你完成全部或者部分练习后,可以git add <文件名>来添加对一个文件的修改。例如,`git add src/double_linked_list.rs`。 397 | 398 | 然后,`git commit -m ""`来创建一个commit。 399 | 400 | 如果你commit完后悔了,要恢复上一个版本,可以使用`git reset --soft HEAD^` 401 | 402 | #### vscode 403 | ![1](assets/git_command.jpg) 404 | 点击切换到vscode的git面板,然后在Changes里面的文件中找到你要添加的修改文件。点击上面的加号确认修改,在Message框中输入commit的信息,最后点击Commit创建一个commitment。 405 | 406 | ### patch 407 | 408 | 在完成练习后,你需要生成一个git patch。 409 | 410 | 使用`git log`查看之前的commit id,复制后,按`q`退出。 411 | 412 | 找到你提交的commit范围 413 | 414 | ```bash 415 | git format-patch --stdout .. > example.patch 416 | # 或者 417 | git format-patch --stdout -<向前n个commit> HEAD > example.patch 418 | # 只有一个commit就可以用 419 | git format-patch -1 HEAD --stdout > example.patch 420 | ``` 421 | 422 | 就会在当前目录下面创建一个`example.patch`文件,你只需要提交这个文件就可以了。 423 | 424 | 例如下图中,commit id的范围是5d87bc88d72d 到 a181054e61cda75, 425 | ![1](assets/git_patch.jpg) 426 | 427 | 因此可以用: 428 | 429 | ``` 430 | git format-patch --stdout 5d87bc88d72d..a181054e61cda75 > example.patch 431 | ``` 432 | 433 | ### 在平台上提交 434 | 435 | 我们搭建了一个网站来接收和运行git patch,目前的url为: 436 | 437 | 登录后,将文件在提交界面上传即可。 438 | ![1](assets/submit.jpg) 439 | 你可以看到运行的结果和日志输出。 440 | --------------------------------------------------------------------------------