├── .gitignore ├── CNAME ├── README.md ├── assets ├── baidu_verify_code-6xpiXNfMYY.html └── mini-redis │ ├── .github │ └── workflows │ │ └── ci.yml │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ ├── examples │ ├── chat.rs │ ├── hello_world.rs │ ├── pub.rs │ └── sub.rs │ ├── src │ ├── bin │ │ ├── cli.rs │ │ └── server.rs │ ├── blocking_client.rs │ ├── buffer.rs │ ├── client.rs │ ├── cmd │ │ ├── get.rs │ │ ├── mod.rs │ │ ├── publish.rs │ │ ├── set.rs │ │ ├── subscribe.rs │ │ └── unknown.rs │ ├── connection.rs │ ├── db.rs │ ├── frame.rs │ ├── lib.rs │ ├── parse.rs │ ├── server.rs │ └── shutdown.rs │ └── tests │ ├── buffer.rs │ ├── client.rs │ └── server.rs ├── book.toml ├── deploy └── src ├── SUMMARY.md ├── about-book.md ├── cipher ├── another-rot13.md ├── caesar.md ├── index.md ├── morse-code.md ├── polibius.md ├── rot13.md ├── sha256.md ├── vigenere.md └── xor.md ├── data-structures ├── avl-tree.md ├── b-tree.md ├── binary-search-tree.md ├── circular-queue.md ├── graph.md ├── heap.md ├── index.md ├── linked-list.md ├── queue.md ├── stack.md └── trie.md ├── dynamic-programming ├── coin-change.md ├── edit-distance.md ├── egg-dropping.md ├── fibonacci.md ├── index.md ├── is-subsequence.md ├── knapsack.md ├── longese-common-sequence.md ├── longest-increasing-subsequence.md ├── longest_continuous_increasing_subsequence.md ├── maximal-square.md ├── maximal-subarray.md └── rod-cutting.md ├── general ├── convex-hull.md ├── hanoi.md ├── index.md ├── kmeans.md ├── nqueens.md └── two-sum.md ├── geometry ├── closet-points.md └── index.md ├── graph ├── bellman-ford.md ├── breadth-first-search.md ├── depth-first-search.md ├── depth-first-tic-tac-toe.md ├── dijkstra.md ├── index.md ├── minimum-spanning-tree.md └── prim.md ├── leetcode ├── 001-two-sum.md └── index.md ├── math ├── extended-euclidean.md ├── greatest-common-divisor.md ├── index.md ├── pascal-triange.md ├── perfect-numbers.md ├── prime-check.md ├── prime-numbers.md └── trial-division.md ├── searching ├── binary-search-recursive.md ├── binary-search.md ├── index.md ├── kth-smallest.md └── linear-search.md ├── sorting ├── bubble-sort.md ├── bucket-sort.md ├── cocktail-shaker-sort.md ├── comb-sort.md ├── counting-sort.md ├── gnome-sort.md ├── heap-sort.md ├── index.md ├── insertion-sort.md ├── merge-sort.md ├── odd-even.md ├── quick-sort.md ├── radix-sort.md ├── selection-sort.md ├── shell-sort.md ├── stooge-sort.md └── timsort.md └── string ├── burrows-wheeler-transform.md ├── index.md ├── knuth-morris-pratt.md ├── manacher.md ├── rabin-karp.md └── reverse.md /.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | algos.rs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Rust算法题解 2 | Rust 作为一门现代化的系统编程语言,拥有与 C/C++ 类似的性能,同时又能做非常底层的性能优化,因此非常适合写算法和 leetcode。 3 | 4 | `algos` 涵盖了各种常用算法和数据结构的代码实现,以及 leetcode 题解,同时对于相关算法还提供了中文文档和注释,可以帮助大家更好、更快的学习。 5 | 6 | ## Rust 语言学习 7 | 如果大家熟悉算法,但是对于 Rust 语言还不够熟悉,可以看看 [Rust语言圣经](https://github.com/sunface/rust-course),它绝对是目前最优秀的 Rust 中文开源教程。 8 | 9 | ## 社区贡献者 10 | 我们深知自身水平的局限性,因此非常欢迎各路大神加入进来,共同打造这门未来可以在中国乃至全世界都排得上号的算法教程! 11 | 12 | -------------------------------------------------------------------------------- /assets/baidu_verify_code-6xpiXNfMYY.html: -------------------------------------------------------------------------------- 1 | 717a8be683db73a812bab355e948d1f7 -------------------------------------------------------------------------------- /assets/mini-redis/.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Build 17 | run: cargo build --verbose 18 | - name: Run tests 19 | run: cargo test --verbose 20 | - name: rustfmt 21 | uses: actions-rs/cargo@v1 22 | with: 23 | command: fmt 24 | args: --all -- --check 25 | -------------------------------------------------------------------------------- /assets/mini-redis/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /assets/mini-redis/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Carl Lerche "] 3 | edition = "2018" 4 | name = "mini-redis" 5 | version = "0.4.1" 6 | license = "MIT" 7 | readme = "README.md" 8 | documentation = "https://docs.rs/mini-redis/0.4.0/mini-redis/" 9 | repository = "https://github.com/tokio-rs/mini-redis" 10 | description = """ 11 | An incomplete implementation of a Rust client and server. Used as a 12 | larger example of an idiomatic Tokio application. 13 | """ 14 | 15 | [[bin]] 16 | name = "mini-redis-cli" 17 | path = "src/bin/cli.rs" 18 | 19 | [[bin]] 20 | name = "mini-redis-server" 21 | path = "src/bin/server.rs" 22 | 23 | [dependencies] 24 | async-stream = "0.3.0" 25 | atoi = "0.3.2" 26 | bytes = "1" 27 | structopt = "0.3.14" 28 | tokio = { version = "1", features = ["full"] } 29 | tokio-stream = "0.1" 30 | tracing = "0.1.13" 31 | tracing-futures = { version = "0.2.3" } 32 | tracing-subscriber = "0.2.2" 33 | 34 | [dev-dependencies] 35 | # Enable test-utilities in dev mode only. This is mostly for tests. 36 | tokio = { version = "1", features = ["test-util"] } 37 | -------------------------------------------------------------------------------- /assets/mini-redis/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Tokio Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /assets/mini-redis/examples/chat.rs: -------------------------------------------------------------------------------- 1 | #[tokio::main] 2 | async fn main() { 3 | unimplemented!(); 4 | } 5 | -------------------------------------------------------------------------------- /assets/mini-redis/examples/hello_world.rs: -------------------------------------------------------------------------------- 1 | //! Hello world server. 2 | //! 3 | //! A simple client that connects to a mini-redis server, sets key "hello" with value "world", 4 | //! and gets it from the server after 5 | //! 6 | //! You can test this out by running: 7 | //! 8 | //! cargo run --bin mini-redis-server 9 | //! 10 | //! And then in another terminal run: 11 | //! 12 | //! cargo run --example hello_world 13 | 14 | #![warn(rust_2018_idioms)] 15 | 16 | use mini_redis::{client, Result}; 17 | 18 | #[tokio::main] 19 | pub async fn main() -> Result<()> { 20 | // Open a connection to the mini-redis address. 21 | let mut client = client::connect("127.0.0.1:6379").await?; 22 | 23 | // Set the key "hello" with value "world" 24 | client.set("hello", "world".into()).await?; 25 | 26 | // Get key "hello" 27 | let result = client.get("hello").await?; 28 | 29 | println!("got value from the server; success={:?}", result.is_some()); 30 | 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /assets/mini-redis/examples/pub.rs: -------------------------------------------------------------------------------- 1 | //! Publish to a redis channel example. 2 | //! 3 | //! A simple client that connects to a mini-redis server, and 4 | //! publishes a message on `foo` channel 5 | //! 6 | //! You can test this out by running: 7 | //! 8 | //! cargo run --bin mini-redis-server 9 | //! 10 | //! Then in another terminal run: 11 | //! 12 | //! cargo run --example sub 13 | //! 14 | //! And then in another terminal run: 15 | //! 16 | //! cargo run --example pub 17 | 18 | #![warn(rust_2018_idioms)] 19 | 20 | use mini_redis::{client, Result}; 21 | 22 | #[tokio::main] 23 | async fn main() -> Result<()> { 24 | // Open a connection to the mini-redis address. 25 | let mut client = client::connect("127.0.0.1:6379").await?; 26 | 27 | // publish message `bar` on channel foo 28 | client.publish("foo", "bar".into()).await?; 29 | 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /assets/mini-redis/examples/sub.rs: -------------------------------------------------------------------------------- 1 | //! Subscribe to a redis channel example. 2 | //! 3 | //! A simple client that connects to a mini-redis server, subscribes to "foo" and "bar" channels 4 | //! and awaits messages published on those channels 5 | //! 6 | //! You can test this out by running: 7 | //! 8 | //! cargo run --bin mini-redis-server 9 | //! 10 | //! Then in another terminal run: 11 | //! 12 | //! cargo run --example sub 13 | //! 14 | //! And then in another terminal run: 15 | //! 16 | //! cargo run --example pub 17 | 18 | 19 | 20 | use mini_redis::{client, Result}; 21 | use tokio_stream::StreamExt; 22 | #[tokio::main] 23 | pub async fn main() -> Result<()> { 24 | // Open a connection to the mini-redis address. 25 | let client = client::connect("127.0.0.1:6379").await?; 26 | 27 | // subscribe to channel foo 28 | let mut subscriber = client.subscribe(vec!["foo".into()]).await?; 29 | let messages = subscriber.into_stream(); 30 | tokio::pin!(messages); 31 | // await messages on channel foo 32 | while let Some(msg) = messages.next().await { 33 | println!("got = {:?}", msg); 34 | } 35 | 36 | Ok(()) 37 | } 38 | -------------------------------------------------------------------------------- /assets/mini-redis/src/bin/cli.rs: -------------------------------------------------------------------------------- 1 | use mini_redis::{client, DEFAULT_PORT}; 2 | 3 | use bytes::Bytes; 4 | use std::num::ParseIntError; 5 | use std::str; 6 | use std::time::Duration; 7 | use structopt::StructOpt; 8 | 9 | #[derive(StructOpt, Debug)] 10 | #[structopt(name = "mini-redis-cli", author = env!("CARGO_PKG_AUTHORS"), about = "Issue Redis commands")] 11 | struct Cli { 12 | #[structopt(subcommand)] 13 | command: Command, 14 | 15 | #[structopt(name = "hostname", long = "--host", default_value = "127.0.0.1")] 16 | host: String, 17 | 18 | #[structopt(name = "port", long = "--port", default_value = DEFAULT_PORT)] 19 | port: String, 20 | } 21 | 22 | #[derive(StructOpt, Debug)] 23 | enum Command { 24 | /// Get the value of key. 25 | Get { 26 | /// Name of key to get 27 | key: String, 28 | }, 29 | /// Set key to hold the string value. 30 | Set { 31 | /// Name of key to set 32 | key: String, 33 | 34 | /// Value to set. 35 | #[structopt(parse(from_str = bytes_from_str))] 36 | value: Bytes, 37 | 38 | /// Expire the value after specified amount of time 39 | #[structopt(parse(try_from_str = duration_from_ms_str))] 40 | expires: Option, 41 | }, 42 | } 43 | 44 | /// Entry point for CLI tool. 45 | /// 46 | /// The `[tokio::main]` annotation signals that the Tokio runtime should be 47 | /// started when the function is called. The body of the function is executed 48 | /// within the newly spawned runtime. 49 | /// 50 | /// `flavor = "current_thread"` is used here to avoid spawning background 51 | /// threads. The CLI tool use case benefits more by being lighter instead of 52 | /// multi-threaded. 53 | #[tokio::main(flavor = "current_thread")] 54 | async fn main() -> mini_redis::Result<()> { 55 | // Enable logging 56 | tracing_subscriber::fmt::try_init()?; 57 | 58 | // Parse command line arguments 59 | let cli = Cli::from_args(); 60 | 61 | // Get the remote address to connect to 62 | let addr = format!("{}:{}", cli.host, cli.port); 63 | 64 | // Establish a connection 65 | let mut client = client::connect(&addr).await?; 66 | 67 | // Process the requested command 68 | match cli.command { 69 | Command::Get { key } => { 70 | if let Some(value) = client.get(&key).await? { 71 | if let Ok(string) = str::from_utf8(&value) { 72 | println!("\"{}\"", string); 73 | } else { 74 | println!("{:?}", value); 75 | } 76 | } else { 77 | println!("(nil)"); 78 | } 79 | } 80 | Command::Set { 81 | key, 82 | value, 83 | expires: None, 84 | } => { 85 | client.set(&key, value).await?; 86 | println!("OK"); 87 | } 88 | Command::Set { 89 | key, 90 | value, 91 | expires: Some(expires), 92 | } => { 93 | client.set_expires(&key, value, expires).await?; 94 | println!("OK"); 95 | } 96 | } 97 | 98 | Ok(()) 99 | } 100 | 101 | fn duration_from_ms_str(src: &str) -> Result { 102 | let ms = src.parse::()?; 103 | Ok(Duration::from_millis(ms)) 104 | } 105 | 106 | fn bytes_from_str(src: &str) -> Bytes { 107 | Bytes::from(src.to_string()) 108 | } 109 | -------------------------------------------------------------------------------- /assets/mini-redis/src/bin/server.rs: -------------------------------------------------------------------------------- 1 | //! mini-redis server. 2 | //! 3 | //! This file is the entry point for the server implemented in the library. It 4 | //! performs command line parsing and passes the arguments on to 5 | //! `mini_redis::server`. 6 | //! 7 | //! The `clap` crate is used for parsing arguments. 8 | 9 | use mini_redis::{server, DEFAULT_PORT}; 10 | 11 | use structopt::StructOpt; 12 | use tokio::net::TcpListener; 13 | use tokio::signal; 14 | 15 | #[tokio::main] 16 | pub async fn main() -> mini_redis::Result<()> { 17 | // enable logging 18 | // see https://docs.rs/tracing for more info 19 | tracing_subscriber::fmt::try_init()?; 20 | 21 | let cli = Cli::from_args(); 22 | let port = cli.port.as_deref().unwrap_or(DEFAULT_PORT); 23 | 24 | // Bind a TCP listener 25 | let listener = TcpListener::bind(&format!("127.0.0.1:{}", port)).await?; 26 | 27 | server::run(listener, signal::ctrl_c()).await; 28 | 29 | Ok(()) 30 | } 31 | 32 | #[derive(StructOpt, Debug)] 33 | #[structopt(name = "mini-redis-server", version = env!("CARGO_PKG_VERSION"), author = env!("CARGO_PKG_AUTHORS"), about = "A Redis server")] 34 | struct Cli { 35 | #[structopt(name = "port", long = "--port")] 36 | port: Option, 37 | } 38 | -------------------------------------------------------------------------------- /assets/mini-redis/src/buffer.rs: -------------------------------------------------------------------------------- 1 | use crate::client::Client; 2 | use crate::Result; 3 | 4 | use bytes::Bytes; 5 | use tokio::sync::mpsc::{channel, Receiver, Sender}; 6 | use tokio::sync::oneshot; 7 | 8 | /// Create a new client request buffer 9 | /// 10 | /// The `Client` performs Redis commands directly on the TCP connection. Only a 11 | /// single request may be in-flight at a given time and operations require 12 | /// mutable access to the `Client` handle. This prevents using a single Redis 13 | /// connection from multiple Tokio tasks. 14 | /// 15 | /// The strategy for dealing with this class of problem is to spawn a dedicated 16 | /// Tokio task to manage the Redis connection and using "message passing" to 17 | /// operate on the connection. Commands are pushed into a channel. The 18 | /// connection task pops commands off of the channel and applies them to the 19 | /// Redis connection. When the response is received, it is forwarded to the 20 | /// original requester. 21 | /// 22 | /// The returned `Buffer` handle may be cloned before passing the new handle to 23 | /// separate tasks. 24 | pub fn buffer(client: Client) -> Buffer { 25 | // Setting the message limit to a hard coded value of 32. in a real-app, the 26 | // buffer size should be configurable, but we don't need to do that here. 27 | let (tx, rx) = channel(32); 28 | 29 | // Spawn a task to process requests for the connection. 30 | tokio::spawn(async move { run(client, rx).await }); 31 | 32 | // Return the `Buffer` handle. 33 | Buffer { tx } 34 | } 35 | 36 | // Enum used to message pass the requested command from the `Buffer` handle 37 | #[derive(Debug)] 38 | enum Command { 39 | Get(String), 40 | Set(String, Bytes), 41 | } 42 | 43 | // Message type sent over the channel to the connection task. 44 | // 45 | // `Command` is the command to forward to the connection. 46 | // 47 | // `oneshot::Sender` is a channel type that sends a **single** value. It is used 48 | // here to send the response received from the connection back to the original 49 | // requester. 50 | type Message = (Command, oneshot::Sender>>); 51 | 52 | /// Receive commands sent through the channel and forward them to client. The 53 | /// response is returned back to the caller via a `oneshot`. 54 | async fn run(mut client: Client, mut rx: Receiver) { 55 | // Repeatedly pop messages from the channel. A return value of `None` 56 | // indicates that all `Buffer` handles have dropped and there will never be 57 | // another message sent on the channel. 58 | while let Some((cmd, tx)) = rx.recv().await { 59 | // The command is forwarded to the connection 60 | let response = match cmd { 61 | Command::Get(key) => client.get(&key).await, 62 | Command::Set(key, value) => client.set(&key, value).await.map(|_| None), 63 | }; 64 | 65 | // Send the response back to the caller. 66 | // 67 | // Failing to send the message indicates the `rx` half dropped 68 | // before receiving the message. This is a normal runtime event. 69 | let _ = tx.send(response); 70 | } 71 | } 72 | 73 | #[derive(Clone)] 74 | pub struct Buffer { 75 | tx: Sender, 76 | } 77 | 78 | impl Buffer { 79 | /// Get the value of a key. 80 | /// 81 | /// Same as `Client::get` but requests are **buffered** until the associated 82 | /// connection has the ability to send the request. 83 | pub async fn get(&mut self, key: &str) -> Result> { 84 | // Initialize a new `Get` command to send via the channel. 85 | let get = Command::Get(key.into()); 86 | 87 | // Initialize a new oneshot to be used to receive the response back from the connection. 88 | let (tx, rx) = oneshot::channel(); 89 | 90 | // Send the request 91 | self.tx.send((get, tx)).await?; 92 | 93 | // Await the response 94 | match rx.await { 95 | Ok(res) => res, 96 | Err(err) => Err(err.into()), 97 | } 98 | } 99 | 100 | /// Set `key` to hold the given `value`. 101 | /// 102 | /// Same as `Client::set` but requests are **buffered** until the associated 103 | /// connection has the ability to send the request 104 | pub async fn set(&mut self, key: &str, value: Bytes) -> Result<()> { 105 | // Initialize a new `Set` command to send via the channel. 106 | let set = Command::Set(key.into(), value); 107 | 108 | // Initialize a new oneshot to be used to receive the response back from the connection. 109 | let (tx, rx) = oneshot::channel(); 110 | 111 | // Send the request 112 | self.tx.send((set, tx)).await?; 113 | 114 | // Await the response 115 | match rx.await { 116 | Ok(res) => res.map(|_| ()), 117 | Err(err) => Err(err.into()), 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /assets/mini-redis/src/cmd/get.rs: -------------------------------------------------------------------------------- 1 | use crate::{Connection, Db, Frame, Parse}; 2 | 3 | use bytes::Bytes; 4 | use tracing::{debug, instrument}; 5 | 6 | /// Get the value of key. 7 | /// 8 | /// If the key does not exist the special value nil is returned. An error is 9 | /// returned if the value stored at key is not a string, because GET only 10 | /// handles string values. 11 | #[derive(Debug)] 12 | pub struct Get { 13 | /// Name of the key to get 14 | key: String, 15 | } 16 | 17 | impl Get { 18 | /// Create a new `Get` command which fetches `key`. 19 | pub fn new(key: impl ToString) -> Get { 20 | Get { 21 | key: key.to_string(), 22 | } 23 | } 24 | 25 | /// Get the key 26 | pub fn key(&self) -> &str { 27 | &self.key 28 | } 29 | 30 | /// Parse a `Get` instance from a received frame. 31 | /// 32 | /// The `Parse` argument provides a cursor-like API to read fields from the 33 | /// `Frame`. At this point, the entire frame has already been received from 34 | /// the socket. 35 | /// 36 | /// The `GET` string has already been consumed. 37 | /// 38 | /// # Returns 39 | /// 40 | /// Returns the `Get` value on success. If the frame is malformed, `Err` is 41 | /// returned. 42 | /// 43 | /// # Format 44 | /// 45 | /// Expects an array frame containing two entries. 46 | /// 47 | /// ```text 48 | /// GET key 49 | /// ``` 50 | pub(crate) fn parse_frames(parse: &mut Parse) -> crate::Result { 51 | // The `GET` string has already been consumed. The next value is the 52 | // name of the key to get. If the next value is not a string or the 53 | // input is fully consumed, then an error is returned. 54 | let key = parse.next_string()?; 55 | 56 | Ok(Get { key }) 57 | } 58 | 59 | /// Apply the `Get` command to the specified `Db` instance. 60 | /// 61 | /// The response is written to `dst`. This is called by the server in order 62 | /// to execute a received command. 63 | #[instrument(skip(self, db, dst))] 64 | pub(crate) async fn apply(self, db: &Db, dst: &mut Connection) -> crate::Result<()> { 65 | // Get the value from the shared database state 66 | let response = if let Some(value) = db.get(&self.key) { 67 | // If a value is present, it is written to the client in "bulk" 68 | // format. 69 | Frame::Bulk(value) 70 | } else { 71 | // If there is no value, `Null` is written. 72 | Frame::Null 73 | }; 74 | 75 | debug!(?response); 76 | 77 | // Write the response back to the client 78 | dst.write_frame(&response).await?; 79 | 80 | Ok(()) 81 | } 82 | 83 | /// Converts the command into an equivalent `Frame`. 84 | /// 85 | /// This is called by the client when encoding a `Get` command to send to 86 | /// the server. 87 | pub(crate) fn into_frame(self) -> Frame { 88 | let mut frame = Frame::array(); 89 | frame.push_bulk(Bytes::from("get".as_bytes())); 90 | frame.push_bulk(Bytes::from(self.key.into_bytes())); 91 | frame 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /assets/mini-redis/src/cmd/mod.rs: -------------------------------------------------------------------------------- 1 | mod get; 2 | pub use get::Get; 3 | 4 | mod publish; 5 | pub use publish::Publish; 6 | 7 | mod set; 8 | pub use set::Set; 9 | 10 | mod subscribe; 11 | pub use subscribe::{Subscribe, Unsubscribe}; 12 | 13 | mod unknown; 14 | pub use unknown::Unknown; 15 | 16 | use crate::{Connection, Db, Frame, Parse, ParseError, Shutdown}; 17 | 18 | /// Enumeration of supported Redis commands. 19 | /// 20 | /// Methods called on `Command` are delegated to the command implementation. 21 | #[derive(Debug)] 22 | pub enum Command { 23 | Get(Get), 24 | Publish(Publish), 25 | Set(Set), 26 | Subscribe(Subscribe), 27 | Unsubscribe(Unsubscribe), 28 | Unknown(Unknown), 29 | } 30 | 31 | impl Command { 32 | /// Parse a command from a received frame. 33 | /// 34 | /// The `Frame` must represent a Redis command supported by `mini-redis` and 35 | /// be the array variant. 36 | /// 37 | /// # Returns 38 | /// 39 | /// On success, the command value is returned, otherwise, `Err` is returned. 40 | pub fn from_frame(frame: Frame) -> crate::Result { 41 | // The frame value is decorated with `Parse`. `Parse` provides a 42 | // "cursor" like API which makes parsing the command easier. 43 | // 44 | // The frame value must be an array variant. Any other frame variants 45 | // result in an error being returned. 46 | let mut parse = Parse::new(frame)?; 47 | 48 | // All redis commands begin with the command name as a string. The name 49 | // is read and converted to lower cases in order to do case sensitive 50 | // matching. 51 | let command_name = parse.next_string()?.to_lowercase(); 52 | 53 | // Match the command name, delegating the rest of the parsing to the 54 | // specific command. 55 | let command = match &command_name[..] { 56 | "get" => Command::Get(Get::parse_frames(&mut parse)?), 57 | "publish" => Command::Publish(Publish::parse_frames(&mut parse)?), 58 | "set" => Command::Set(Set::parse_frames(&mut parse)?), 59 | "subscribe" => Command::Subscribe(Subscribe::parse_frames(&mut parse)?), 60 | "unsubscribe" => Command::Unsubscribe(Unsubscribe::parse_frames(&mut parse)?), 61 | _ => { 62 | // The command is not recognized and an Unknown command is 63 | // returned. 64 | // 65 | // `return` is called here to skip the `finish()` call below. As 66 | // the command is not recognized, there is most likely 67 | // unconsumed fields remaining in the `Parse` instance. 68 | return Ok(Command::Unknown(Unknown::new(command_name))); 69 | } 70 | }; 71 | 72 | // Check if there is any remaining unconsumed fields in the `Parse` 73 | // value. If fields remain, this indicates an unexpected frame format 74 | // and an error is returned. 75 | parse.finish()?; 76 | 77 | // The command has been successfully parsed 78 | Ok(command) 79 | } 80 | 81 | /// Apply the command to the specified `Db` instance. 82 | /// 83 | /// The response is written to `dst`. This is called by the server in order 84 | /// to execute a received command. 85 | pub(crate) async fn apply( 86 | self, 87 | db: &Db, 88 | dst: &mut Connection, 89 | shutdown: &mut Shutdown, 90 | ) -> crate::Result<()> { 91 | use Command::*; 92 | 93 | match self { 94 | Get(cmd) => cmd.apply(db, dst).await, 95 | Publish(cmd) => cmd.apply(db, dst).await, 96 | Set(cmd) => cmd.apply(db, dst).await, 97 | Subscribe(cmd) => cmd.apply(db, dst, shutdown).await, 98 | Unknown(cmd) => cmd.apply(dst).await, 99 | // `Unsubscribe` cannot be applied. It may only be received from the 100 | // context of a `Subscribe` command. 101 | Unsubscribe(_) => Err("`Unsubscribe` is unsupported in this context".into()), 102 | } 103 | } 104 | 105 | /// Returns the command name 106 | pub(crate) fn get_name(&self) -> &str { 107 | match self { 108 | Command::Get(_) => "get", 109 | Command::Publish(_) => "pub", 110 | Command::Set(_) => "set", 111 | Command::Subscribe(_) => "subscribe", 112 | Command::Unsubscribe(_) => "unsubscribe", 113 | Command::Unknown(cmd) => cmd.get_name(), 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /assets/mini-redis/src/cmd/publish.rs: -------------------------------------------------------------------------------- 1 | use crate::{Connection, Db, Frame, Parse}; 2 | 3 | use bytes::Bytes; 4 | 5 | /// Posts a message to the given channel. 6 | /// 7 | /// Send a message into a channel without any knowledge of individual consumers. 8 | /// Consumers may subscribe to channels in order to receive the messages. 9 | /// 10 | /// Channel names have no relation to the key-value namespace. Publishing on a 11 | /// channel named "foo" has no relation to setting the "foo" key. 12 | #[derive(Debug)] 13 | pub struct Publish { 14 | /// Name of the channel on which the message should be published. 15 | channel: String, 16 | 17 | /// The message to publish. 18 | message: Bytes, 19 | } 20 | 21 | impl Publish { 22 | /// Create a new `Publish` command which sends `message` on `channel`. 23 | pub(crate) fn new(channel: impl ToString, message: Bytes) -> Publish { 24 | Publish { 25 | channel: channel.to_string(), 26 | message, 27 | } 28 | } 29 | 30 | /// Parse a `Publish` instance from a received frame. 31 | /// 32 | /// The `Parse` argument provides a cursor-like API to read fields from the 33 | /// `Frame`. At this point, the entire frame has already been received from 34 | /// the socket. 35 | /// 36 | /// The `PUBLISH` string has already been consumed. 37 | /// 38 | /// # Returns 39 | /// 40 | /// On success, the `Publish` value is returned. If the frame is malformed, 41 | /// `Err` is returned. 42 | /// 43 | /// # Format 44 | /// 45 | /// Expects an array frame containing three entries. 46 | /// 47 | /// ```text 48 | /// PUBLISH channel message 49 | /// ``` 50 | pub(crate) fn parse_frames(parse: &mut Parse) -> crate::Result { 51 | // The `PUBLISH` string has already been consumed. Extract the `channel` 52 | // and `message` values from the frame. 53 | // 54 | // The `channel` must be a valid string. 55 | let channel = parse.next_string()?; 56 | 57 | // The `message` is arbitrary bytes. 58 | let message = parse.next_bytes()?; 59 | 60 | Ok(Publish { channel, message }) 61 | } 62 | 63 | /// Apply the `Publish` command to the specified `Db` instance. 64 | /// 65 | /// The response is written to `dst`. This is called by the server in order 66 | /// to execute a received command. 67 | pub(crate) async fn apply(self, db: &Db, dst: &mut Connection) -> crate::Result<()> { 68 | // The shared state contains the `tokio::sync::broadcast::Sender` for 69 | // all active channels. Calling `db.publish` dispatches the message into 70 | // the appropriate channel. 71 | // 72 | // The number of subscribers currently listening on the channel is 73 | // returned. This does not mean that `num_subscriber` channels will 74 | // receive the message. Subscribers may drop before receiving the 75 | // message. Given this, `num_subscribers` should only be used as a 76 | // "hint". 77 | let num_subscribers = db.publish(&self.channel, self.message); 78 | 79 | // The number of subscribers is returned as the response to the publish 80 | // request. 81 | let response = Frame::Integer(num_subscribers as u64); 82 | 83 | // Write the frame to the client. 84 | dst.write_frame(&response).await?; 85 | 86 | Ok(()) 87 | } 88 | 89 | /// Converts the command into an equivalent `Frame`. 90 | /// 91 | /// This is called by the client when encoding a `Publish` command to send 92 | /// to the server. 93 | pub(crate) fn into_frame(self) -> Frame { 94 | let mut frame = Frame::array(); 95 | frame.push_bulk(Bytes::from("publish".as_bytes())); 96 | frame.push_bulk(Bytes::from(self.channel.into_bytes())); 97 | frame.push_bulk(self.message); 98 | 99 | frame 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /assets/mini-redis/src/cmd/unknown.rs: -------------------------------------------------------------------------------- 1 | use crate::{Connection, Frame}; 2 | 3 | use tracing::{debug, instrument}; 4 | 5 | /// Represents an "unknown" command. This is not a real `Redis` command. 6 | #[derive(Debug)] 7 | pub struct Unknown { 8 | command_name: String, 9 | } 10 | 11 | impl Unknown { 12 | /// Create a new `Unknown` command which responds to unknown commands 13 | /// issued by clients 14 | pub(crate) fn new(key: impl ToString) -> Unknown { 15 | Unknown { 16 | command_name: key.to_string(), 17 | } 18 | } 19 | 20 | /// Returns the command name 21 | pub(crate) fn get_name(&self) -> &str { 22 | &self.command_name 23 | } 24 | 25 | /// Responds to the client, indicating the command is not recognized. 26 | /// 27 | /// This usually means the command is not yet implemented by `mini-redis`. 28 | #[instrument(skip(self, dst))] 29 | pub(crate) async fn apply(self, dst: &mut Connection) -> crate::Result<()> { 30 | let response = Frame::Error(format!("ERR unknown command '{}'", self.command_name)); 31 | 32 | debug!(?response); 33 | 34 | dst.write_frame(&response).await?; 35 | Ok(()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /assets/mini-redis/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A minimal (i.e. very incomplete) implementation of a Redis server and 2 | //! client. 3 | //! 4 | //! The purpose of this project is to provide a larger example of an 5 | //! asynchronous Rust project built with Tokio. Do not attempt to run this in 6 | //! production... seriously. 7 | //! 8 | //! # Layout 9 | //! 10 | //! The library is structured such that it can be used with guides. There are 11 | //! modules that are public that probably would not be public in a "real" redis 12 | //! client library. 13 | //! 14 | //! The major components are: 15 | //! 16 | //! * `server`: Redis server implementation. Includes a single `run` function 17 | //! that takes a `TcpListener` and starts accepting redis client connections. 18 | //! 19 | //! * `client`: an asynchronous Redis client implementation. Demonstrates how to 20 | //! build clients with Tokio. 21 | //! 22 | //! * `cmd`: implementations of the supported Redis commands. 23 | //! 24 | //! * `frame`: represents a single Redis protocol frame. A frame is used as an 25 | //! intermediate representation between a "command" and the byte 26 | //! representation. 27 | 28 | pub mod blocking_client; 29 | pub mod client; 30 | 31 | pub mod cmd; 32 | pub use cmd::Command; 33 | 34 | mod connection; 35 | pub use connection::Connection; 36 | 37 | pub mod frame; 38 | pub use frame::Frame; 39 | 40 | mod db; 41 | use db::Db; 42 | use db::DbDropGuard; 43 | 44 | mod parse; 45 | use parse::{Parse, ParseError}; 46 | 47 | pub mod server; 48 | 49 | mod buffer; 50 | pub use buffer::{buffer, Buffer}; 51 | 52 | mod shutdown; 53 | use shutdown::Shutdown; 54 | 55 | /// Default port that a redis server listens on. 56 | /// 57 | /// Used if no port is specified. 58 | pub const DEFAULT_PORT: &str = "6379"; 59 | 60 | /// Error returned by most functions. 61 | /// 62 | /// When writing a real application, one might want to consider a specialized 63 | /// error handling crate or defining an error type as an `enum` of causes. 64 | /// However, for our example, using a boxed `std::error::Error` is sufficient. 65 | /// 66 | /// For performance reasons, boxing is avoided in any hot path. For example, in 67 | /// `parse`, a custom error `enum` is defined. This is because the error is hit 68 | /// and handled during normal execution when a partial frame is received on a 69 | /// socket. `std::error::Error` is implemented for `parse::Error` which allows 70 | /// it to be converted to `Box`. 71 | pub type Error = Box; 72 | 73 | /// A specialized `Result` type for mini-redis operations. 74 | /// 75 | /// This is defined as a convenience. 76 | pub type Result = std::result::Result; 77 | -------------------------------------------------------------------------------- /assets/mini-redis/src/parse.rs: -------------------------------------------------------------------------------- 1 | use crate::Frame; 2 | 3 | use bytes::Bytes; 4 | use std::{fmt, str, vec}; 5 | 6 | /// Utility for parsing a command 7 | /// 8 | /// Commands are represented as array frames. Each entry in the frame is a 9 | /// "token". A `Parse` is initialized with the array frame and provides a 10 | /// cursor-like API. Each command struct includes a `parse_frame` method that 11 | /// uses a `Parse` to extract its fields. 12 | #[derive(Debug)] 13 | pub(crate) struct Parse { 14 | /// Array frame iterator. 15 | parts: vec::IntoIter, 16 | } 17 | 18 | /// Error encountered while parsing a frame. 19 | /// 20 | /// Only `EndOfStream` errors are handled at runtime. All other errors result in 21 | /// the connection being terminated. 22 | #[derive(Debug)] 23 | pub(crate) enum ParseError { 24 | /// Attempting to extract a value failed due to the frame being fully 25 | /// consumed. 26 | EndOfStream, 27 | 28 | /// All other errors 29 | Other(crate::Error), 30 | } 31 | 32 | impl Parse { 33 | /// Create a new `Parse` to parse the contents of `frame`. 34 | /// 35 | /// Returns `Err` if `frame` is not an array frame. 36 | pub(crate) fn new(frame: Frame) -> Result { 37 | let array = match frame { 38 | Frame::Array(array) => array, 39 | frame => return Err(format!("protocol error; expected array, got {:?}", frame).into()), 40 | }; 41 | 42 | Ok(Parse { 43 | parts: array.into_iter(), 44 | }) 45 | } 46 | 47 | /// Return the next entry. Array frames are arrays of frames, so the next 48 | /// entry is a frame. 49 | fn next(&mut self) -> Result { 50 | self 51 | .parts 52 | .next() 53 | .ok_or(ParseError::EndOfStream) 54 | } 55 | 56 | /// Return the next entry as a string. 57 | /// 58 | /// If the next entry cannot be represented as a String, then an error is returned. 59 | pub(crate) fn next_string(&mut self) -> Result { 60 | match self.next()? { 61 | // Both `Simple` and `Bulk` representation may be strings. Strings 62 | // are parsed to UTF-8. 63 | // 64 | // While errors are stored as strings, they are considered separate 65 | // types. 66 | Frame::Simple(s) => Ok(s), 67 | Frame::Bulk(data) => str::from_utf8(&data[..]) 68 | .map(|s| s.to_string()) 69 | .map_err(|_| "protocol error; invalid string".into()), 70 | frame => Err(format!( 71 | "protocol error; expected simple frame or bulk frame, got {:?}", 72 | frame 73 | ) 74 | .into()), 75 | } 76 | } 77 | 78 | /// Return the next entry as raw bytes. 79 | /// 80 | /// If the next entry cannot be represented as raw bytes, an error is 81 | /// returned. 82 | pub(crate) fn next_bytes(&mut self) -> Result { 83 | match self.next()? { 84 | // Both `Simple` and `Bulk` representation may be raw bytes. 85 | // 86 | // Although errors are stored as strings and could be represented as 87 | // raw bytes, they are considered separate types. 88 | Frame::Simple(s) => Ok(Bytes::from(s.into_bytes())), 89 | Frame::Bulk(data) => Ok(data), 90 | frame => Err(format!( 91 | "protocol error; expected simple frame or bulk frame, got {:?}", 92 | frame 93 | ) 94 | .into()), 95 | } 96 | } 97 | 98 | /// Return the next entry as an integer. 99 | /// 100 | /// This includes `Simple`, `Bulk`, and `Integer` frame types. `Simple` and 101 | /// `Bulk` frame types are parsed. 102 | /// 103 | /// If the next entry cannot be represented as an integer, then an error is 104 | /// returned. 105 | pub(crate) fn next_int(&mut self) -> Result { 106 | use atoi::atoi; 107 | 108 | const MSG: &str = "protocol error; invalid number"; 109 | 110 | match self.next()? { 111 | // An integer frame type is already stored as an integer. 112 | Frame::Integer(v) => Ok(v), 113 | // Simple and bulk frames must be parsed as integers. If the parsing 114 | // fails, an error is returned. 115 | Frame::Simple(data) => atoi::(data.as_bytes()).ok_or_else(|| MSG.into()), 116 | Frame::Bulk(data) => atoi::(&data).ok_or_else(|| MSG.into()), 117 | frame => Err(format!("protocol error; expected int frame but got {:?}", frame).into()), 118 | } 119 | } 120 | 121 | /// Ensure there are no more entries in the array 122 | pub(crate) fn finish(&mut self) -> Result<(), ParseError> { 123 | if self.parts.next().is_none() { 124 | Ok(()) 125 | } else { 126 | Err("protocol error; expected end of frame, but there was more".into()) 127 | } 128 | } 129 | } 130 | 131 | impl From for ParseError { 132 | fn from(src: String) -> ParseError { 133 | ParseError::Other(src.into()) 134 | } 135 | } 136 | 137 | impl From<&str> for ParseError { 138 | fn from(src: &str) -> ParseError { 139 | src.to_string().into() 140 | } 141 | } 142 | 143 | impl fmt::Display for ParseError { 144 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 145 | match self { 146 | ParseError::EndOfStream => "protocol error; unexpected end of stream".fmt(f), 147 | ParseError::Other(err) => err.fmt(f), 148 | } 149 | } 150 | } 151 | 152 | impl std::error::Error for ParseError {} 153 | -------------------------------------------------------------------------------- /assets/mini-redis/src/shutdown.rs: -------------------------------------------------------------------------------- 1 | use tokio::sync::broadcast; 2 | 3 | /// Listens for the server shutdown signal. 4 | /// 5 | /// Shutdown is signalled using a `broadcast::Receiver`. Only a single value is 6 | /// ever sent. Once a value has been sent via the broadcast channel, the server 7 | /// should shutdown. 8 | /// 9 | /// The `Shutdown` struct listens for the signal and tracks that the signal has 10 | /// been received. Callers may query for whether the shutdown signal has been 11 | /// received or not. 12 | #[derive(Debug)] 13 | pub(crate) struct Shutdown { 14 | /// `true` if the shutdown signal has been received 15 | shutdown: bool, 16 | 17 | /// The receive half of the channel used to listen for shutdown. 18 | notify: broadcast::Receiver<()>, 19 | } 20 | 21 | impl Shutdown { 22 | /// Create a new `Shutdown` backed by the given `broadcast::Receiver`. 23 | pub(crate) fn new(notify: broadcast::Receiver<()>) -> Shutdown { 24 | Shutdown { 25 | shutdown: false, 26 | notify, 27 | } 28 | } 29 | 30 | /// Returns `true` if the shutdown signal has been received. 31 | pub(crate) fn is_shutdown(&self) -> bool { 32 | self.shutdown 33 | } 34 | 35 | /// Receive the shutdown notice, waiting if necessary. 36 | pub(crate) async fn recv(&mut self) { 37 | // If the shutdown signal has already been received, then return 38 | // immediately. 39 | if self.shutdown { 40 | return; 41 | } 42 | 43 | // Cannot receive a "lag error" as only one value is ever sent. 44 | let _ = self.notify.recv().await; 45 | 46 | // Remember that the signal has been received. 47 | self.shutdown = true; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /assets/mini-redis/tests/buffer.rs: -------------------------------------------------------------------------------- 1 | use mini_redis::{buffer, client, server}; 2 | use std::net::SocketAddr; 3 | use tokio::net::TcpListener; 4 | use tokio::task::JoinHandle; 5 | 6 | /// A basic "hello world" style test. A server instance is started in a 7 | /// background task. A client instance is then established and used to intialize 8 | /// the buffer. Set and get commands are sent to the server. The response is 9 | /// then evaluated. 10 | #[tokio::test] 11 | async fn pool_key_value_get_set() { 12 | let (addr, _) = start_server().await; 13 | 14 | let client = client::connect(addr).await.unwrap(); 15 | let mut client = buffer(client); 16 | 17 | client.set("hello", "world".into()).await.unwrap(); 18 | 19 | let value = client.get("hello").await.unwrap().unwrap(); 20 | assert_eq!(b"world", &value[..]) 21 | } 22 | 23 | async fn start_server() -> (SocketAddr, JoinHandle<()>) { 24 | let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); 25 | let addr = listener.local_addr().unwrap(); 26 | 27 | let handle = tokio::spawn(async move { server::run(listener, tokio::signal::ctrl_c()).await }); 28 | 29 | (addr, handle) 30 | } 31 | -------------------------------------------------------------------------------- /assets/mini-redis/tests/client.rs: -------------------------------------------------------------------------------- 1 | use mini_redis::{client, server}; 2 | use std::net::SocketAddr; 3 | use tokio::net::TcpListener; 4 | use tokio::task::JoinHandle; 5 | 6 | /// A basic "hello world" style test. A server instance is started in a 7 | /// background task. A client instance is then established and set and get 8 | /// commands are sent to the server. The response is then evaluated 9 | #[tokio::test] 10 | async fn key_value_get_set() { 11 | let (addr, _) = start_server().await; 12 | 13 | let mut client = client::connect(addr).await.unwrap(); 14 | client.set("hello", "world".into()).await.unwrap(); 15 | 16 | let value = client.get("hello").await.unwrap().unwrap(); 17 | assert_eq!(b"world", &value[..]) 18 | } 19 | 20 | /// similar to the "hello world" style test, But this time 21 | /// a single channel subscription will be tested instead 22 | #[tokio::test] 23 | async fn receive_message_subscribed_channel() { 24 | let (addr, _) = start_server().await; 25 | 26 | let client = client::connect(addr.clone()).await.unwrap(); 27 | let mut subscriber = client.subscribe(vec!["hello".into()]).await.unwrap(); 28 | 29 | tokio::spawn(async move { 30 | let mut client = client::connect(addr).await.unwrap(); 31 | client.publish("hello", "world".into()).await.unwrap() 32 | }); 33 | 34 | let message = subscriber.next_message().await.unwrap().unwrap(); 35 | assert_eq!("hello", &message.channel); 36 | assert_eq!(b"world", &message.content[..]) 37 | } 38 | 39 | /// test that a client gets messages from multiple subscribed channels 40 | #[tokio::test] 41 | async fn receive_message_multiple_subscribed_channels() { 42 | let (addr, _) = start_server().await; 43 | 44 | let client = client::connect(addr.clone()).await.unwrap(); 45 | let mut subscriber = client 46 | .subscribe(vec!["hello".into(), "world".into()]) 47 | .await 48 | .unwrap(); 49 | 50 | tokio::spawn(async move { 51 | let mut client = client::connect(addr).await.unwrap(); 52 | client.publish("hello", "world".into()).await.unwrap() 53 | }); 54 | 55 | let message1 = subscriber.next_message().await.unwrap().unwrap(); 56 | assert_eq!("hello", &message1.channel); 57 | assert_eq!(b"world", &message1.content[..]); 58 | 59 | tokio::spawn(async move { 60 | let mut client = client::connect(addr).await.unwrap(); 61 | client.publish("world", "howdy?".into()).await.unwrap() 62 | }); 63 | 64 | let message2 = subscriber.next_message().await.unwrap().unwrap(); 65 | assert_eq!("world", &message2.channel); 66 | assert_eq!(b"howdy?", &message2.content[..]) 67 | } 68 | 69 | /// test that a client accurately removes its own subscribed chanel list 70 | /// when unbscribing to all subscribed channels by submitting an empty vec 71 | #[tokio::test] 72 | async fn unsubscribes_from_channels() { 73 | let (addr, _) = start_server().await; 74 | 75 | let client = client::connect(addr.clone()).await.unwrap(); 76 | let mut subscriber = client 77 | .subscribe(vec!["hello".into(), "world".into()]) 78 | .await 79 | .unwrap(); 80 | 81 | subscriber.unsubscribe(&[]).await.unwrap(); 82 | assert_eq!(subscriber.get_subscribed().len(), 0); 83 | } 84 | 85 | async fn start_server() -> (SocketAddr, JoinHandle<()>) { 86 | let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); 87 | let addr = listener.local_addr().unwrap(); 88 | 89 | let handle = tokio::spawn(async move { server::run(listener, tokio::signal::ctrl_c()).await }); 90 | 91 | (addr, handle) 92 | } 93 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["course.rs"] 3 | language = "zh-CN" 4 | multilingual = false 5 | src = "src" 6 | title = "Rust算法教程 The Algos (algorithms)" 7 | 8 | [output.html] 9 | git-repository-url = "https://github.com/course-rs/algos" 10 | edit-url-template = "https://github.com/course-rs/algos/blob/main/{path}" 11 | 12 | [output.html.fold] 13 | enable = true 14 | level = 1 15 | -------------------------------------------------------------------------------- /deploy: -------------------------------------------------------------------------------- 1 | ## this script is releasing the book to github pages 2 | 3 | ## build book 4 | mdbook build 5 | ## copy CNAME info to book dir 6 | cp CNAME ./book/ 7 | cp ./assets/*.html ./book/ 8 | 9 | ## init git repo 10 | cd book 11 | git init 12 | git config user.name "sunface" 13 | git config user.email "cto@188.com" 14 | git add . 15 | git commit -m 'release book' 16 | git branch -M gh-pages 17 | git remote add origin https://github.com/course-rs/algos 18 | 19 | ## push to github pages 20 | git push -u -f origin gh-pages -------------------------------------------------------------------------------- /src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [Rust算法教程](./about-book.md) 4 | 5 | - [排序](sorting/index.md) 6 | - [冒泡排序](sorting/bubble-sort.md) 7 | - [桶排序](sorting/bucket-sort.md) 8 | - [鸡尾酒排序](sorting/cocktail-shaker-sort.md) 9 | - [梳排序](sorting/comb-sort.md) 10 | - [计数排序](sorting/counting-sort.md) 11 | - [地精排序](sorting/gnome-sort.md) 12 | - [堆排序](sorting/heap-sort.md) 13 | - [插入排序](sorting/insertion-sort.md) 14 | - [归并排序](sorting/merge-sort.md) 15 | - [奇偶排序](sorting/odd-even.md) 16 | - [快速排序](sorting/quick-sort.md) 17 | - [基数排序](sorting/radix-sort.md) 18 | - [选择排序](sorting/selection-sort.md) 19 | - [希尔排序](sorting/shell-sort.md) 20 | - [臭皮匠排序](sorting/stooge-sort.md) 21 | 22 | - [字符串](string/index.md) 23 | - [逆序倒转](string/reverse.md) 24 | - [数据转换算法](string/burrows-wheeler-transform.md) 25 | - [KMP算法](string/knuth-morris-pratt.md) 26 | - [马拉车算法](string/manacher.md) 27 | - [Rabin Karp算法](string/rabin-karp.md) 28 | 29 | - [查找算法](searching/index.md) 30 | - [二分查找](searching/binary-search.md) 31 | - [递归二分查找](searching/binary-search-recursive.md) 32 | - [查找第K小的元素](searching/kth-smallest.md) 33 | - [线性搜索](searching/linear-search.md) 34 | 35 | - [图论](graph/index.md) 36 | - [最短路径-Bellman Ford](graph/bellman-ford.md) 37 | - [最短路径-Dijkstra](graph/dijkstra.md) 38 | - [深度优先搜索](graph/depth-first-search.md) 39 | - [广度优先搜索](graph/breadth-first-search.md) 40 | - [深度优先Tic Tac Toe](graph/depth-first-tic-tac-toe.md) 41 | - [最小生成树](graph/minimum-spanning-tree.md) 42 | - [Prim算法(最小生成树)](graph/prim.md) 43 | 44 | - [动态规划](dynamic-programming/index.md) 45 | - [斐波那契(fibonacci)](dynamic-programming/fibonacci.md) 46 | - [找钱(Coin change)](dynamic-programming/coin-change.md) 47 | - [最小编辑距离(Edit distance)](dynamic-programming/edit-distance.md) 48 | - [扔鸡蛋(Egg dropping)](dynamic-programming/egg-dropping.md) 49 | - [判断子序列](dynamic-programming/is-subsequence.md) 50 | - [背包问题](dynamic-programming/knapsack.md) 51 | - [最长公共子序列](dynamic-programming/longese-common-sequence.md) 52 | - [最长连续递增序列](dynamic-programming/longest_continuous_increasing_subsequence.md) 53 | - [最长上升子序列](dynamic-programming/longest-increasing-subsequence.md) 54 | - [最大正方形](dynamic-programming/maximal-square.md) 55 | - [最大子数组](dynamic-programming/maximal-subarray.md) 56 | - [棒的切割](dynamic-programming/rod-cutting.md) 57 | 58 | - [数学]() 59 | - [扩展欧几里得算法](math/extended-euclidean.md) 60 | - [最大公约数](math/greatest-common-divisor.md) 61 | - [帕斯卡三角](math/pascal-triange.md) 62 | - [寻找完美数](math/perfect-numbers.md) 63 | - [质数检测](math/prime-check.md) 64 | - [质数筛法](math/prime-numbers.md) 65 | - [试除法](math/trial-division.md) 66 | 67 | - [几何]() 68 | - [最近点算法](geometry/closet-points.md) 69 | 70 | - [加密算法](cipher/index.md) 71 | - [凯撒算法(caesar)](cipher/caesar.md) 72 | - [摩斯码](cipher/morse-code.md) 73 | - [Polibius密码](cipher/polibius.md) 74 | - [rot13加密算法](cipher/rot13.md) 75 | - [rot13第二种实现](cipher/another-rot13.md) 76 | - [sha256加密](cipher/sha256.md) 77 | - [vigenere加密](cipher/vigenere.md) 78 | - [xor](cipher/xor.md) 79 | 80 | - [其它算法]() 81 | - [凸包算法](general/convex-hull.md) 82 | - [汉诺塔算法](general/hanoi.md) 83 | - [K-Means算法](general/kmeans.md) 84 | - [N皇后算法](general/nqueens.md) 85 | - [两数之和](general/two-sum.md) 86 | 87 | 88 | - [数据结构](data-structures/index.md) 89 | - [B树](data-structures/b-tree.md) 90 | - [二叉树](data-structures/binary-search-tree.md) 91 | - [avl树](data-structures/avl-tree.md) 92 | - [链表](data-structures/linked-list.md) 93 | - [堆(Heap)](data-structures/heap.md) 94 | - [栈](data-structures/stack.md) 95 | - [队列](data-structures/queue.md) 96 | - [trie(字典树)](data-structures/trie.md) 97 | - [图(graph)](data-structures/graph.md) 98 | - [循环队列(circular queue)](data-structures/circular-queue.md) 99 | 100 | - [LeetCode题解](leetcode/index.md) 101 | - [1.两数之和](leetcode/001-two-sum.md) -------------------------------------------------------------------------------- /src/about-book.md: -------------------------------------------------------------------------------- 1 | ## Algos算法教程 2 | Rust作为一门现代化的系统编程语言,拥有与C/C++类似的性能,同时又能做非常底层的性能优化,因此非常适合写算法和leetcode。 3 | 4 | Algos 算法教程涵盖了各种常用算法和数据结构的代码实现,以及leetcode题解,同时对于相关算法还提供了中文文档和注释,可以帮助大家更好、更快的学习。 5 | 6 | ## 关于算法 7 | 8 | 算法,一个高大上的词汇,在计算机领域也绝对是凡人的禁忌,但是其实算法又没那么神秘,我们在写代码时,无时无刻都在与算法打交道,只是绝大部分算法我们无法感知到而已,因为这些算法已经很好的被包装在其它库中,我们只需要输入数据然后调用它获得输出数据即可,因此这就引出了算法的基本定义: 9 | 10 | 计算机算法是以一步接一步的方式来详细描述计算机如何将输入转化为所要求的输出的过程,或者说,算法是对计算机上执行的计算过程的具体描述。(以上内容摘抄自百度百科),简单点说计算机算法就是将输入转化为所要求的输出过程。 11 | 12 | 既然只要调用别人的算法库即可完成任务,我们为什么要学习算法呢?原因很简单:面试需要。哈哈,开个玩笑,当然面试很重要,但是提升自己的能力也很重要,学习算法往往能提升我们对于代码的深层次理解和认识,你会知道为何要优化代码,该如何优化代码,甚至在真的需要你手撸算法时,心中也有一个明确的思路:我该选择哪个算法,而不是一片茫然,只知道用遍历的方式来完成任务。 13 | 14 | 所以现在开始我们的算法之旅吧, 本章重点呈现各种常用算法的Rust实现,大部分章节都会链接一篇讲解该算法的文章。 15 | 16 | ## Rust 语言学习 17 | 如果大家熟悉算法,但是对于 Rust 语言还不够熟悉,可以看看 [Rust语言圣经](https://github.com/sunface/rust-course),它绝对是目前最优秀的 Rust 中文开源教程。 18 | 19 | ## 社区贡献者 20 | 我们深知自身水平的局限性,因此非常欢迎各路大神加入进来,共同打造这门未来可以在中国乃至全世界都排得上号的算法教程! 21 | 22 | -------------------------------------------------------------------------------- /src/cipher/another-rot13.md: -------------------------------------------------------------------------------- 1 | # rot13第二种实现 2 | 3 | ```rust 4 | pub fn another_rot13(text: &str) -> String { 5 | let input = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 6 | let output = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"; 7 | text.chars() 8 | .map(|c| match input.find(c) { 9 | Some(i) => output.chars().nth(i).unwrap(), 10 | None => c, 11 | }) 12 | .collect() 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | // Note this useful idiom: importing names from outer (for mod tests) scope. 18 | use super::*; 19 | 20 | #[test] 21 | fn test_simple() { 22 | assert_eq!(another_rot13("ABCzyx"), "NOPmlk"); 23 | } 24 | 25 | #[test] 26 | fn test_every_alphabet_with_space() { 27 | assert_eq!( 28 | another_rot13("The quick brown fox jumps over the lazy dog"), 29 | "Gur dhvpx oebja sbk whzcf bire gur ynml qbt" 30 | ); 31 | } 32 | 33 | #[test] 34 | fn test_non_alphabet() { 35 | assert_eq!(another_rot13("🎃 Jack-o'-lantern"), "🎃 Wnpx-b'-ynagrea"); 36 | } 37 | } 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /src/cipher/caesar.md: -------------------------------------------------------------------------------- 1 | # 凯撒算法(caesar) 2 | 3 | ```rust 4 | pub fn another_rot13(text: &str) -> String { 5 | let input = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 6 | let output = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"; 7 | text.chars() 8 | .map(|c| match input.find(c) { 9 | Some(i) => output.chars().nth(i).unwrap(), 10 | None => c, 11 | }) 12 | .collect() 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | // Note this useful idiom: importing names from outer (for mod tests) scope. 18 | use super::*; 19 | 20 | #[test] 21 | fn test_simple() { 22 | assert_eq!(another_rot13("ABCzyx"), "NOPmlk"); 23 | } 24 | 25 | #[test] 26 | fn test_every_alphabet_with_space() { 27 | assert_eq!( 28 | another_rot13("The quick brown fox jumps over the lazy dog"), 29 | "Gur dhvpx oebja sbk whzcf bire gur ynml qbt" 30 | ); 31 | } 32 | 33 | #[test] 34 | fn test_non_alphabet() { 35 | assert_eq!(another_rot13("🎃 Jack-o'-lantern"), "🎃 Wnpx-b'-ynagrea"); 36 | } 37 | } 38 | ``` -------------------------------------------------------------------------------- /src/cipher/index.md: -------------------------------------------------------------------------------- 1 | # 加密算法 2 | 3 | 数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码为“密文”,使其只能在输入相应的密钥之后才能显示出原容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。 该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。 4 | 5 | 随着信息化和数字化社会的发展,人们对信息安全和保密的重要性认识不断提高,于是在1997年,美国国家标准局公布实施了“美国数据加密标准(DES)”,民间力量开始全面介入密码学的研究和应用中,采用的加密算法有`DES、RSA、SHA`等。随着对加密强度需求的不断提高,近期又出现了`AES、ECC`等。 6 | 使用密码学可以达到以下目的: 7 | - 保密性:防止用户的标识或数据被读取。 8 | - 数据完整性:防止数据被更改。 9 | - 身份验证:确保数据发自特定的一方。 -------------------------------------------------------------------------------- /src/cipher/polibius.md: -------------------------------------------------------------------------------- 1 | # Polibius密码 2 | 3 | ```rust 4 | /// Encode an ASCII string into its location in a Polybius square. 5 | /// Only alphabetical characters are encoded. 6 | pub fn encode_ascii(string: &str) -> String { 7 | string 8 | .chars() 9 | .map(|c| match c { 10 | 'a' | 'A' => "11", 11 | 'b' | 'B' => "12", 12 | 'c' | 'C' => "13", 13 | 'd' | 'D' => "14", 14 | 'e' | 'E' => "15", 15 | 'f' | 'F' => "21", 16 | 'g' | 'G' => "22", 17 | 'h' | 'H' => "23", 18 | 'i' | 'I' | 'j' | 'J' => "24", 19 | 'k' | 'K' => "25", 20 | 'l' | 'L' => "31", 21 | 'm' | 'M' => "32", 22 | 'n' | 'N' => "33", 23 | 'o' | 'O' => "34", 24 | 'p' | 'P' => "35", 25 | 'q' | 'Q' => "41", 26 | 'r' | 'R' => "42", 27 | 's' | 'S' => "43", 28 | 't' | 'T' => "44", 29 | 'u' | 'U' => "45", 30 | 'v' | 'V' => "51", 31 | 'w' | 'W' => "52", 32 | 'x' | 'X' => "53", 33 | 'y' | 'Y' => "54", 34 | 'z' | 'Z' => "55", 35 | _ => "", 36 | }) 37 | .collect() 38 | } 39 | 40 | /// Decode a string of ints into their corresponding 41 | /// letters in a Polybius square. 42 | /// 43 | /// Any invalid characters, or whitespace will be ignored. 44 | pub fn decode_ascii(string: &str) -> String { 45 | string 46 | .chars() 47 | .filter(|c| !c.is_whitespace()) 48 | .collect::() 49 | .as_bytes() 50 | .chunks(2) 51 | .map(|s| match std::str::from_utf8(s) { 52 | Ok(v) => v.parse::().unwrap_or(0), 53 | Err(_) => 0, 54 | }) 55 | .map(|i| match i { 56 | 11 => 'A', 57 | 12 => 'B', 58 | 13 => 'C', 59 | 14 => 'D', 60 | 15 => 'E', 61 | 21 => 'F', 62 | 22 => 'G', 63 | 23 => 'H', 64 | 24 => 'I', 65 | 25 => 'K', 66 | 31 => 'L', 67 | 32 => 'M', 68 | 33 => 'N', 69 | 34 => 'O', 70 | 35 => 'P', 71 | 41 => 'Q', 72 | 42 => 'R', 73 | 43 => 'S', 74 | 44 => 'T', 75 | 45 => 'U', 76 | 51 => 'V', 77 | 52 => 'W', 78 | 53 => 'X', 79 | 54 => 'Y', 80 | 55 => 'Z', 81 | _ => ' ', 82 | }) 83 | .collect::() 84 | .replace(" ", "") 85 | } 86 | 87 | #[cfg(test)] 88 | mod tests { 89 | use super::{decode_ascii, encode_ascii}; 90 | 91 | #[test] 92 | fn encode_empty() { 93 | assert_eq!(encode_ascii(""), ""); 94 | } 95 | 96 | #[test] 97 | fn encode_valid_string() { 98 | assert_eq!(encode_ascii("This is a test"), "4423244324431144154344"); 99 | } 100 | 101 | #[test] 102 | fn encode_emoji() { 103 | assert_eq!(encode_ascii("🙂"), ""); 104 | } 105 | 106 | #[test] 107 | fn decode_empty() { 108 | assert_eq!(decode_ascii(""), ""); 109 | } 110 | 111 | #[test] 112 | fn decode_valid_string() { 113 | assert_eq!( 114 | decode_ascii("44 23 24 43 24 43 11 44 15 43 44 "), 115 | "THISISATEST" 116 | ); 117 | } 118 | 119 | #[test] 120 | fn decode_emoji() { 121 | assert_eq!(decode_ascii("🙂"), ""); 122 | } 123 | 124 | #[test] 125 | fn decode_string_with_whitespace() { 126 | assert_eq!( 127 | decode_ascii("44\n23\t\r24\r\n43 2443\n 11 \t 44\r \r15 \n43 44"), 128 | "THISISATEST" 129 | ); 130 | } 131 | 132 | #[test] 133 | fn decode_unknown_string() { 134 | assert_eq!(decode_ascii("94 63 64 83 64 48 77 00 05 47 48 "), ""); 135 | } 136 | 137 | #[test] 138 | fn decode_odd_length() { 139 | assert_eq!(decode_ascii("11 22 33 4"), "AGN"); 140 | } 141 | 142 | #[test] 143 | fn encode_and_decode() { 144 | let string = "Do you ever wonder why we're here?"; 145 | let encode = encode_ascii(string); 146 | assert_eq!( 147 | "1434543445155115425234331415425223545215421523154215", 148 | encode, 149 | ); 150 | assert_eq!("DOYOUEVERWONDERWHYWEREHERE", decode_ascii(&encode)); 151 | } 152 | } 153 | ``` -------------------------------------------------------------------------------- /src/cipher/rot13.md: -------------------------------------------------------------------------------- 1 | # rot13加密算法 2 | 3 | ```rust 4 | pub fn rot13(text: &str) -> String { 5 | let to_enc = text.to_uppercase(); 6 | to_enc 7 | .chars() 8 | .map(|c| match c { 9 | 'A'..='M' => ((c as u8) + 13) as char, 10 | 'N'..='Z' => ((c as u8) - 13) as char, 11 | _ => c, 12 | }) 13 | .collect() 14 | } 15 | 16 | #[cfg(test)] 17 | mod test { 18 | use super::*; 19 | 20 | #[test] 21 | fn test_single_letter() { 22 | assert_eq!("N", rot13("A")); 23 | } 24 | 25 | #[test] 26 | fn test_bunch_of_letters() { 27 | assert_eq!("NOP", rot13("ABC")); 28 | } 29 | 30 | #[test] 31 | fn test_non_ascii() { 32 | assert_eq!("😀NO", rot13("😀AB")); 33 | } 34 | 35 | #[test] 36 | fn test_twice() { 37 | assert_eq!("ABCD", rot13(&rot13("ABCD"))); 38 | } 39 | } 40 | ``` -------------------------------------------------------------------------------- /src/cipher/vigenere.md: -------------------------------------------------------------------------------- 1 | # vigenere加密 2 | 3 | ```rust 4 | //! Vigenère Cipher 5 | //! 6 | //! # Algorithm 7 | //! 8 | //! Rotate each ascii character by the offset of the corresponding key character. 9 | //! When we reach the last key character, we start over from the first one. 10 | //! This implementation does not rotate unicode characters. 11 | 12 | /// Vigenère cipher to rotate plain_text text by key and return an owned String. 13 | pub fn vigenere(plain_text: &str, key: &str) -> String { 14 | // Remove all unicode and non-ascii characters from key 15 | let key: String = key.chars().filter(|&c| c.is_ascii_alphabetic()).collect(); 16 | key.to_ascii_lowercase(); 17 | 18 | let key_len = key.len(); 19 | if key_len == 0 { 20 | return String::from(plain_text); 21 | } 22 | 23 | let mut index = 0; 24 | 25 | plain_text 26 | .chars() 27 | .map(|c| { 28 | if c.is_ascii_alphabetic() { 29 | let first = if c.is_ascii_lowercase() { b'a' } else { b'A' }; 30 | let shift = key.as_bytes()[index % key_len] - b'a'; 31 | index += 1; 32 | // modulo the distance to keep character range 33 | (first + (c as u8 + shift - first) % 26) as char 34 | } else { 35 | c 36 | } 37 | }) 38 | .collect() 39 | } 40 | 41 | #[cfg(test)] 42 | mod tests { 43 | use super::*; 44 | 45 | #[test] 46 | fn empty() { 47 | assert_eq!(vigenere("", "test"), ""); 48 | } 49 | 50 | #[test] 51 | fn vigenere_base() { 52 | assert_eq!( 53 | vigenere("LoremIpsumDolorSitAmet", "base"), 54 | "MojinIhwvmVsmojWjtSqft" 55 | ); 56 | } 57 | 58 | #[test] 59 | fn vigenere_with_spaces() { 60 | assert_eq!( 61 | vigenere( 62 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 63 | "spaces" 64 | ), 65 | "Ddrgq ahhuo hgddr uml sbev, ggfheexwljr chahxsemfy tlkx." 66 | ); 67 | } 68 | 69 | #[test] 70 | fn vigenere_unicode_and_numbers() { 71 | assert_eq!( 72 | vigenere("1 Lorem ⏳ ipsum dolor sit amet Ѡ", "unicode"), 73 | "1 Fbzga ⏳ ltmhu fcosl fqv opin Ѡ" 74 | ); 75 | } 76 | 77 | #[test] 78 | fn vigenere_unicode_key() { 79 | assert_eq!( 80 | vigenere("Lorem ipsum dolor sit amet", "😉 key!"), 81 | "Vspoq gzwsw hmvsp cmr kqcd" 82 | ); 83 | } 84 | 85 | #[test] 86 | fn vigenere_empty_key() { 87 | assert_eq!(vigenere("Lorem ipsum", ""), "Lorem ipsum"); 88 | } 89 | } 90 | ``` -------------------------------------------------------------------------------- /src/cipher/xor.md: -------------------------------------------------------------------------------- 1 | # xor 2 | 3 | ```rust 4 | pub fn xor(text: &str, key: u8) -> String { 5 | text.chars().map(|c| ((c as u8) ^ key) as char).collect() 6 | } 7 | 8 | #[cfg(test)] 9 | mod tests { 10 | use super::*; 11 | 12 | #[test] 13 | fn test_simple() { 14 | let test_string = "test string"; 15 | let ciphered_text = xor(test_string, 32); 16 | assert_eq!(test_string, xor(&ciphered_text, 32)); 17 | } 18 | 19 | #[test] 20 | fn test_every_alphabet_with_space() { 21 | let test_string = "The quick brown fox jumps over the lazy dog"; 22 | let ciphered_text = xor(test_string, 64); 23 | assert_eq!(test_string, xor(&ciphered_text, 64)); 24 | } 25 | } 26 | ``` -------------------------------------------------------------------------------- /src/data-structures/circular-queue.md: -------------------------------------------------------------------------------- 1 | # 循环队列(Circular Queue) 2 | 3 | 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器” 4 | 5 | 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。 6 | 7 | __Properties__ 8 | * de_queue O(1) 9 | * en_queue O(1) 10 | 11 | ```rust 12 | use std::{ 13 | alloc::{self, Layout}, 14 | ptr, 15 | }; 16 | 17 | pub struct CircularQueue { 18 | write_index: usize, 19 | read_index: usize, 20 | cap: usize, 21 | len: usize, 22 | data: Box<[T]>, 23 | } 24 | 25 | impl CircularQueue { 26 | pub fn new(cap: usize) -> Self { 27 | let data = unsafe { 28 | let data_ptr = alloc::alloc(Layout::array::(cap).unwrap()) as *mut T; 29 | Box::from_raw(ptr::slice_from_raw_parts_mut(data_ptr, cap)) 30 | }; 31 | Self { 32 | write_index: 0, 33 | read_index: 0, 34 | cap, 35 | len: 0, 36 | data, 37 | } 38 | } 39 | 40 | /** 41 | * add value to CircularQueue 42 | * return true if success, false if queue is full 43 | */ 44 | pub fn en_queue(&mut self, value: T) -> bool { 45 | if self.is_full() { 46 | false 47 | } else { 48 | self.data[self.write_index] = value; 49 | self.write_index = (self.write_index + 1) % self.cap; 50 | self.len += 1; 51 | true 52 | } 53 | } 54 | 55 | /** 56 | * remove value from CircularQueue 57 | * return true if success, false if queue is full 58 | */ 59 | pub fn de_queue(&mut self) -> bool { 60 | if self.is_empty() { 61 | false 62 | } else { 63 | self.read_index = (self.read_index + 1) % self.cap; 64 | self.len -= 1; 65 | true 66 | } 67 | } 68 | 69 | /** 70 | * get front value 71 | */ 72 | pub fn front(&self) -> Option<&T> { 73 | if self.is_empty() { 74 | None 75 | } else { 76 | Some(&self.data[self.read_index]) 77 | } 78 | } 79 | 80 | /** 81 | * get tail value 82 | */ 83 | pub fn rear(&self) -> Option<&T> { 84 | if self.is_empty() { 85 | None 86 | } else if self.write_index == 0 { 87 | Some(&self.data[self.cap - 1]) 88 | } else { 89 | Some(&self.data[self.write_index - 1]) 90 | } 91 | } 92 | 93 | pub fn is_empty(&self) -> bool { 94 | self.len == 0 95 | } 96 | 97 | pub fn is_full(&self) -> bool { 98 | self.cap == self.len 99 | } 100 | } 101 | 102 | #[cfg(test)] 103 | mod tests { 104 | use std::result; 105 | 106 | use super::*; 107 | 108 | #[test] 109 | fn test_en_queue() { 110 | let mut circular_queue = CircularQueue::new(100); 111 | for i in 0..100 { 112 | let result = circular_queue.en_queue(i); 113 | assert!(result); 114 | } 115 | let result = circular_queue.en_queue(100); 116 | assert!(!result); 117 | } 118 | 119 | #[test] 120 | fn test_de_queue() { 121 | let mut circular_queue = CircularQueue::new(100); 122 | for i in 0..200 { 123 | circular_queue.en_queue(i); 124 | } 125 | 126 | for _ in 0..100 { 127 | let result = circular_queue.de_queue(); 128 | assert!(result); 129 | } 130 | 131 | let result = circular_queue.de_queue(); 132 | assert!(!result); 133 | } 134 | 135 | #[test] 136 | fn test_circular_queue_order() { 137 | let mut circular_queue = CircularQueue::new(3); 138 | 139 | for i in 1..4 { 140 | circular_queue.en_queue(i); 141 | } 142 | 143 | circular_queue.en_queue(4); 144 | 145 | let result = circular_queue.rear(); 146 | assert_eq!(result, Some(&3)); 147 | 148 | assert!(circular_queue.is_full()); 149 | 150 | circular_queue.de_queue(); 151 | 152 | circular_queue.en_queue(4); 153 | let result = circular_queue.front(); 154 | assert_eq!(result, Some(&2)); 155 | 156 | let result = circular_queue.rear(); 157 | assert_eq!(result, Some(&4)) 158 | } 159 | } 160 | ``` -------------------------------------------------------------------------------- /src/data-structures/heap.md: -------------------------------------------------------------------------------- 1 | # 堆(Heap) 2 | 3 | ```rust 4 | // Heap data structure 5 | // Takes a closure as a comparator to allow for min-heap, max-heap, and works with custom key functions 6 | 7 | use std::cmp::Ord; 8 | use std::default::Default; 9 | 10 | pub struct Heap 11 | where 12 | T: Default, 13 | { 14 | count: usize, 15 | items: Vec, 16 | comparator: fn(&T, &T) -> bool, 17 | } 18 | 19 | impl Heap 20 | where 21 | T: Default, 22 | { 23 | pub fn new(comparator: fn(&T, &T) -> bool) -> Self { 24 | Self { 25 | count: 0, 26 | // Add a default in the first spot to offset indexes 27 | // for the parent/child math to work out. 28 | // Vecs have to have all the same type so using Default 29 | // is a way to add an unused item. 30 | items: vec![T::default()], 31 | comparator, 32 | } 33 | } 34 | 35 | pub fn len(&self) -> usize { 36 | self.count 37 | } 38 | 39 | pub fn is_empty(&self) -> bool { 40 | self.len() == 0 41 | } 42 | 43 | pub fn add(&mut self, value: T) { 44 | self.count += 1; 45 | self.items.push(value); 46 | 47 | // Heapify Up 48 | let mut idx = self.count; 49 | while self.parent_idx(idx) > 0 { 50 | let pdx = self.parent_idx(idx); 51 | if (self.comparator)(&self.items[idx], &self.items[pdx]) { 52 | self.items.swap(idx, pdx); 53 | } 54 | idx = pdx; 55 | } 56 | } 57 | 58 | fn parent_idx(&self, idx: usize) -> usize { 59 | idx / 2 60 | } 61 | 62 | fn children_present(&self, idx: usize) -> bool { 63 | self.left_child_idx(idx) <= self.count 64 | } 65 | 66 | fn left_child_idx(&self, idx: usize) -> usize { 67 | idx * 2 68 | } 69 | 70 | fn right_child_idx(&self, idx: usize) -> usize { 71 | self.left_child_idx(idx) + 1 72 | } 73 | 74 | fn smallest_child_idx(&self, idx: usize) -> usize { 75 | if self.right_child_idx(idx) > self.count { 76 | self.left_child_idx(idx) 77 | } else { 78 | let ldx = self.left_child_idx(idx); 79 | let rdx = self.right_child_idx(idx); 80 | if (self.comparator)(&self.items[ldx], &self.items[rdx]) { 81 | ldx 82 | } else { 83 | rdx 84 | } 85 | } 86 | } 87 | } 88 | 89 | impl Heap 90 | where 91 | T: Default + Ord, 92 | { 93 | /// Create a new MinHeap 94 | pub fn new_min() -> Self { 95 | Self::new(|a, b| a < b) 96 | } 97 | 98 | /// Create a new MaxHeap 99 | pub fn new_max() -> Self { 100 | Self::new(|a, b| a > b) 101 | } 102 | } 103 | 104 | impl Iterator for Heap 105 | where 106 | T: Default, 107 | { 108 | type Item = T; 109 | 110 | fn next(&mut self) -> Option { 111 | if self.count == 0 { 112 | return None; 113 | } 114 | // This feels like a function built for heap impl :) 115 | // Removes an item at an index and fills in with the last item 116 | // of the Vec 117 | let next = Some(self.items.swap_remove(1)); 118 | self.count -= 1; 119 | 120 | if self.count > 0 { 121 | // Heapify Down 122 | let mut idx = 1; 123 | while self.children_present(idx) { 124 | let cdx = self.smallest_child_idx(idx); 125 | if !(self.comparator)(&self.items[idx], &self.items[cdx]) { 126 | self.items.swap(idx, cdx); 127 | } 128 | idx = cdx; 129 | } 130 | } 131 | 132 | next 133 | } 134 | } 135 | 136 | pub struct MinHeap; 137 | 138 | impl MinHeap { 139 | #[allow(clippy::new_ret_no_self)] 140 | pub fn new() -> Heap 141 | where 142 | T: Default + Ord, 143 | { 144 | Heap::new(|a, b| a < b) 145 | } 146 | } 147 | 148 | pub struct MaxHeap; 149 | 150 | impl MaxHeap { 151 | #[allow(clippy::new_ret_no_self)] 152 | pub fn new() -> Heap 153 | where 154 | T: Default + Ord, 155 | { 156 | Heap::new(|a, b| a > b) 157 | } 158 | } 159 | 160 | #[cfg(test)] 161 | mod tests { 162 | use super::*; 163 | #[test] 164 | fn test_empty_heap() { 165 | let mut heap = MaxHeap::new::(); 166 | assert_eq!(heap.next(), None); 167 | } 168 | 169 | #[test] 170 | fn test_min_heap() { 171 | let mut heap = MinHeap::new(); 172 | heap.add(4); 173 | heap.add(2); 174 | heap.add(9); 175 | heap.add(11); 176 | assert_eq!(heap.len(), 4); 177 | assert_eq!(heap.next(), Some(2)); 178 | assert_eq!(heap.next(), Some(4)); 179 | assert_eq!(heap.next(), Some(9)); 180 | heap.add(1); 181 | assert_eq!(heap.next(), Some(1)); 182 | } 183 | 184 | #[test] 185 | fn test_max_heap() { 186 | let mut heap = MaxHeap::new(); 187 | heap.add(4); 188 | heap.add(2); 189 | heap.add(9); 190 | heap.add(11); 191 | assert_eq!(heap.len(), 4); 192 | assert_eq!(heap.next(), Some(11)); 193 | assert_eq!(heap.next(), Some(9)); 194 | assert_eq!(heap.next(), Some(4)); 195 | heap.add(1); 196 | assert_eq!(heap.next(), Some(2)); 197 | } 198 | 199 | struct Point(/* x */ i32, /* y */ i32); 200 | impl Default for Point { 201 | fn default() -> Self { 202 | Self(0, 0) 203 | } 204 | } 205 | 206 | #[test] 207 | fn test_key_heap() { 208 | let mut heap: Heap = Heap::new(|a, b| a.0 < b.0); 209 | heap.add(Point(1, 5)); 210 | heap.add(Point(3, 10)); 211 | heap.add(Point(-2, 4)); 212 | assert_eq!(heap.len(), 3); 213 | assert_eq!(heap.next().unwrap().0, -2); 214 | assert_eq!(heap.next().unwrap().0, 1); 215 | heap.add(Point(50, 34)); 216 | assert_eq!(heap.next().unwrap().0, 3); 217 | } 218 | } 219 | ``` -------------------------------------------------------------------------------- /src/data-structures/index.md: -------------------------------------------------------------------------------- 1 | # 数据结构 2 | 3 | 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关 4 | 5 | 在计算机科学的发展过程中,数据结构也随之发展。程序设计中常用的数据结构包括如下几个。 6 | 7 | 1. 数组(Array) 8 | 数组是一种聚合数据类型,它是将具有相同类型的若干变量有序地组织在一起的集合。数组可以说是最基本的数据结构,在各种编程语言中都有对应。一个数组可以分解为多个数组元素,按照数据元素的类型,数组可以分为整型数组、字符型数组、浮点型数组、指针数组和结构数组等。数组还可以有一维、二维以及多维等表现形式。 9 | 10 | 2. 栈( Stack) 11 | 栈是一种特殊的线性表,它只能在一个表的一个固定端进行数据结点的插入和删除操作。栈按照后进先出的原则来存储数据,也就是说,先插入的数据将被压入栈底,最后插入的数据在栈顶,读出数据时,从栈顶开始逐个读出。栈在汇编语言程序中,经常用于重要数据的现场保护。栈中没有数据时,称为空栈。 12 | 13 | 3. 队列(Queue) 14 | 队列和栈类似,也是一种特殊的线性表。和栈不同的是,队列只允许在表的一端进行插入操作,而在另一端进行删除操作。一般来说,进行插入操作的一端称为队尾,进行删除操作的一端称为队头。队列中没有元素时,称为空队列。 15 | 16 | 4. 链表( Linked List) 17 | 链表是一种数据元素按照链式存储结构进行存储的数据结构,这种存储结构具有在物理上存在非连续的特点。链表由一系列数据结点构成,每个数据结点包括数据域和指针域两部分。其中,指针域保存了数据结构中下一个元素存放的地址。链表结构中数据元素的逻辑顺序是通过链表中的指针链接次序来实现的。 18 | 19 | 5. 树( Tree) 20 | 树是典型的非线性结构,它是包括,2个结点的有穷集合K。在树结构中,有且仅有一个根结点,该结点没有前驱结点。在树结构中的其他结点都有且仅有一个前驱结点,而且可以有两个后继结点,m≥0。 21 | 22 | 6. 图(Graph) 23 | 图是另一种非线性数据结构。在图结构中,数据结点一般称为顶点,而边是顶点的有序偶对。如果两个顶点之间存在一条边,那么就表示这两个顶点具有相邻关系。 24 | 25 | 7. 堆(Heap) 26 | 堆是一种特殊的树形数据结构,一般讨论的堆都是二叉堆。堆的特点是根结点的值是所有结点中最小的或者最大的,并且根结点的两个子树也是一个堆结构。 27 | 28 | 8. 散列表(Hash) 29 | 散列表源自于散列函数(Hash function),其思想是如果在结构中存在关键字和T相等的记录,那么必定在F(T)的存储位置可以找到该记录,这样就可以不用进行比较操作而直接取得所查记录。 30 | 31 | 9. 循环队列(Circular Queue) 32 | 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 33 | 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。 34 | -------------------------------------------------------------------------------- /src/data-structures/linked-list.md: -------------------------------------------------------------------------------- 1 | # 链表 2 | 3 | A linked list is also a `linear` data structure, and each element in the linked list is actually a separate object while all the objects are `linked together by the reference filed` in each element. In a `doubly linked list`, each node contains, besides the `next` node link, a second link field pointing to the `previous` node in the sequence. The two links may be called `next` and `prev`. And many modern operating systems use doubly linked lists to maintain references to active processes, threads and other dynamic objects. 4 | 5 | __Properties__ 6 | * Indexing O(n) 7 | * Insertion O(1) 8 | * Beginning O(1) 9 | * Middle (Indexing time+O(1)) 10 | * End O(n) 11 | * Deletion O(1) 12 | * Beginning O(1) 13 | * Middle (Indexing time+O(1)) 14 | * End O(n) 15 | * Search O(n) 16 | 17 | ```rust 18 | use std::fmt::{self, Display, Formatter}; 19 | use std::ptr::NonNull; 20 | 21 | struct Node { 22 | val: T, 23 | next: Option>>, 24 | prev: Option>>, 25 | } 26 | 27 | impl Node { 28 | fn new(t: T) -> Node { 29 | Node { 30 | val: t, 31 | prev: None, 32 | next: None, 33 | } 34 | } 35 | } 36 | 37 | pub struct LinkedList { 38 | length: u32, 39 | start: Option>>, 40 | end: Option>>, 41 | } 42 | 43 | impl Default for LinkedList { 44 | fn default() -> Self { 45 | Self::new() 46 | } 47 | } 48 | 49 | impl LinkedList { 50 | pub fn new() -> Self { 51 | Self { 52 | length: 0, 53 | start: None, 54 | end: None, 55 | } 56 | } 57 | 58 | pub fn add(&mut self, obj: T) { 59 | let mut node = Box::new(Node::new(obj)); 60 | // Since we are adding node at the end, next will always be None 61 | node.next = None; 62 | node.prev = self.end; 63 | // Get a pointer to node 64 | let node_ptr = Some(unsafe { NonNull::new_unchecked(Box::into_raw(node)) }); 65 | match self.end { 66 | // This is the case of empty list 67 | None => self.start = node_ptr, 68 | Some(end_ptr) => unsafe { (*end_ptr.as_ptr()).next = node_ptr }, 69 | } 70 | self.end = node_ptr; 71 | self.length += 1; 72 | } 73 | 74 | pub fn get(&mut self, index: i32) -> Option<&T> { 75 | self.get_ith_node(self.start, index) 76 | } 77 | 78 | fn get_ith_node(&mut self, node: Option>>, index: i32) -> Option<&T> { 79 | match node { 80 | None => None, 81 | Some(next_ptr) => match index { 82 | 0 => Some(unsafe { &(*next_ptr.as_ptr()).val }), 83 | _ => self.get_ith_node(unsafe { (*next_ptr.as_ptr()).next }, index - 1), 84 | }, 85 | } 86 | } 87 | } 88 | 89 | impl Display for LinkedList 90 | where 91 | T: Display, 92 | { 93 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 94 | match self.start { 95 | Some(node) => write!(f, "{}", unsafe { node.as_ref() }), 96 | None => Ok(()), 97 | } 98 | } 99 | } 100 | 101 | impl Display for Node 102 | where 103 | T: Display, 104 | { 105 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 106 | match self.next { 107 | Some(node) => write!(f, "{}, {}", self.val, unsafe { node.as_ref() }), 108 | None => write!(f, "{}", self.val), 109 | } 110 | } 111 | } 112 | 113 | #[cfg(test)] 114 | mod tests { 115 | use super::LinkedList; 116 | 117 | #[test] 118 | fn create_numeric_list() { 119 | let mut list = LinkedList::::new(); 120 | list.add(1); 121 | list.add(2); 122 | list.add(3); 123 | println!("Linked List is {}", list); 124 | assert_eq!(3, list.length); 125 | } 126 | 127 | #[test] 128 | fn create_string_list() { 129 | let mut list_str = LinkedList::::new(); 130 | list_str.add("A".to_string()); 131 | list_str.add("B".to_string()); 132 | list_str.add("C".to_string()); 133 | println!("Linked List is {}", list_str); 134 | assert_eq!(3, list_str.length); 135 | } 136 | 137 | #[test] 138 | fn get_by_index_in_numeric_list() { 139 | let mut list = LinkedList::::new(); 140 | list.add(1); 141 | list.add(2); 142 | println!("Linked List is {}", list); 143 | let retrived_item = list.get(1); 144 | assert!(retrived_item.is_some()); 145 | assert_eq!(2 as i32, *retrived_item.unwrap()); 146 | } 147 | 148 | #[test] 149 | fn get_by_index_in_string_list() { 150 | let mut list_str = LinkedList::::new(); 151 | list_str.add("A".to_string()); 152 | list_str.add("B".to_string()); 153 | println!("Linked List is {}", list_str); 154 | let retrived_item = list_str.get(1); 155 | assert!(retrived_item.is_some()); 156 | assert_eq!("B", *retrived_item.unwrap()); 157 | } 158 | } 159 | ``` -------------------------------------------------------------------------------- /src/data-structures/queue.md: -------------------------------------------------------------------------------- 1 | # 队列 2 | 3 | ```rust 4 | #[derive(Debug)] 5 | pub struct Queue { 6 | elements: Vec, 7 | } 8 | 9 | impl Queue { 10 | pub fn new() -> Queue { 11 | Queue { 12 | elements: Vec::new(), 13 | } 14 | } 15 | 16 | pub fn enqueue(&mut self, value: T) { 17 | self.elements.push(value) 18 | } 19 | 20 | pub fn dequeue(&mut self) -> Result { 21 | if !self.elements.is_empty() { 22 | Ok(self.elements.remove(0usize)) 23 | } else { 24 | Err("Queue is empty") 25 | } 26 | } 27 | 28 | pub fn peek(&self) -> Result<&T, &str> { 29 | match self.elements.first() { 30 | Some(value) => Ok(value), 31 | None => Err("Queue is empty"), 32 | } 33 | } 34 | 35 | pub fn size(&self) -> usize { 36 | self.elements.len() 37 | } 38 | 39 | pub fn is_empty(&self) -> bool { 40 | self.elements.is_empty() 41 | } 42 | } 43 | 44 | impl Default for Queue { 45 | fn default() -> Queue { 46 | Queue { 47 | elements: Vec::new(), 48 | } 49 | } 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::Queue; 55 | 56 | #[test] 57 | fn test_enqueue() { 58 | let mut queue: Queue = Queue::new(); 59 | queue.enqueue(64); 60 | assert_eq!(queue.is_empty(), false); 61 | } 62 | 63 | #[test] 64 | fn test_dequeue() { 65 | let mut queue: Queue = Queue::new(); 66 | queue.enqueue(32); 67 | queue.enqueue(64); 68 | let retrieved_dequeue = queue.dequeue(); 69 | assert!(retrieved_dequeue.is_ok()); 70 | assert_eq!(32, retrieved_dequeue.unwrap()); 71 | } 72 | 73 | #[test] 74 | fn test_peek() { 75 | let mut queue: Queue = Queue::new(); 76 | queue.enqueue(8); 77 | queue.enqueue(16); 78 | let retrieved_peek = queue.peek(); 79 | assert!(retrieved_peek.is_ok()); 80 | assert_eq!(8, *retrieved_peek.unwrap()); 81 | } 82 | 83 | #[test] 84 | fn test_size() { 85 | let mut queue: Queue = Queue::new(); 86 | queue.enqueue(8); 87 | queue.enqueue(16); 88 | assert_eq!(2, queue.size()); 89 | } 90 | } 91 | ``` -------------------------------------------------------------------------------- /src/data-structures/trie.md: -------------------------------------------------------------------------------- 1 | # trie树 2 | 3 | ```rust 4 | use std::collections::HashMap; 5 | use std::hash::Hash; 6 | 7 | #[derive(Debug, Default)] 8 | struct Node { 9 | children: HashMap>, 10 | value: Option, 11 | } 12 | 13 | #[derive(Debug, Default)] 14 | pub struct Trie 15 | where 16 | Key: Default + Eq + Hash, 17 | Type: Default, 18 | { 19 | root: Node, 20 | } 21 | 22 | impl Trie 23 | where 24 | Key: Default + Eq + Hash, 25 | Type: Default, 26 | { 27 | pub fn new() -> Self { 28 | Self { 29 | root: Node::default(), 30 | } 31 | } 32 | 33 | pub fn insert(&mut self, key: impl IntoIterator, value: Type) 34 | where 35 | Key: Eq + Hash, 36 | { 37 | let mut node = &mut self.root; 38 | for c in key.into_iter() { 39 | node = node.children.entry(c).or_insert_with(Node::default); 40 | } 41 | node.value = Some(value); 42 | } 43 | 44 | pub fn get(&self, key: impl IntoIterator) -> Option<&Type> 45 | where 46 | Key: Eq + Hash, 47 | { 48 | let mut node = &self.root; 49 | for c in key.into_iter() { 50 | if node.children.contains_key(&c) { 51 | node = node.children.get(&c).unwrap() 52 | } else { 53 | return None; 54 | } 55 | } 56 | node.value.as_ref() 57 | } 58 | } 59 | 60 | #[cfg(test)] 61 | mod tests { 62 | 63 | use super::*; 64 | 65 | #[test] 66 | fn test_insertion() { 67 | let mut trie = Trie::new(); 68 | assert_eq!(trie.get("".chars()), None); 69 | 70 | trie.insert("foo".chars(), 1); 71 | trie.insert("foobar".chars(), 2); 72 | 73 | let mut trie = Trie::new(); 74 | assert_eq!(trie.get(vec![1, 2, 3]), None); 75 | 76 | trie.insert(vec![1, 2, 3], 1); 77 | trie.insert(vec![3, 4, 5], 2); 78 | } 79 | 80 | #[test] 81 | fn test_get() { 82 | let mut trie = Trie::new(); 83 | trie.insert("foo".chars(), 1); 84 | trie.insert("foobar".chars(), 2); 85 | trie.insert("bar".chars(), 3); 86 | trie.insert("baz".chars(), 4); 87 | 88 | assert_eq!(trie.get("foo".chars()), Some(&1)); 89 | assert_eq!(trie.get("food".chars()), None); 90 | 91 | let mut trie = Trie::new(); 92 | trie.insert(vec![1, 2, 3, 4], 1); 93 | trie.insert(vec![42], 2); 94 | trie.insert(vec![42, 6, 1000], 3); 95 | trie.insert(vec![1, 2, 4, 16, 32], 4); 96 | 97 | assert_eq!(trie.get(vec![42, 6, 1000]), Some(&3)); 98 | assert_eq!(trie.get(vec![43, 44, 45]), None); 99 | } 100 | } 101 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/coin-change.md: -------------------------------------------------------------------------------- 1 | # 找钱(Coin change) 2 | 3 | ```rust 4 | /// Coin change via Dynamic Programming 5 | 6 | /// coin_change(coins, amount) returns the fewest number of coins that need to make up that amount. 7 | /// If that amount of money cannot be made up by any combination of the coins, return `None`. 8 | /// 9 | /// Arguments: 10 | /// * `coins` - coins of different denominations 11 | /// * `amount` - a total amount of money be made up. 12 | /// Complexity 13 | /// - time complexity: O(amount * coins.length), 14 | /// - space complexity: O(amount), 15 | pub fn coin_change(coins: &[usize], amount: usize) -> Option { 16 | let mut dp = vec![std::usize::MAX; amount + 1]; 17 | dp[0] = 0; 18 | 19 | // Assume dp[i] is the fewest number of coins making up amount i, 20 | // then for every coin in coins, dp[i] = min(dp[i - coin] + 1). 21 | for i in 0..=amount { 22 | for j in 0..coins.len() { 23 | if i >= coins[j] && dp[i - coins[j]] != std::usize::MAX { 24 | dp[i] = dp[i].min(dp[i - coins[j]] + 1); 25 | } 26 | } 27 | } 28 | 29 | match dp[amount] { 30 | std::usize::MAX => None, 31 | _ => Some(dp[amount]), 32 | } 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use super::*; 38 | 39 | #[test] 40 | fn basic() { 41 | // 11 = 5 * 2 + 1 * 1 42 | let coins = vec![1, 2, 5]; 43 | assert_eq!(Some(3), coin_change(&coins, 11)); 44 | 45 | // 119 = 11 * 10 + 7 * 1 + 2 * 1 46 | let coins = vec![2, 3, 5, 7, 11]; 47 | assert_eq!(Some(12), coin_change(&coins, 119)); 48 | } 49 | 50 | #[test] 51 | fn coins_empty() { 52 | let coins = vec![]; 53 | assert_eq!(None, coin_change(&coins, 1)); 54 | } 55 | 56 | #[test] 57 | fn amount_zero() { 58 | let coins = vec![1, 2, 3]; 59 | assert_eq!(Some(0), coin_change(&coins, 0)); 60 | } 61 | 62 | #[test] 63 | fn fail_change() { 64 | // 3 can't be change by 2. 65 | let coins = vec![2]; 66 | assert_eq!(None, coin_change(&coins, 3)); 67 | let coins = vec![10, 20, 50, 100]; 68 | assert_eq!(None, coin_change(&coins, 5)); 69 | } 70 | } 71 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/edit-distance.md: -------------------------------------------------------------------------------- 1 | # 最小编辑距离(Edit distance) 2 | 3 | ```rust 4 | /// Coin change via Dynamic Programming 5 | 6 | /// coin_change(coins, amount) returns the fewest number of coins that need to make up that amount. 7 | /// If that amount of money cannot be made up by any combination of the coins, return `None`. 8 | /// 9 | /// Arguments: 10 | /// * `coins` - coins of different denominations 11 | /// * `amount` - a total amount of money be made up. 12 | /// Complexity 13 | /// - time complexity: O(amount * coins.length), 14 | /// - space complexity: O(amount), 15 | pub fn coin_change(coins: &[usize], amount: usize) -> Option { 16 | let mut dp = vec![std::usize::MAX; amount + 1]; 17 | dp[0] = 0; 18 | 19 | // Assume dp[i] is the fewest number of coins making up amount i, 20 | // then for every coin in coins, dp[i] = min(dp[i - coin] + 1). 21 | for i in 0..=amount { 22 | for j in 0..coins.len() { 23 | if i >= coins[j] && dp[i - coins[j]] != std::usize::MAX { 24 | dp[i] = dp[i].min(dp[i - coins[j]] + 1); 25 | } 26 | } 27 | } 28 | 29 | match dp[amount] { 30 | std::usize::MAX => None, 31 | _ => Some(dp[amount]), 32 | } 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use super::*; 38 | 39 | #[test] 40 | fn basic() { 41 | // 11 = 5 * 2 + 1 * 1 42 | let coins = vec![1, 2, 5]; 43 | assert_eq!(Some(3), coin_change(&coins, 11)); 44 | 45 | // 119 = 11 * 10 + 7 * 1 + 2 * 1 46 | let coins = vec![2, 3, 5, 7, 11]; 47 | assert_eq!(Some(12), coin_change(&coins, 119)); 48 | } 49 | 50 | #[test] 51 | fn coins_empty() { 52 | let coins = vec![]; 53 | assert_eq!(None, coin_change(&coins, 1)); 54 | } 55 | 56 | #[test] 57 | fn amount_zero() { 58 | let coins = vec![1, 2, 3]; 59 | assert_eq!(Some(0), coin_change(&coins, 0)); 60 | } 61 | 62 | #[test] 63 | fn fail_change() { 64 | // 3 can't be change by 2. 65 | let coins = vec![2]; 66 | assert_eq!(None, coin_change(&coins, 3)); 67 | let coins = vec![10, 20, 50, 100]; 68 | assert_eq!(None, coin_change(&coins, 5)); 69 | } 70 | } 71 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/egg-dropping.md: -------------------------------------------------------------------------------- 1 | # 扔鸡蛋(Egg dropping) 2 | 3 | ```rust 4 | /// # Egg Dropping Puzzle 5 | 6 | /// `egg_drop(eggs, floors)` returns the least number of egg droppings 7 | /// required to determine the highest floor from which an egg will not 8 | /// break upon dropping 9 | /// 10 | /// Assumptions: n > 0 11 | pub fn egg_drop(eggs: u32, floors: u32) -> u32 { 12 | assert!(eggs > 0); 13 | 14 | // Explicity handle edge cases (optional) 15 | if eggs == 1 || floors == 0 || floors == 1 { 16 | return floors; 17 | } 18 | 19 | let eggs_index = eggs as usize; 20 | let floors_index = floors as usize; 21 | 22 | // Store solutions to subproblems in 2D Vec, 23 | // where egg_drops[i][j] represents the solution to the egg dropping 24 | // problem with i eggs and j floors 25 | let mut egg_drops: Vec> = vec![vec![0; floors_index + 1]; eggs_index + 1]; 26 | 27 | // Assign solutions for egg_drop(n, 0) = 0, egg_drop(n, 1) = 1 28 | for egg_drop in egg_drops.iter_mut().skip(1) { 29 | egg_drop[0] = 0; 30 | egg_drop[1] = 1; 31 | } 32 | 33 | // Assign solutions to egg_drop(1, k) = k 34 | for j in 1..=floors_index { 35 | egg_drops[1][j] = j as u32; 36 | } 37 | 38 | // Complete solutions vector using optimal substructure property 39 | for i in 2..=eggs_index { 40 | for j in 2..=floors_index { 41 | egg_drops[i][j] = std::u32::MAX; 42 | 43 | for k in 1..=j { 44 | let res = 1 + std::cmp::max(egg_drops[i - 1][k - 1], egg_drops[i][j - k]); 45 | 46 | if res < egg_drops[i][j] { 47 | egg_drops[i][j] = res; 48 | } 49 | } 50 | } 51 | } 52 | 53 | egg_drops[eggs_index][floors_index] 54 | } 55 | 56 | #[cfg(test)] 57 | mod tests { 58 | use super::egg_drop; 59 | 60 | #[test] 61 | fn zero_floors() { 62 | assert_eq!(egg_drop(5, 0), 0); 63 | } 64 | 65 | #[test] 66 | fn one_egg() { 67 | assert_eq!(egg_drop(1, 8), 8); 68 | } 69 | 70 | #[test] 71 | fn eggs2_floors2() { 72 | assert_eq!(egg_drop(2, 2), 2); 73 | } 74 | 75 | #[test] 76 | fn eggs3_floors5() { 77 | assert_eq!(egg_drop(3, 5), 3); 78 | } 79 | 80 | #[test] 81 | fn eggs2_floors10() { 82 | assert_eq!(egg_drop(2, 10), 4); 83 | } 84 | 85 | #[test] 86 | fn eggs2_floors36() { 87 | assert_eq!(egg_drop(2, 36), 8); 88 | } 89 | 90 | #[test] 91 | fn large_floors() { 92 | assert_eq!(egg_drop(2, 100), 14); 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/index.md: -------------------------------------------------------------------------------- 1 | # 动态规划 2 | 3 | 动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。 4 | 动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。 5 | -------------------------------------------------------------------------------- /src/dynamic-programming/knapsack.md: -------------------------------------------------------------------------------- 1 | # 背包问题 2 | 3 | ```rust 4 | //! Solves the knapsack problem 5 | use std::cmp::max; 6 | 7 | /// knapsack_table(w, weights, values) returns the knapsack table (`n`, `m`) with maximum values, where `n` is number of items 8 | /// 9 | /// Arguments: 10 | /// * `w` - knapsack capacity 11 | /// * `weights` - set of weights for each item 12 | /// * `values` - set of values for each item 13 | fn knapsack_table(w: &usize, weights: &[usize], values: &[usize]) -> Vec> { 14 | // Initialize `n` - number of items 15 | let n: usize = weights.len(); 16 | // Initialize `m` 17 | // m[i, w] - the maximum value that can be attained with weight less that or equal to `w` using items up to `i` 18 | let mut m: Vec> = vec![vec![0; w + 1]; n + 1]; 19 | 20 | for i in 0..=n { 21 | for j in 0..=*w { 22 | // m[i, j] compiled according to the following rule: 23 | if i == 0 || j == 0 { 24 | m[i][j] = 0; 25 | } else if weights[i - 1] <= j { 26 | // If `i` is in the knapsack 27 | // Then m[i, j] is equal to the maximum value of the knapsack, 28 | // where the weight `j` is reduced by the weight of the `i-th` item and the set of admissible items plus the value `k` 29 | m[i][j] = max(values[i - 1] + m[i - 1][j - weights[i - 1]], m[i - 1][j]); 30 | } else { 31 | // If the item `i` did not get into the knapsack 32 | // Then m[i, j] is equal to the maximum cost of a knapsack with the same capacity and a set of admissible items 33 | m[i][j] = m[i - 1][j] 34 | } 35 | } 36 | } 37 | m 38 | } 39 | 40 | /// knapsack_items(weights, m, i, j) returns the indices of the items of the optimal knapsack (from 1 to `n`) 41 | /// 42 | /// Arguments: 43 | /// * `weights` - set of weights for each item 44 | /// * `m` - knapsack table with maximum values 45 | /// * `i` - include items 1 through `i` in knapsack (for the initial value, use `n`) 46 | /// * `j` - maximum weight of the knapsack 47 | fn knapsack_items(weights: &[usize], m: &[Vec], i: usize, j: usize) -> Vec { 48 | if i == 0 { 49 | return vec![]; 50 | } 51 | if m[i][j] > m[i - 1][j] { 52 | let mut knap: Vec = knapsack_items(weights, m, i - 1, j - weights[i - 1]); 53 | knap.push(i); 54 | knap 55 | } else { 56 | knapsack_items(weights, m, i - 1, j) 57 | } 58 | } 59 | 60 | /// knapsack(w, weights, values) returns the tuple where first value is `optimal profit`, 61 | /// second value is `knapsack optimal weight` and the last value is `indices of items`, that we got (from 1 to `n`) 62 | /// 63 | /// Arguments: 64 | /// * `w` - knapsack capacity 65 | /// * `weights` - set of weights for each item 66 | /// * `values` - set of values for each item 67 | /// 68 | /// Complexity 69 | /// - time complexity: O(nw), 70 | /// - space complexity: O(nw), 71 | /// 72 | /// where `n` and `w` are `number of items` and `knapsack capacity` 73 | pub fn knapsack(w: usize, weights: Vec, values: Vec) -> (usize, usize, Vec) { 74 | // Checks if the number of items in the list of weights is the same as the number of items in the list of values 75 | assert_eq!(weights.len(), values.len(), "Number of items in the list of weights doesn't match the number of items in the list of values!"); 76 | // Initialize `n` - number of items 77 | let n: usize = weights.len(); 78 | // Find the knapsack table 79 | let m: Vec> = knapsack_table(&w, &weights, &values); 80 | // Find the indices of the items 81 | let items: Vec = knapsack_items(&weights, &m, n, w); 82 | // Find the total weight of optimal knapsack 83 | let mut total_weight: usize = 0; 84 | for i in items.iter() { 85 | total_weight += weights[i - 1]; 86 | } 87 | // Return result 88 | (m[n][w], total_weight, items) 89 | } 90 | 91 | #[cfg(test)] 92 | mod tests { 93 | // Took test datasets from https://people.sc.fsu.edu/~jburkardt/datasets/bin_packing/bin_packing.html 94 | use super::*; 95 | 96 | #[test] 97 | fn test_p02() { 98 | assert_eq!( 99 | (51, 26, vec![2, 3, 4]), 100 | knapsack(26, vec![12, 7, 11, 8, 9], vec![24, 13, 23, 15, 16]) 101 | ); 102 | } 103 | 104 | #[test] 105 | fn test_p04() { 106 | assert_eq!( 107 | (150, 190, vec![1, 2, 5]), 108 | knapsack( 109 | 190, 110 | vec![56, 59, 80, 64, 75, 17], 111 | vec![50, 50, 64, 46, 50, 5] 112 | ) 113 | ); 114 | } 115 | 116 | #[test] 117 | fn test_p01() { 118 | assert_eq!( 119 | (309, 165, vec![1, 2, 3, 4, 6]), 120 | knapsack( 121 | 165, 122 | vec![23, 31, 29, 44, 53, 38, 63, 85, 89, 82], 123 | vec![92, 57, 49, 68, 60, 43, 67, 84, 87, 72] 124 | ) 125 | ); 126 | } 127 | 128 | #[test] 129 | fn test_p06() { 130 | assert_eq!( 131 | (1735, 169, vec![2, 4, 7]), 132 | knapsack( 133 | 170, 134 | vec![41, 50, 49, 59, 55, 57, 60], 135 | vec![442, 525, 511, 593, 546, 564, 617] 136 | ) 137 | ); 138 | } 139 | 140 | #[test] 141 | fn test_p07() { 142 | assert_eq!( 143 | (1458, 749, vec![1, 3, 5, 7, 8, 9, 14, 15]), 144 | knapsack( 145 | 750, 146 | vec![70, 73, 77, 80, 82, 87, 90, 94, 98, 106, 110, 113, 115, 118, 120], 147 | vec![135, 139, 149, 150, 156, 163, 173, 184, 192, 201, 210, 214, 221, 229, 240] 148 | ) 149 | ); 150 | } 151 | } 152 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/longese-common-sequence.md: -------------------------------------------------------------------------------- 1 | # 最长公共子序列 2 | 3 | ```rust 4 | /// Longest common subsequence via Dynamic Programming 5 | 6 | /// longest_common_subsequence(a, b) returns the longest common subsequence 7 | /// between the strings a and b. 8 | pub fn longest_common_subsequence(a: &str, b: &str) -> String { 9 | let a: Vec<_> = a.chars().collect(); 10 | let b: Vec<_> = b.chars().collect(); 11 | let (na, nb) = (a.len(), b.len()); 12 | 13 | // solutions[i][j] is the length of the longest common subsequence 14 | // between a[0..i-1] and b[0..j-1] 15 | let mut solutions = vec![vec![0; nb + 1]; na + 1]; 16 | 17 | for (i, ci) in a.iter().enumerate() { 18 | for (j, cj) in b.iter().enumerate() { 19 | // if ci == cj, there is a new common character; 20 | // otherwise, take the best of the two solutions 21 | // at (i-1,j) and (i,j-1) 22 | solutions[i + 1][j + 1] = if ci == cj { 23 | solutions[i][j] + 1 24 | } else { 25 | solutions[i][j + 1].max(solutions[i + 1][j]) 26 | } 27 | } 28 | } 29 | 30 | // reconstitute the solution string from the lengths 31 | let mut result: Vec = Vec::new(); 32 | let (mut i, mut j) = (na, nb); 33 | while i > 0 && j > 0 { 34 | if a[i - 1] == b[j - 1] { 35 | result.push(a[i - 1]); 36 | i -= 1; 37 | j -= 1; 38 | } else if solutions[i - 1][j] > solutions[i][j - 1] { 39 | i -= 1; 40 | } else { 41 | j -= 1; 42 | } 43 | } 44 | 45 | result.reverse(); 46 | result.iter().collect() 47 | } 48 | 49 | #[cfg(test)] 50 | mod tests { 51 | use super::longest_common_subsequence; 52 | 53 | #[test] 54 | fn test_longest_common_subsequence() { 55 | // empty case 56 | assert_eq!(&longest_common_subsequence("", ""), ""); 57 | assert_eq!(&longest_common_subsequence("", "abcd"), ""); 58 | assert_eq!(&longest_common_subsequence("abcd", ""), ""); 59 | 60 | // simple cases 61 | assert_eq!(&longest_common_subsequence("abcd", "c"), "c"); 62 | assert_eq!(&longest_common_subsequence("abcd", "d"), "d"); 63 | assert_eq!(&longest_common_subsequence("abcd", "e"), ""); 64 | assert_eq!(&longest_common_subsequence("abcdefghi", "acegi"), "acegi"); 65 | 66 | // less simple cases 67 | assert_eq!(&longest_common_subsequence("abcdgh", "aedfhr"), "adh"); 68 | assert_eq!(&longest_common_subsequence("aggtab", "gxtxayb"), "gtab"); 69 | 70 | // unicode 71 | assert_eq!( 72 | &longest_common_subsequence("你好,世界", "再见世界"), 73 | "世界" 74 | ); 75 | } 76 | } 77 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/longest_continuous_increasing_subsequence.md: -------------------------------------------------------------------------------- 1 | # 最长连续递增序列 2 | 3 | ```rust 4 | pub fn longest_continuous_increasing_subsequence(input_array: &[T]) -> &[T] { 5 | let length: usize = input_array.len(); 6 | 7 | //Handle the base cases 8 | if length <= 1 { 9 | return input_array; 10 | } 11 | 12 | //Create the array to store the longest subsequence at each location 13 | let mut tracking_vec = vec![1; length]; 14 | 15 | //Iterate through the input and store longest subsequences at each location in the vector 16 | for i in (0..length - 1).rev() { 17 | if input_array[i] < input_array[i + 1] { 18 | tracking_vec[i] = tracking_vec[i + 1] + 1; 19 | } 20 | } 21 | 22 | //Find the longest subsequence 23 | let mut max_index: usize = 0; 24 | let mut max_value: i32 = 0; 25 | for (index, value) in tracking_vec.iter().enumerate() { 26 | if value > &max_value { 27 | max_value = *value; 28 | max_index = index; 29 | } 30 | } 31 | 32 | &input_array[max_index..max_index + max_value as usize] 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use super::longest_continuous_increasing_subsequence; 38 | 39 | #[test] 40 | fn test_longest_increasing_subsequence() { 41 | //Base Cases 42 | let base_case_array: [i32; 0] = []; 43 | assert_eq!( 44 | &longest_continuous_increasing_subsequence(&base_case_array), 45 | &[] 46 | ); 47 | assert_eq!(&longest_continuous_increasing_subsequence(&[1]), &[1]); 48 | 49 | //Normal i32 Cases 50 | assert_eq!( 51 | &longest_continuous_increasing_subsequence(&[1, 2, 3, 4]), 52 | &[1, 2, 3, 4] 53 | ); 54 | assert_eq!( 55 | &longest_continuous_increasing_subsequence(&[1, 2, 2, 3, 4, 2]), 56 | &[2, 3, 4] 57 | ); 58 | assert_eq!( 59 | &longest_continuous_increasing_subsequence(&[5, 4, 3, 2, 1]), 60 | &[5] 61 | ); 62 | assert_eq!( 63 | &longest_continuous_increasing_subsequence(&[5, 4, 3, 4, 2, 1]), 64 | &[3, 4] 65 | ); 66 | 67 | //Non-Numeric case 68 | assert_eq!( 69 | &longest_continuous_increasing_subsequence(&['a', 'b', 'c']), 70 | &['a', 'b', 'c'] 71 | ); 72 | assert_eq!( 73 | &longest_continuous_increasing_subsequence(&['d', 'c', 'd']), 74 | &['c', 'd'] 75 | ); 76 | } 77 | } 78 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/maximal-square.md: -------------------------------------------------------------------------------- 1 | # 最大正方形 2 | 3 | ```rust 4 | use std::cmp::max; 5 | use std::cmp::min; 6 | 7 | /// Maximal Square 8 | /// Given an m x n binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area. 9 | /// https://leetcode.com/problems/maximal-square/ 10 | /// 11 | /// Arguments: 12 | /// * `matrix` - an array of integer array 13 | /// Complexity 14 | /// - time complexity: O(n^2), 15 | /// - space complexity: O(n), 16 | pub fn maximal_square(matrix: &mut Vec>) -> i32 { 17 | if matrix.is_empty() { 18 | return 0; 19 | } 20 | 21 | let rows = matrix.len(); 22 | let cols = matrix[0].len(); 23 | let mut result: i32 = 0; 24 | 25 | for row in 0..rows { 26 | for col in 0..cols { 27 | if matrix[row][col] == 1 { 28 | if row == 0 || col == 0 { 29 | result = max(result, 1); 30 | } else { 31 | let temp = min(matrix[row - 1][col - 1], matrix[row - 1][col]); 32 | 33 | let count: i32 = min(temp, matrix[row][col - 1]) + 1; 34 | result = max(result, count); 35 | 36 | matrix[row][col] = count; 37 | } 38 | } 39 | } 40 | } 41 | 42 | result * result 43 | } 44 | 45 | #[cfg(test)] 46 | mod tests { 47 | use super::*; 48 | 49 | #[test] 50 | fn test() { 51 | assert_eq!(maximal_square(&mut vec![]), 0); 52 | 53 | let mut matrix = vec![vec![0, 1], vec![1, 0]]; 54 | assert_eq!(maximal_square(&mut matrix), 1); 55 | 56 | let mut matrix = vec![ 57 | vec![1, 0, 1, 0, 0], 58 | vec![1, 0, 1, 1, 1], 59 | vec![1, 1, 1, 1, 1], 60 | vec![1, 0, 0, 1, 0], 61 | ]; 62 | assert_eq!(maximal_square(&mut matrix), 4); 63 | 64 | let mut matrix = vec![vec![0]]; 65 | assert_eq!(maximal_square(&mut matrix), 0); 66 | } 67 | } 68 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/maximal-subarray.md: -------------------------------------------------------------------------------- 1 | # 最大子数组 2 | 3 | ```rust 4 | /// ## maximum subarray via Dynamic Programming 5 | 6 | /// maximum_subarray(array) find the subarray (containing at least one number) which has the largest sum 7 | /// and return its sum. 8 | /// 9 | /// A subarray is a contiguous part of an array. 10 | /// 11 | /// Arguments: 12 | /// * `array` - an integer array 13 | /// Complexity 14 | /// - time complexity: O(array.length), 15 | /// - space complexity: O(array.length), 16 | pub fn maximum_subarray(array: &[i32]) -> i32 { 17 | let mut dp = vec![0; array.len()]; 18 | dp[0] = array[0]; 19 | let mut result = dp[0]; 20 | 21 | for i in 1..array.len() { 22 | if dp[i - 1] > 0 { 23 | dp[i] = dp[i - 1] + array[i]; 24 | } else { 25 | dp[i] = array[i]; 26 | } 27 | result = result.max(dp[i]); 28 | } 29 | 30 | result 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use super::*; 36 | 37 | #[test] 38 | fn non_negative() { 39 | //the maximum value: 1 + 0 + 5 + 8 = 14 40 | let array = vec![1, 0, 5, 8]; 41 | assert_eq!(maximum_subarray(&array), 14); 42 | } 43 | 44 | #[test] 45 | fn negative() { 46 | //the maximum value: -1 47 | let array = vec![-3, -1, -8, -2]; 48 | assert_eq!(maximum_subarray(&array), -1); 49 | } 50 | 51 | #[test] 52 | fn normal() { 53 | //the maximum value: 3 + (-2) + 5 = 6 54 | let array = vec![-4, 3, -2, 5, -8]; 55 | assert_eq!(maximum_subarray(&array), 6); 56 | } 57 | 58 | #[test] 59 | fn single_element() { 60 | let array = vec![6]; 61 | assert_eq!(maximum_subarray(&array), 6); 62 | let array = vec![-6]; 63 | assert_eq!(maximum_subarray(&array), -6); 64 | } 65 | } 66 | ``` -------------------------------------------------------------------------------- /src/dynamic-programming/rod-cutting.md: -------------------------------------------------------------------------------- 1 | # 棒的切割 2 | 3 | ```rust 4 | //! Solves the rod-cutting problem 5 | use std::cmp::max; 6 | 7 | /// `rod_cut(p)` returns the maximum possible profit if a rod of length `n` = `p.len()` 8 | /// is cut into up to `n` pieces, where the profit gained from each piece of length 9 | /// `l` is determined by `p[l - 1]` and the total profit is the sum of the profit 10 | /// gained from each piece. 11 | /// 12 | /// # Arguments 13 | /// - `p` - profit for rods of length 1 to n inclusive 14 | /// 15 | /// # Complexity 16 | /// - time complexity: O(n^2), 17 | /// - space complexity: O(n^2), 18 | /// 19 | /// where n is the length of `p`. 20 | pub fn rod_cut(p: &[usize]) -> usize { 21 | let n = p.len(); 22 | // f is the dynamic programming table 23 | let mut f = vec![0; n]; 24 | 25 | for i in 0..n { 26 | let mut max_price = p[i]; 27 | for j in 1..=i { 28 | max_price = max(max_price, p[j - 1] + f[i - j]); 29 | } 30 | f[i] = max_price; 31 | } 32 | 33 | // accomodate for input with length zero 34 | if n != 0 { 35 | f[n - 1] 36 | } else { 37 | 0 38 | } 39 | } 40 | 41 | #[cfg(test)] 42 | mod tests { 43 | use super::rod_cut; 44 | 45 | #[test] 46 | fn test_rod_cut() { 47 | assert_eq!(0, rod_cut(&[])); 48 | assert_eq!(15, rod_cut(&[5, 8, 2])); 49 | assert_eq!(10, rod_cut(&[1, 5, 8, 9])); 50 | assert_eq!(25, rod_cut(&[5, 8, 2, 1, 7])); 51 | assert_eq!(87, rod_cut(&[0, 0, 0, 0, 0, 87])); 52 | assert_eq!(49, rod_cut(&[7, 6, 5, 4, 3, 2, 1])); 53 | assert_eq!(22, rod_cut(&[1, 5, 8, 9, 10, 17, 17, 20])); 54 | assert_eq!(60, rod_cut(&[6, 4, 8, 2, 5, 8, 2, 3, 7, 11])); 55 | assert_eq!(30, rod_cut(&[1, 5, 8, 9, 10, 17, 17, 20, 24, 30])); 56 | assert_eq!(12, rod_cut(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])); 57 | } 58 | } 59 | ``` -------------------------------------------------------------------------------- /src/general/convex-hull.md: -------------------------------------------------------------------------------- 1 | # 凸包算法 2 | 3 | ```rust 4 | use std::cmp::Ordering::Equal; 5 | 6 | fn sort_by_min_angle(pts: &[(f64, f64)], min: &(f64, f64)) -> Vec<(f64, f64)> { 7 | let mut points: Vec<(f64, f64, (f64, f64))> = pts 8 | .iter() 9 | .map(|x| { 10 | ( 11 | ((x.1 - min.1) as f64).atan2((x.0 - min.0) as f64), 12 | // angle 13 | ((x.1 - min.1) as f64).hypot((x.0 - min.0) as f64), 14 | // distance (we want the closest to be first) 15 | *x, 16 | ) 17 | }) 18 | .collect(); 19 | points.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Equal)); 20 | points.into_iter().map(|x| x.2).collect() 21 | } 22 | 23 | // calculates the z coordinate of the vector product of vectors ab and ac 24 | fn calc_z_coord_vector_product(a: &(f64, f64), b: &(f64, f64), c: &(f64, f64)) -> f64 { 25 | (b.0 - a.0) * (c.1 - a.1) - (c.0 - a.0) * (b.1 - a.1) 26 | } 27 | 28 | /* 29 | If three points are aligned and are part of the convex hull then the three are kept. 30 | If one doesn't want to keep those points, it is easy to iterate the answer and remove them. 31 | The first point is the one with the lowest y-coordinate and the lowest x-coordinate. 32 | Points are then given counter-clockwise, and the closest one is given first if needed. 33 | */ 34 | pub fn convex_hull_graham(pts: &[(f64, f64)]) -> Vec<(f64, f64)> { 35 | if pts.is_empty() { 36 | return vec![]; 37 | } 38 | 39 | let mut stack: Vec<(f64, f64)> = vec![]; 40 | let min = pts 41 | .iter() 42 | .min_by(|a, b| { 43 | let ord = a.1.partial_cmp(&b.1).unwrap_or(Equal); 44 | match ord { 45 | Equal => a.0.partial_cmp(&b.0).unwrap_or(Equal), 46 | o => o, 47 | } 48 | }) 49 | .unwrap(); 50 | let points = sort_by_min_angle(pts, min); 51 | 52 | if points.len() <= 3 { 53 | return points; 54 | } 55 | 56 | for point in points { 57 | while stack.len() > 1 58 | && calc_z_coord_vector_product(&stack[stack.len() - 2], &stack[stack.len() - 1], &point) 59 | < 0. 60 | { 61 | stack.pop(); 62 | } 63 | stack.push(point); 64 | } 65 | 66 | stack 67 | } 68 | 69 | #[cfg(test)] 70 | mod tests { 71 | use super::*; 72 | 73 | #[test] 74 | fn empty() { 75 | assert_eq!(convex_hull_graham(&vec![]), vec![]); 76 | } 77 | 78 | #[test] 79 | fn not_enough_points() { 80 | let list = vec![(0f64, 0f64)]; 81 | assert_eq!(convex_hull_graham(&list), list); 82 | } 83 | 84 | #[test] 85 | fn not_enough_points1() { 86 | let list = vec![(2f64, 2f64), (1f64, 1f64), (0f64, 0f64)]; 87 | let ans = vec![(0f64, 0f64), (1f64, 1f64), (2f64, 2f64)]; 88 | assert_eq!(convex_hull_graham(&list), ans); 89 | } 90 | 91 | #[test] 92 | fn not_enough_points2() { 93 | let list = vec![(2f64, 2f64), (1f64, 2f64), (0f64, 0f64)]; 94 | let ans = vec![(0f64, 0f64), (2f64, 2f64), (1f64, 2f64)]; 95 | assert_eq!(convex_hull_graham(&list), ans); 96 | } 97 | 98 | #[test] 99 | // from https://codegolf.stackexchange.com/questions/11035/find-the-convex-hull-of-a-set-of-2d-points 100 | fn lots_of_points() { 101 | let list = vec![ 102 | (4.4, 14.), 103 | (6.7, 15.25), 104 | (6.9, 12.8), 105 | (2.1, 11.1), 106 | (9.5, 14.9), 107 | (13.2, 11.9), 108 | (10.3, 12.3), 109 | (6.8, 9.5), 110 | (3.3, 7.7), 111 | (0.6, 5.1), 112 | (5.3, 2.4), 113 | (8.45, 4.7), 114 | (11.5, 9.6), 115 | (13.8, 7.3), 116 | (12.9, 3.1), 117 | (11., 1.1), 118 | ]; 119 | let ans = vec![ 120 | (11., 1.1), 121 | (12.9, 3.1), 122 | (13.8, 7.3), 123 | (13.2, 11.9), 124 | (9.5, 14.9), 125 | (6.7, 15.25), 126 | (4.4, 14.), 127 | (2.1, 11.1), 128 | (0.6, 5.1), 129 | (5.3, 2.4), 130 | ]; 131 | 132 | assert_eq!(convex_hull_graham(&list), ans); 133 | } 134 | 135 | #[test] 136 | // from https://codegolf.stackexchange.com/questions/11035/find-the-convex-hull-of-a-set-of-2d-points 137 | fn lots_of_points2() { 138 | let list = vec![ 139 | (1., 0.), 140 | (1., 1.), 141 | (1., -1.), 142 | (0.68957, 0.283647), 143 | (0.909487, 0.644276), 144 | (0.0361877, 0.803816), 145 | (0.583004, 0.91555), 146 | (-0.748169, 0.210483), 147 | (-0.553528, -0.967036), 148 | (0.316709, -0.153861), 149 | (-0.79267, 0.585945), 150 | (-0.700164, -0.750994), 151 | (0.452273, -0.604434), 152 | (-0.79134, -0.249902), 153 | (-0.594918, -0.397574), 154 | (-0.547371, -0.434041), 155 | (0.958132, -0.499614), 156 | (0.039941, 0.0990732), 157 | (-0.891471, -0.464943), 158 | (0.513187, -0.457062), 159 | (-0.930053, 0.60341), 160 | (0.656995, 0.854205), 161 | ]; 162 | let ans = vec![ 163 | (1., -1.), 164 | (1., 0.), 165 | (1., 1.), 166 | (0.583004, 0.91555), 167 | (0.0361877, 0.803816), 168 | (-0.930053, 0.60341), 169 | (-0.891471, -0.464943), 170 | (-0.700164, -0.750994), 171 | (-0.553528, -0.967036), 172 | ]; 173 | 174 | assert_eq!(convex_hull_graham(&list), ans); 175 | } 176 | } 177 | ``` -------------------------------------------------------------------------------- /src/general/hanoi.md: -------------------------------------------------------------------------------- 1 | # 汉诺塔算法 2 | 3 | ```rust 4 | pub fn hanoi(n: i32, from: i32, to: i32, via: i32, moves: &mut Vec<(i32, i32)>) { 5 | if n > 0 { 6 | hanoi(n - 1, from, via, to, moves); 7 | moves.push((from, to)); 8 | hanoi(n - 1, via, to, from, moves); 9 | } 10 | } 11 | 12 | #[cfg(test)] 13 | mod tests { 14 | use super::*; 15 | 16 | #[test] 17 | fn hanoi_simple() { 18 | let correct_solution: Vec<(i32, i32)> = 19 | vec![(1, 3), (1, 2), (3, 2), (1, 3), (2, 1), (2, 3), (1, 3)]; 20 | let mut our_solution: Vec<(i32, i32)> = Vec::new(); 21 | hanoi(3, 1, 3, 2, &mut our_solution); 22 | assert_eq!(correct_solution, our_solution); 23 | } 24 | } 25 | ``` -------------------------------------------------------------------------------- /src/general/index.md: -------------------------------------------------------------------------------- 1 | # 常用算法 2 | -------------------------------------------------------------------------------- /src/general/nqueens.md: -------------------------------------------------------------------------------- 1 | # N皇后算法 2 | 3 | ```rust 4 | #[allow(unused_imports)] 5 | use std::env::args; 6 | 7 | #[allow(dead_code)] 8 | fn main() { 9 | let mut board_width = 0; 10 | 11 | for arg in args() { 12 | board_width = match arg.parse() { 13 | Ok(x) => x, 14 | _ => 0, 15 | }; 16 | 17 | if board_width != 0 { 18 | break; 19 | } 20 | } 21 | 22 | if board_width < 4 { 23 | println!( 24 | "Running algorithm with 8 as a default. Specify an alternative Chess board size for \ 25 | N-Queens as a command line argument.\n" 26 | ); 27 | board_width = 8; 28 | } 29 | 30 | let board = match nqueens(board_width) { 31 | Ok(success) => success, 32 | Err(err) => panic!("{}", err), 33 | }; 34 | 35 | println!("N-Queens {} by {} board result:", board_width, board_width); 36 | print_board(&board); 37 | } 38 | 39 | /* 40 | The n-Queens search is a backtracking algorithm. Each row of the Chess board where a Queen is 41 | placed is dependent on all earlier rows. As only one Queen can fit per row, a one-dimensional 42 | integer array is used to represent the Queen's offset on each row. 43 | */ 44 | pub fn nqueens(board_width: i64) -> Result, &'static str> { 45 | let mut board_rows = vec![0; board_width as usize]; 46 | let mut conflict; 47 | let mut current_row = 0; 48 | 49 | //Process by row up to the current active row 50 | loop { 51 | conflict = false; 52 | 53 | //Column review of previous rows 54 | for review_index in 0..current_row { 55 | //Calculate the diagonals of earlier rows where a Queen would be a conflict 56 | let left = board_rows[review_index] - (current_row as i64 - review_index as i64); 57 | let right = board_rows[review_index] + (current_row as i64 - review_index as i64); 58 | 59 | if board_rows[current_row] == board_rows[review_index] 60 | || (left >= 0 && left == board_rows[current_row]) 61 | || (right < board_width as i64 && right == board_rows[current_row]) 62 | { 63 | conflict = true; 64 | break; 65 | } 66 | } 67 | 68 | match conflict { 69 | true => { 70 | board_rows[current_row] += 1; 71 | 72 | if current_row == 0 && board_rows[current_row] == board_width { 73 | return Err("No solution exists for specificed board size."); 74 | } 75 | 76 | while board_rows[current_row] == board_width { 77 | board_rows[current_row] = 0; 78 | 79 | if current_row == 0 { 80 | return Err("No solution exists for specificed board size."); 81 | } 82 | 83 | current_row -= 1; 84 | board_rows[current_row] += 1; 85 | } 86 | } 87 | _ => { 88 | current_row += 1; 89 | 90 | if current_row as i64 == board_width { 91 | break; 92 | } 93 | } 94 | } 95 | } 96 | 97 | Ok(board_rows) 98 | } 99 | 100 | fn print_board(board: &[i64]) { 101 | for row in 0..board.len() { 102 | print!("{}\t", board[row as usize]); 103 | 104 | for column in 0..board.len() as i64 { 105 | if board[row as usize] == column { 106 | print!("Q"); 107 | } else { 108 | print!("."); 109 | } 110 | } 111 | println!(); 112 | } 113 | } 114 | 115 | #[cfg(test)] 116 | mod test { 117 | use super::*; 118 | 119 | fn check_board(board: &Vec) -> bool { 120 | for current_row in 0..board.len() { 121 | //Column review 122 | for review_index in 0..current_row { 123 | //Look for any conflict. 124 | let left = board[review_index] - (current_row as i64 - review_index as i64); 125 | let right = board[review_index] + (current_row as i64 - review_index as i64); 126 | 127 | if board[current_row] == board[review_index] 128 | || (left >= 0 && left == board[current_row]) 129 | || (right < board.len() as i64 && right == board[current_row]) 130 | { 131 | return false; 132 | } 133 | } 134 | } 135 | true 136 | } 137 | 138 | #[test] 139 | fn test_board_size_4() { 140 | let board = nqueens(4).expect("Error propagated."); 141 | assert_eq!(board, vec![1, 3, 0, 2]); 142 | assert!(check_board(&board)); 143 | } 144 | 145 | #[test] 146 | fn test_board_size_7() { 147 | let board = nqueens(7).expect("Error propagated."); 148 | assert_eq!(board, vec![0, 2, 4, 6, 1, 3, 5]); 149 | assert!(check_board(&board)); 150 | } 151 | } 152 | ``` -------------------------------------------------------------------------------- /src/general/two-sum.md: -------------------------------------------------------------------------------- 1 | # 两数之和 2 | 3 | ```rust 4 | use std::collections::HashMap; 5 | use std::convert::TryInto; 6 | 7 | // Given an array of integers nums and an integer target, 8 | // return indices of the two numbers such that they add up to target. 9 | 10 | pub fn two_sum(nums: Vec, target: i32) -> Vec { 11 | let mut hash_map: HashMap = HashMap::new(); 12 | 13 | for (i, item) in nums.iter().enumerate() { 14 | match hash_map.get(&(target - item)) { 15 | Some(value) => { 16 | return vec![i.try_into().unwrap(), *value]; 17 | } 18 | None => { 19 | hash_map.insert(*item, i.try_into().unwrap()); 20 | } 21 | } 22 | } 23 | 24 | vec![] 25 | } 26 | 27 | #[cfg(test)] 28 | mod test { 29 | use super::*; 30 | 31 | #[test] 32 | fn test() { 33 | let nums = vec![2, 7, 11, 15]; 34 | assert_eq!(two_sum(nums, 9), vec![1, 0]); 35 | 36 | let nums = vec![3, 2, 4]; 37 | assert_eq!(two_sum(nums, 6), vec![2, 1]); 38 | 39 | let nums = vec![3, 3]; 40 | assert_eq!(two_sum(nums, 6), vec![1, 0]); 41 | } 42 | } 43 | ``` -------------------------------------------------------------------------------- /src/geometry/index.md: -------------------------------------------------------------------------------- 1 | # 几何 2 | -------------------------------------------------------------------------------- /src/graph/breadth-first-search.md: -------------------------------------------------------------------------------- 1 | # 广度优先搜索 2 | 3 | ```rust 4 | use std::collections::HashSet; 5 | use std::collections::VecDeque; 6 | 7 | /// Perform a breadth-first search on Graph `graph`. 8 | /// 9 | /// # Parameters 10 | /// 11 | /// - `graph`: The graph to search. 12 | /// - `root`: The starting node of the graph from which to begin searching. 13 | /// - `target`: The target node for the search. 14 | /// 15 | /// # Returns 16 | /// 17 | /// If the target is found, an Optional vector is returned with the history 18 | /// of nodes visited as its contents. 19 | /// 20 | /// If the target is not found or there is no path from the root, 21 | /// `None` is returned. 22 | /// 23 | pub fn breadth_first_search(graph: &Graph, root: Node, target: Node) -> Option> { 24 | let mut visited: HashSet = HashSet::new(); 25 | let mut history: Vec = Vec::new(); 26 | let mut queue = VecDeque::new(); 27 | 28 | visited.insert(root); 29 | queue.push_back(root); 30 | while let Some(currentnode) = queue.pop_front() { 31 | history.push(currentnode.value()); 32 | 33 | // If we reach the goal, return our travel history. 34 | if currentnode == target { 35 | return Some(history); 36 | } 37 | 38 | // Check the neighboring nodes for any that we've not visited yet. 39 | for neighbor in currentnode.neighbors(graph) { 40 | if !visited.contains(&neighbor) { 41 | visited.insert(neighbor); 42 | queue.push_back(neighbor); 43 | } 44 | } 45 | } 46 | 47 | // All nodes were visited, yet the target was not found. 48 | None 49 | } 50 | 51 | // Data Structures 52 | 53 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 54 | pub struct Node(u32); 55 | 56 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 57 | pub struct Edge(u32, u32); 58 | 59 | #[derive(Clone)] 60 | pub struct Graph { 61 | nodes: Vec, 62 | edges: Vec, 63 | } 64 | 65 | impl Graph { 66 | pub fn new(nodes: Vec, edges: Vec) -> Self { 67 | Graph { nodes, edges } 68 | } 69 | } 70 | 71 | impl From for Node { 72 | fn from(item: u32) -> Self { 73 | Node(item) 74 | } 75 | } 76 | 77 | impl Node { 78 | pub fn value(&self) -> u32 { 79 | self.0 80 | } 81 | 82 | pub fn neighbors(&self, graph: &Graph) -> Vec { 83 | graph 84 | .edges 85 | .iter() 86 | .filter(|e| e.0 == self.0) 87 | .map(|e| e.1.into()) 88 | .collect() 89 | } 90 | } 91 | 92 | impl From<(u32, u32)> for Edge { 93 | fn from(item: (u32, u32)) -> Self { 94 | Edge(item.0, item.1) 95 | } 96 | } 97 | 98 | #[cfg(test)] 99 | mod tests { 100 | use super::*; 101 | 102 | /* Example graph #1: 103 | * 104 | * (1) <--- Root 105 | * / \ 106 | * (2) (3) 107 | * / | | \ 108 | * (4) (5) (6) (7) 109 | * | 110 | * (8) 111 | */ 112 | fn graph1() -> Graph { 113 | let nodes = vec![1, 2, 3, 4, 5, 6, 7]; 114 | let edges = vec![(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7), (5, 8)]; 115 | 116 | Graph::new( 117 | nodes.into_iter().map(|v| v.into()).collect(), 118 | edges.into_iter().map(|e| e.into()).collect(), 119 | ) 120 | } 121 | 122 | #[test] 123 | fn breadth_first_search_graph1_when_node_not_found_returns_none() { 124 | let graph = graph1(); 125 | let root = 1; 126 | let target = 10; 127 | 128 | assert_eq!( 129 | breadth_first_search(&graph, root.into(), target.into()), 130 | None 131 | ); 132 | } 133 | 134 | #[test] 135 | fn breadth_first_search_graph1_when_target_8_should_evaluate_all_nodes_first() { 136 | let graph = graph1(); 137 | let root = 1; 138 | let target = 8; 139 | 140 | let expected_path = vec![1, 2, 3, 4, 5, 6, 7, 8]; 141 | 142 | assert_eq!( 143 | breadth_first_search(&graph, root.into(), target.into()), 144 | Some(expected_path) 145 | ); 146 | } 147 | 148 | /* Example graph #2: 149 | * 150 | * (1) --- (2) (3) --- (4) 151 | * / | / / 152 | * / | / / 153 | * / | / / 154 | * (5) (6) --- (7) (8) 155 | */ 156 | fn graph2() -> Graph { 157 | let nodes = vec![1, 2, 3, 4, 5, 6, 7, 8]; 158 | let undirected_edges = vec![ 159 | (1, 2), 160 | (2, 1), 161 | (2, 5), 162 | (5, 2), 163 | (2, 6), 164 | (6, 2), 165 | (3, 4), 166 | (4, 3), 167 | (3, 6), 168 | (6, 3), 169 | (4, 7), 170 | (7, 4), 171 | (6, 7), 172 | (7, 6), 173 | ]; 174 | 175 | Graph::new( 176 | nodes.into_iter().map(|v| v.into()).collect(), 177 | undirected_edges.into_iter().map(|e| e.into()).collect(), 178 | ) 179 | } 180 | 181 | #[test] 182 | fn breadth_first_search_graph2_when_no_path_to_node_returns_none() { 183 | let graph = graph2(); 184 | let root = 8; 185 | let target = 4; 186 | 187 | assert_eq!( 188 | breadth_first_search(&graph, root.into(), target.into()), 189 | None 190 | ); 191 | } 192 | 193 | #[test] 194 | fn breadth_first_search_graph2_should_find_path_from_4_to_1() { 195 | let graph = graph2(); 196 | let root = 4; 197 | let target = 1; 198 | 199 | let expected_path = vec![4, 3, 7, 6, 2, 1]; 200 | 201 | assert_eq!( 202 | breadth_first_search(&graph, root.into(), target.into()), 203 | Some(expected_path) 204 | ); 205 | } 206 | } 207 | ``` -------------------------------------------------------------------------------- /src/graph/depth-first-search.md: -------------------------------------------------------------------------------- 1 | # 深度优先搜索 2 | 3 | ```rust 4 | use std::collections::HashSet; 5 | use std::collections::VecDeque; 6 | 7 | // Perform a Depth First Search Algorithm to find a element in a graph 8 | // 9 | // Return a Optional with a vector with history of vertex visiteds 10 | // or a None if the element not exists on the graph 11 | pub fn depth_first_search(graph: &Graph, root: Vertex, objective: Vertex) -> Option> { 12 | let mut visited: HashSet = HashSet::new(); 13 | let mut history: Vec = Vec::new(); 14 | let mut queue = VecDeque::new(); 15 | queue.push_back(root); 16 | 17 | // While there is an element in the queue 18 | // get the first element of the vertex queue 19 | while let Some(current_vertex) = queue.pop_front() { 20 | // Added current vertex in the history of visiteds vertex 21 | history.push(current_vertex.value()); 22 | 23 | // Verify if this vertex is the objective 24 | if current_vertex == objective { 25 | // Return the Optional with the history of visiteds vertex 26 | return Some(history); 27 | } 28 | 29 | // For each over the neighbors of current vertex 30 | for neighbor in current_vertex.neighbors(graph).into_iter().rev() { 31 | // Insert in the HashSet of visiteds if this value not exist yet 32 | if visited.insert(neighbor) { 33 | // Add the neighbor on front of queue 34 | queue.push_front(neighbor); 35 | } 36 | } 37 | } 38 | 39 | // If all vertex is visited and the objective is not found 40 | // return a Optional with None value 41 | None 42 | } 43 | 44 | // Data Structures 45 | 46 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 47 | pub struct Vertex(u32); 48 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 49 | pub struct Edge(u32, u32); 50 | #[derive(Clone)] 51 | pub struct Graph { 52 | vertices: Vec, 53 | edges: Vec, 54 | } 55 | 56 | impl Graph { 57 | pub fn new(vertices: Vec, edges: Vec) -> Self { 58 | Graph { vertices, edges } 59 | } 60 | } 61 | 62 | impl From for Vertex { 63 | fn from(item: u32) -> Self { 64 | Vertex(item) 65 | } 66 | } 67 | 68 | impl Vertex { 69 | pub fn value(&self) -> u32 { 70 | self.0 71 | } 72 | 73 | pub fn neighbors(&self, graph: &Graph) -> VecDeque { 74 | graph 75 | .edges 76 | .iter() 77 | .filter(|e| e.0 == self.0) 78 | .map(|e| e.1.into()) 79 | .collect() 80 | } 81 | } 82 | 83 | impl From<(u32, u32)> for Edge { 84 | fn from(item: (u32, u32)) -> Self { 85 | Edge(item.0, item.1) 86 | } 87 | } 88 | 89 | #[cfg(test)] 90 | mod tests { 91 | use super::*; 92 | 93 | #[test] 94 | fn find_1_fail() { 95 | let vertices = vec![1, 2, 3, 4, 5, 6, 7]; 96 | let edges = vec![(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)]; 97 | 98 | let root = 1; 99 | let objective = 99; 100 | 101 | let graph = Graph::new( 102 | vertices.into_iter().map(|v| v.into()).collect(), 103 | edges.into_iter().map(|e| e.into()).collect(), 104 | ); 105 | 106 | assert_eq!( 107 | depth_first_search(&graph, root.into(), objective.into()), 108 | None 109 | ); 110 | } 111 | 112 | #[test] 113 | fn find_1_sucess() { 114 | let vertices = vec![1, 2, 3, 4, 5, 6, 7]; 115 | let edges = vec![(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)]; 116 | 117 | let root = 1; 118 | let objective = 7; 119 | 120 | let correct_path = vec![1, 2, 4, 5, 3, 6, 7]; 121 | 122 | let graph = Graph::new( 123 | vertices.into_iter().map(|v| v.into()).collect(), 124 | edges.into_iter().map(|e| e.into()).collect(), 125 | ); 126 | 127 | assert_eq!( 128 | depth_first_search(&graph, root.into(), objective.into()), 129 | Some(correct_path) 130 | ); 131 | } 132 | 133 | #[test] 134 | fn find_2_sucess() { 135 | let vertices = vec![0, 1, 2, 3, 4, 5, 6, 7]; 136 | let edges = vec![ 137 | (0, 1), 138 | (1, 3), 139 | (3, 2), 140 | (2, 1), 141 | (3, 4), 142 | (4, 5), 143 | (5, 7), 144 | (7, 6), 145 | (6, 4), 146 | ]; 147 | 148 | let root = 0; 149 | let objective = 6; 150 | 151 | let correct_path = vec![0, 1, 3, 2, 4, 5, 7, 6]; 152 | 153 | let graph = Graph::new( 154 | vertices.into_iter().map(|v| v.into()).collect(), 155 | edges.into_iter().map(|e| e.into()).collect(), 156 | ); 157 | 158 | assert_eq!( 159 | depth_first_search(&graph, root.into(), objective.into()), 160 | Some(correct_path) 161 | ); 162 | } 163 | 164 | #[test] 165 | fn find_3_sucess() { 166 | let vertices = vec![0, 1, 2, 3, 4, 5, 6, 7]; 167 | let edges = vec![ 168 | (0, 1), 169 | (1, 3), 170 | (3, 2), 171 | (2, 1), 172 | (3, 4), 173 | (4, 5), 174 | (5, 7), 175 | (7, 6), 176 | (6, 4), 177 | ]; 178 | 179 | let root = 0; 180 | let objective = 4; 181 | 182 | let correct_path = vec![0, 1, 3, 2, 4]; 183 | 184 | let graph = Graph::new( 185 | vertices.into_iter().map(|v| v.into()).collect(), 186 | edges.into_iter().map(|e| e.into()).collect(), 187 | ); 188 | 189 | assert_eq!( 190 | depth_first_search(&graph, root.into(), objective.into()), 191 | Some(correct_path) 192 | ); 193 | } 194 | } 195 | ``` -------------------------------------------------------------------------------- /src/graph/dijkstra.md: -------------------------------------------------------------------------------- 1 | # 最短路径-Dijkstra 2 | 3 | ```rust 4 | use std::cmp::Reverse; 5 | use std::collections::{BTreeMap, BinaryHeap}; 6 | use std::ops::Add; 7 | 8 | type Graph = BTreeMap>; 9 | 10 | // performs Dijsktra's algorithm on the given graph from the given start 11 | // the graph is a positively-weighted undirected graph 12 | // 13 | // returns a map that for each reachable vertex associates the distance and the predecessor 14 | // since the start has no predecessor but is reachable, map[start] will be None 15 | pub fn dijkstra>( 16 | graph: &Graph, 17 | start: &V, 18 | ) -> BTreeMap> { 19 | let mut ans = BTreeMap::new(); 20 | let mut prio = BinaryHeap::new(); 21 | 22 | // start is the special case that doesn't have a predecessor 23 | ans.insert(*start, None); 24 | 25 | for (new, weight) in &graph[start] { 26 | ans.insert(*new, Some((*start, *weight))); 27 | prio.push(Reverse((*weight, new, start))); 28 | } 29 | 30 | while let Some(Reverse((dist_new, new, prev))) = prio.pop() { 31 | match ans[new] { 32 | // what we popped is what is in ans, we'll compute it 33 | Some((p, d)) if p == *prev && d == dist_new => {} 34 | // otherwise it's not interesting 35 | _ => continue, 36 | } 37 | 38 | for (next, weight) in &graph[new] { 39 | match ans.get(next) { 40 | // if ans[next] is a lower dist than the alternative one, we do nothing 41 | Some(Some((_, dist_next))) if dist_new + *weight >= *dist_next => {} 42 | // if ans[next] is None then next is start and so the distance won't be changed, it won't be added again in prio 43 | Some(None) => {} 44 | // the new path is shorter, either new was not in ans or it was farther 45 | _ => { 46 | ans.insert(*next, Some((*new, *weight + dist_new))); 47 | prio.push(Reverse((*weight + dist_new, next, new))); 48 | } 49 | } 50 | } 51 | } 52 | 53 | ans 54 | } 55 | 56 | #[cfg(test)] 57 | mod tests { 58 | use super::{dijkstra, Graph}; 59 | use std::collections::BTreeMap; 60 | 61 | fn add_edge(graph: &mut Graph, v1: V, v2: V, c: E) { 62 | graph.entry(v1).or_insert_with(BTreeMap::new).insert(v2, c); 63 | graph.entry(v2).or_insert_with(BTreeMap::new); 64 | } 65 | 66 | #[test] 67 | fn single_vertex() { 68 | let mut graph: Graph = BTreeMap::new(); 69 | graph.insert(0, BTreeMap::new()); 70 | 71 | let mut dists = BTreeMap::new(); 72 | dists.insert(0, None); 73 | 74 | assert_eq!(dijkstra(&graph, &0), dists); 75 | } 76 | 77 | #[test] 78 | fn single_edge() { 79 | let mut graph = BTreeMap::new(); 80 | add_edge(&mut graph, 0, 1, 2); 81 | 82 | let mut dists_0 = BTreeMap::new(); 83 | dists_0.insert(0, None); 84 | dists_0.insert(1, Some((0, 2))); 85 | 86 | assert_eq!(dijkstra(&graph, &0), dists_0); 87 | 88 | let mut dists_1 = BTreeMap::new(); 89 | dists_1.insert(1, None); 90 | 91 | assert_eq!(dijkstra(&graph, &1), dists_1); 92 | } 93 | 94 | #[test] 95 | fn tree_1() { 96 | let mut graph = BTreeMap::new(); 97 | let mut dists = BTreeMap::new(); 98 | dists.insert(1, None); 99 | for i in 1..100 { 100 | add_edge(&mut graph, i, i * 2, i * 2); 101 | add_edge(&mut graph, i, i * 2 + 1, i * 2 + 1); 102 | 103 | match dists[&i] { 104 | Some((_, d)) => { 105 | dists.insert(i * 2, Some((i, d + i * 2))); 106 | dists.insert(i * 2 + 1, Some((i, d + i * 2 + 1))); 107 | } 108 | None => { 109 | dists.insert(i * 2, Some((i, i * 2))); 110 | dists.insert(i * 2 + 1, Some((i, i * 2 + 1))); 111 | } 112 | } 113 | } 114 | 115 | assert_eq!(dijkstra(&graph, &1), dists); 116 | } 117 | 118 | #[test] 119 | fn graph_1() { 120 | let mut graph = BTreeMap::new(); 121 | add_edge(&mut graph, 'a', 'c', 12); 122 | add_edge(&mut graph, 'a', 'd', 60); 123 | add_edge(&mut graph, 'b', 'a', 10); 124 | add_edge(&mut graph, 'c', 'b', 20); 125 | add_edge(&mut graph, 'c', 'd', 32); 126 | add_edge(&mut graph, 'e', 'a', 7); 127 | 128 | let mut dists_a = BTreeMap::new(); 129 | dists_a.insert('a', None); 130 | dists_a.insert('c', Some(('a', 12))); 131 | dists_a.insert('d', Some(('c', 44))); 132 | dists_a.insert('b', Some(('c', 32))); 133 | assert_eq!(dijkstra(&graph, &'a'), dists_a); 134 | 135 | let mut dists_b = BTreeMap::new(); 136 | dists_b.insert('b', None); 137 | dists_b.insert('a', Some(('b', 10))); 138 | dists_b.insert('c', Some(('a', 22))); 139 | dists_b.insert('d', Some(('c', 54))); 140 | assert_eq!(dijkstra(&graph, &'b'), dists_b); 141 | 142 | let mut dists_c = BTreeMap::new(); 143 | dists_c.insert('c', None); 144 | dists_c.insert('b', Some(('c', 20))); 145 | dists_c.insert('d', Some(('c', 32))); 146 | dists_c.insert('a', Some(('b', 30))); 147 | assert_eq!(dijkstra(&graph, &'c'), dists_c); 148 | 149 | let mut dists_d = BTreeMap::new(); 150 | dists_d.insert('d', None); 151 | assert_eq!(dijkstra(&graph, &'d'), dists_d); 152 | 153 | let mut dists_e = BTreeMap::new(); 154 | dists_e.insert('e', None); 155 | dists_e.insert('a', Some(('e', 7))); 156 | dists_e.insert('c', Some(('a', 19))); 157 | dists_e.insert('d', Some(('c', 51))); 158 | dists_e.insert('b', Some(('c', 39))); 159 | assert_eq!(dijkstra(&graph, &'e'), dists_e); 160 | } 161 | } 162 | ``` -------------------------------------------------------------------------------- /src/graph/index.md: -------------------------------------------------------------------------------- 1 | # 图论 2 | 3 | 图论算法在计算机科学中扮演着很重要的角色,它提供了对很多问题都有效的一种简单而系统的建模方式。很多问题都可以转化为图论问题,然后用图论的基本算法加以解决。 -------------------------------------------------------------------------------- /src/graph/minimum-spanning-tree.md: -------------------------------------------------------------------------------- 1 | # 最小生成树 2 | 3 | ```rust 4 | use std::vec::Vec; 5 | 6 | #[derive(Debug)] 7 | pub struct Edge { 8 | source: i64, 9 | destination: i64, 10 | cost: i64, 11 | } 12 | 13 | impl PartialEq for Edge { 14 | fn eq(&self, other: &Self) -> bool { 15 | self.source == other.source 16 | && self.destination == other.destination 17 | && self.cost == other.cost 18 | } 19 | } 20 | 21 | impl Eq for Edge {} 22 | 23 | impl Edge { 24 | fn new(source: i64, destination: i64, cost: i64) -> Self { 25 | Self { 26 | source, 27 | destination, 28 | cost, 29 | } 30 | } 31 | } 32 | 33 | fn make_sets(number_of_vertices: i64) -> Vec { 34 | let mut parent: Vec = Vec::with_capacity(number_of_vertices as usize); 35 | for i in 0..number_of_vertices { 36 | parent.push(i); 37 | } 38 | parent 39 | } 40 | 41 | fn find(parent: &mut Vec, x: i64) -> i64 { 42 | let idx: usize = x as usize; 43 | if parent[idx] != x { 44 | parent[idx] = find(parent, parent[idx]); 45 | } 46 | parent[idx] 47 | } 48 | 49 | fn merge(parent: &mut Vec, x: i64, y: i64) { 50 | let idx_x: usize = find(parent, x) as usize; 51 | let parent_y: i64 = find(parent, y); 52 | parent[idx_x] = parent_y; 53 | } 54 | 55 | fn is_same_set(parent: &mut Vec, x: i64, y: i64) -> bool { 56 | find(parent, x) == find(parent, y) 57 | } 58 | 59 | pub fn kruskal(mut edges: Vec, number_of_vertices: i64) -> (i64, Vec) { 60 | let mut parent: Vec = make_sets(number_of_vertices); 61 | 62 | edges.sort_unstable_by(|a, b| a.cost.cmp(&b.cost)); 63 | let mut total_cost: i64 = 0; 64 | let mut final_edges: Vec = Vec::new(); 65 | let mut merge_count: i64 = 0; 66 | for edge in edges.iter() { 67 | if merge_count >= number_of_vertices - 1 { 68 | break; 69 | } 70 | 71 | let source: i64 = edge.source; 72 | let destination: i64 = edge.destination; 73 | if !is_same_set(&mut parent, source, destination) { 74 | merge(&mut parent, source, destination); 75 | merge_count += 1; 76 | let cost: i64 = edge.cost; 77 | total_cost += cost; 78 | let final_edge: Edge = Edge::new(source, destination, cost); 79 | final_edges.push(final_edge); 80 | } 81 | } 82 | (total_cost, final_edges) 83 | } 84 | 85 | #[cfg(test)] 86 | mod tests { 87 | use super::*; 88 | 89 | #[test] 90 | fn test_seven_vertices_eleven_edges() { 91 | let mut edges: Vec = Vec::new(); 92 | edges.push(Edge::new(0, 1, 7)); 93 | edges.push(Edge::new(0, 3, 5)); 94 | edges.push(Edge::new(1, 2, 8)); 95 | edges.push(Edge::new(1, 3, 9)); 96 | edges.push(Edge::new(1, 4, 7)); 97 | edges.push(Edge::new(2, 4, 5)); 98 | edges.push(Edge::new(3, 4, 15)); 99 | edges.push(Edge::new(3, 5, 6)); 100 | edges.push(Edge::new(4, 5, 8)); 101 | edges.push(Edge::new(4, 6, 9)); 102 | edges.push(Edge::new(5, 6, 11)); 103 | 104 | let number_of_vertices: i64 = 7; 105 | 106 | let expected_total_cost = 39; 107 | let mut expected_used_edges: Vec = Vec::new(); 108 | expected_used_edges.push(Edge::new(0, 3, 5)); 109 | expected_used_edges.push(Edge::new(2, 4, 5)); 110 | expected_used_edges.push(Edge::new(3, 5, 6)); 111 | expected_used_edges.push(Edge::new(0, 1, 7)); 112 | expected_used_edges.push(Edge::new(1, 4, 7)); 113 | expected_used_edges.push(Edge::new(4, 6, 9)); 114 | 115 | let (actual_total_cost, actual_final_edges) = kruskal(edges, number_of_vertices); 116 | 117 | assert_eq!(actual_total_cost, expected_total_cost); 118 | assert_eq!(actual_final_edges, expected_used_edges); 119 | } 120 | 121 | #[test] 122 | fn test_ten_vertices_twenty_edges() { 123 | let mut edges: Vec = Vec::new(); 124 | edges.push(Edge::new(0, 1, 3)); 125 | edges.push(Edge::new(0, 3, 6)); 126 | edges.push(Edge::new(0, 4, 9)); 127 | edges.push(Edge::new(1, 2, 2)); 128 | edges.push(Edge::new(1, 3, 4)); 129 | edges.push(Edge::new(1, 4, 9)); 130 | edges.push(Edge::new(2, 3, 2)); 131 | edges.push(Edge::new(2, 5, 8)); 132 | edges.push(Edge::new(2, 6, 9)); 133 | edges.push(Edge::new(3, 6, 9)); 134 | edges.push(Edge::new(4, 5, 8)); 135 | edges.push(Edge::new(4, 9, 18)); 136 | edges.push(Edge::new(5, 6, 7)); 137 | edges.push(Edge::new(5, 8, 9)); 138 | edges.push(Edge::new(5, 9, 10)); 139 | edges.push(Edge::new(6, 7, 4)); 140 | edges.push(Edge::new(6, 8, 5)); 141 | edges.push(Edge::new(7, 8, 1)); 142 | edges.push(Edge::new(7, 9, 4)); 143 | edges.push(Edge::new(8, 9, 3)); 144 | 145 | let number_of_vertices: i64 = 10; 146 | 147 | let expected_total_cost = 38; 148 | let mut expected_used_edges = Vec::new(); 149 | expected_used_edges.push(Edge::new(7, 8, 1)); 150 | expected_used_edges.push(Edge::new(1, 2, 2)); 151 | expected_used_edges.push(Edge::new(2, 3, 2)); 152 | expected_used_edges.push(Edge::new(0, 1, 3)); 153 | expected_used_edges.push(Edge::new(8, 9, 3)); 154 | expected_used_edges.push(Edge::new(6, 7, 4)); 155 | expected_used_edges.push(Edge::new(5, 6, 7)); 156 | expected_used_edges.push(Edge::new(2, 5, 8)); 157 | expected_used_edges.push(Edge::new(4, 5, 8)); 158 | 159 | let (actual_total_cost, actual_final_edges) = kruskal(edges, number_of_vertices); 160 | 161 | assert_eq!(actual_total_cost, expected_total_cost); 162 | assert_eq!(actual_final_edges, expected_used_edges); 163 | } 164 | } 165 | ``` -------------------------------------------------------------------------------- /src/leetcode/001-two-sum.md: -------------------------------------------------------------------------------- 1 | # 1. 两数之和 2 | 题目链接: [两数之和](https://leetcode-cn.com/problems/two-sum/) 3 | 4 | 相信每个刷过LeetCode的人永远也忘不了这道题(就像当年背单词书永远也忘不了书中的第一个单词abandon哈哈哈),但是这道题用Rust来写也并不是那么简单,尤其是对于Rust新手,相信看完这道题你对Rust中的一些小细节会有更深的理解。 5 | 6 | 7 | ## 解法一 8 | 简单粗暴,双重循环,遍历所有的二元组直到找到符合题目要求的结果。 9 | 10 | ```rust 11 | impl Solution { 12 | pub fn two_sum(nums: Vec, target: i32) -> Vec { 13 | for i in 0..nums.len() { 14 | for j in (i + 1)..nums.len() { 15 | if nums[i] + nums[j] == target { 16 | // 注意Rust中下标索引类型为usize,因此这里我们需要将i, j转换为i32 17 | return vec![i as i32, j as i32]; 18 | } 19 | } 20 | } 21 | vec![] 22 | } 23 | } 24 | ``` 25 | 26 | ## 解法二 27 | 我们观察解法一中第二个for循环: 28 | 29 | ```rust 30 | for j in (i + 1)..nums.len() { 31 | if nums[i] + nums[j] == target { 32 | ... 33 | } 34 | } 35 | ``` 36 | 37 | 我们换种方式思考: 38 | 39 | ```rust 40 | for j in (i + 1)..nums.len() { 41 | let other = target - nums[i]; 42 | if nums[j] == other { 43 | ... 44 | } 45 | } 46 | ``` 47 | 48 | 因此我们的目标就变成了在一个数组中寻找值,这可是HashSet/HashMap的强项啊!由于这里我们还需要获取到对应值在数组中的下标索引位置,因此这里只能用HashMap了。 49 | 50 | ```rust 51 | use std::collections::HashMap; 52 | 53 | impl Solution { 54 | pub fn two_sum(nums: Vec, target: i32) -> Vec { 55 | let mut map = HashMap::new(); 56 | for (index, value) in nums.iter().enumerate() { 57 | let other = target - value; 58 | if let Some(&other_index) = map.get(&other) { 59 | return vec![other_index as i32, index as i32]; 60 | } 61 | map.insert(value, index); 62 | } 63 | vec![] 64 | } 65 | } 66 | ``` 67 | 68 | 如果你是个Rust新手的话,相信你可能会存在以下几点疑惑: 69 | 70 | - 为什么需要`use std::collections::HashMap;`这一行:可能是觉得HashMap用的没有那么多吧,因此Rust并没有将HashMap列入Prelude行列当中,因此当我们需要使用HashMap时,需要手动引入。 71 | - 前面的`for i in 0..nums.len()`哪去了,这个`for (index, value) in nums.iter().enumerate()`是个什么鬼:在Rust中推荐使用迭代器,而enumerate这个迭代器适配器返回含有(下标,值)的元组。 72 | - 为什么`if let Some(&other_index) = map.get(&other)`需要用到两个引用符号:简单来说,因为所有权的问题。[HashMap的get方法](https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.get)中传入的参数是对key的引用,返回的是Option<&value>,因此我们需要用这两个引用符号。 73 | -------------------------------------------------------------------------------- /src/leetcode/index.md: -------------------------------------------------------------------------------- 1 | # LeetCode题解 2 | 目前网上用Rust刷LeetCode的题解相对较少且很少有详细解释,为此在这本算法书里我们希望能够打破这一僵局,写出一份让每个人都能看懂的LeetCode题解。暂定计划按题号顺序来,每日一题,尽可能做到每一题都附带详细过程,如有不足之处,也欢迎大家指出和提出PR。 -------------------------------------------------------------------------------- /src/math/extended-euclidean.md: -------------------------------------------------------------------------------- 1 | # 扩展欧几里得算法 2 | 3 | ```rust 4 | fn update_step(a: &mut i32, old_a: &mut i32, quotient: i32) { 5 | let temp = *a; 6 | *a = *old_a - quotient * temp; 7 | *old_a = temp; 8 | } 9 | 10 | pub fn extended_euclidean_algorithm(a: i32, b: i32) -> (i32, i32, i32) { 11 | let (mut old_r, mut rem) = (a, b); 12 | let (mut old_s, mut coeff_s) = (1, 0); 13 | let (mut old_t, mut coeff_t) = (0, 1); 14 | 15 | while rem != 0 { 16 | let quotient = old_r / rem; 17 | 18 | update_step(&mut rem, &mut old_r, quotient); 19 | update_step(&mut coeff_s, &mut old_s, quotient); 20 | update_step(&mut coeff_t, &mut old_t, quotient); 21 | } 22 | 23 | (old_r, old_s, old_t) 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use super::*; 29 | 30 | #[test] 31 | fn basic() { 32 | assert_eq!(extended_euclidean_algorithm(101, 13), (1, 4, -31)); 33 | assert_eq!(extended_euclidean_algorithm(123, 19), (1, -2, 13)); 34 | assert_eq!(extended_euclidean_algorithm(25, 36), (1, 13, -9)); 35 | assert_eq!(extended_euclidean_algorithm(69, 54), (3, -7, 9)); 36 | assert_eq!(extended_euclidean_algorithm(55, 79), (1, 23, -16)); 37 | assert_eq!(extended_euclidean_algorithm(33, 44), (11, -1, 1)); 38 | assert_eq!(extended_euclidean_algorithm(50, 70), (10, 3, -2)); 39 | } 40 | } 41 | ``` -------------------------------------------------------------------------------- /src/math/greatest-common-divisor.md: -------------------------------------------------------------------------------- 1 | # 最大公约数 2 | 3 | ```rust 4 | /// Greatest Common Divisor. 5 | /// 6 | /// greatest_common_divisor(num1, num2) returns the greatest number of num1 and num2. 7 | /// 8 | /// Wikipedia reference: https://en.wikipedia.org/wiki/Greatest_common_divisor 9 | /// gcd(a, b) = gcd(a, -b) = gcd(-a, b) = gcd(-a, -b) by definition of divisibility 10 | 11 | pub fn greatest_common_divisor_recursive(a: i64, b: i64) -> i64 { 12 | if a == 0 { 13 | b.abs() 14 | } else { 15 | greatest_common_divisor_recursive(b % a, a) 16 | } 17 | } 18 | 19 | pub fn greatest_common_divisor_iterative(mut a: i64, mut b: i64) -> i64 { 20 | while a != 0 { 21 | let remainder = b % a; 22 | b = a; 23 | a = remainder; 24 | } 25 | b.abs() 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::*; 31 | 32 | #[test] 33 | fn positive_number_recursive() { 34 | assert_eq!(greatest_common_divisor_recursive(4, 16), 4); 35 | assert_eq!(greatest_common_divisor_recursive(16, 4), 4); 36 | assert_eq!(greatest_common_divisor_recursive(3, 5), 1); 37 | assert_eq!(greatest_common_divisor_recursive(40, 40), 40); 38 | assert_eq!(greatest_common_divisor_recursive(27, 12), 3); 39 | } 40 | 41 | #[test] 42 | fn positive_number_iterative() { 43 | assert_eq!(greatest_common_divisor_iterative(4, 16), 4); 44 | assert_eq!(greatest_common_divisor_iterative(16, 4), 4); 45 | assert_eq!(greatest_common_divisor_iterative(3, 5), 1); 46 | assert_eq!(greatest_common_divisor_iterative(40, 40), 40); 47 | assert_eq!(greatest_common_divisor_iterative(27, 12), 3); 48 | } 49 | 50 | #[test] 51 | fn negative_number_recursive() { 52 | assert_eq!(greatest_common_divisor_recursive(-32, -8), 8); 53 | assert_eq!(greatest_common_divisor_recursive(-8, -32), 8); 54 | assert_eq!(greatest_common_divisor_recursive(-3, -5), 1); 55 | assert_eq!(greatest_common_divisor_recursive(-40, -40), 40); 56 | assert_eq!(greatest_common_divisor_recursive(-12, -27), 3); 57 | } 58 | 59 | #[test] 60 | fn negative_number_iterative() { 61 | assert_eq!(greatest_common_divisor_iterative(-32, -8), 8); 62 | assert_eq!(greatest_common_divisor_iterative(-8, -32), 8); 63 | assert_eq!(greatest_common_divisor_iterative(-3, -5), 1); 64 | assert_eq!(greatest_common_divisor_iterative(-40, -40), 40); 65 | assert_eq!(greatest_common_divisor_iterative(-12, -27), 3); 66 | } 67 | 68 | #[test] 69 | fn mix_recursive() { 70 | assert_eq!(greatest_common_divisor_recursive(0, -5), 5); 71 | assert_eq!(greatest_common_divisor_recursive(-5, 0), 5); 72 | assert_eq!(greatest_common_divisor_recursive(-64, 32), 32); 73 | assert_eq!(greatest_common_divisor_recursive(-32, 64), 32); 74 | assert_eq!(greatest_common_divisor_recursive(-40, 40), 40); 75 | assert_eq!(greatest_common_divisor_recursive(12, -27), 3); 76 | } 77 | 78 | #[test] 79 | fn mix_iterative() { 80 | assert_eq!(greatest_common_divisor_iterative(0, -5), 5); 81 | assert_eq!(greatest_common_divisor_iterative(-5, 0), 5); 82 | assert_eq!(greatest_common_divisor_iterative(-64, 32), 32); 83 | assert_eq!(greatest_common_divisor_iterative(-32, 64), 32); 84 | assert_eq!(greatest_common_divisor_iterative(-40, 40), 40); 85 | assert_eq!(greatest_common_divisor_iterative(12, -27), 3); 86 | } 87 | } 88 | ``` -------------------------------------------------------------------------------- /src/math/index.md: -------------------------------------------------------------------------------- 1 | # 数学 2 | 3 | -------------------------------------------------------------------------------- /src/math/pascal-triange.md: -------------------------------------------------------------------------------- 1 | # 帕斯卡三角 2 | 3 | ```rust 4 | /// ## Paslcal's triangle problem 5 | 6 | /// pascal_triangle(num_rows) returns the first num_rows of Pascal's triangle. 7 | /// About Pascal's triangle: https://en.wikipedia.org/wiki/Pascal%27s_triangle 8 | /// 9 | /// Arguments: 10 | /// * `num_rows` - number of rows of triangle 11 | /// Complexity 12 | /// - time complexity: O(n^2), 13 | /// - space complexity: O(n^2), 14 | pub fn pascal_triangle(num_rows: i32) -> Vec> { 15 | let mut ans: Vec> = vec![]; 16 | 17 | for i in 1..num_rows + 1 { 18 | let mut vec: Vec = vec![1]; 19 | 20 | let mut res: i32 = 1; 21 | for k in 1..i { 22 | res *= i - k; 23 | res /= k; 24 | vec.push(res); 25 | } 26 | ans.push(vec); 27 | } 28 | 29 | ans 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use super::pascal_triangle; 35 | 36 | #[test] 37 | fn test() { 38 | assert_eq!(pascal_triangle(3), vec![vec![1], vec![1, 1], vec![1, 2, 1]]); 39 | assert_eq!( 40 | pascal_triangle(4), 41 | vec![vec![1], vec![1, 1], vec![1, 2, 1], vec![1, 3, 3, 1]] 42 | ); 43 | assert_eq!( 44 | pascal_triangle(5), 45 | vec![ 46 | vec![1], 47 | vec![1, 1], 48 | vec![1, 2, 1], 49 | vec![1, 3, 3, 1], 50 | vec![1, 4, 6, 4, 1] 51 | ] 52 | ); 53 | } 54 | } 55 | ``` -------------------------------------------------------------------------------- /src/math/perfect-numbers.md: -------------------------------------------------------------------------------- 1 | # 寻找完美数 2 | 3 | ```rust 4 | pub fn is_perfect_number(num: usize) -> bool { 5 | let mut sum = 0; 6 | 7 | for i in 1..num - 1 { 8 | if num % i == 0 { 9 | sum += i; 10 | } 11 | } 12 | 13 | num == sum 14 | } 15 | 16 | pub fn perfect_numbers(max: usize) -> Vec { 17 | let mut result: Vec = Vec::new(); 18 | 19 | // It is not known if there are any odd perfect numbers, so we go around all the numbers. 20 | for i in 1..max + 1 { 21 | if is_perfect_number(i) { 22 | result.push(i); 23 | } 24 | } 25 | 26 | result 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | 33 | #[test] 34 | fn basic() { 35 | assert_eq!(is_perfect_number(6), true); 36 | assert_eq!(is_perfect_number(28), true); 37 | assert_eq!(is_perfect_number(496), true); 38 | assert_eq!(is_perfect_number(8128), true); 39 | 40 | assert_eq!(is_perfect_number(5), false); 41 | assert_eq!(is_perfect_number(86), false); 42 | assert_eq!(is_perfect_number(497), false); 43 | assert_eq!(is_perfect_number(8120), false); 44 | 45 | assert_eq!(perfect_numbers(10), vec![6]); 46 | assert_eq!(perfect_numbers(100), vec![6, 28]); 47 | assert_eq!(perfect_numbers(496), vec![6, 28, 496]); 48 | assert_eq!(perfect_numbers(1000), vec![6, 28, 496]); 49 | } 50 | } 51 | ``` -------------------------------------------------------------------------------- /src/math/prime-check.md: -------------------------------------------------------------------------------- 1 | # 质数检测 2 | 3 | ```rust 4 | pub fn prime_check(num: usize) -> bool { 5 | if (num > 1) & (num < 4) { 6 | return true; 7 | } else if (num < 2) || (num % 2 == 0) { 8 | return false; 9 | } 10 | 11 | let stop: usize = (num as f64).sqrt() as usize + 1; 12 | for i in (3..stop).step_by(2) { 13 | if num % i == 0 { 14 | return false; 15 | } 16 | } 17 | true 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | 24 | #[test] 25 | fn basic() { 26 | assert_eq!(prime_check(3), true); 27 | assert_eq!(prime_check(7), true); 28 | assert_eq!(prime_check(11), true); 29 | assert_eq!(prime_check(2003), true); 30 | 31 | assert_eq!(prime_check(4), false); 32 | assert_eq!(prime_check(6), false); 33 | assert_eq!(prime_check(21), false); 34 | assert_eq!(prime_check(2004), false); 35 | } 36 | } 37 | ``` -------------------------------------------------------------------------------- /src/math/prime-numbers.md: -------------------------------------------------------------------------------- 1 | # 质数筛法 2 | 3 | ```rust 4 | pub fn prime_numbers(max: usize) -> Vec { 5 | let mut result: Vec = Vec::new(); 6 | 7 | if max >= 2 { 8 | result.push(2) 9 | } 10 | for i in (3..max + 1).step_by(2) { 11 | let stop: usize = (i as f64).sqrt() as usize + 1; 12 | let mut status: bool = true; 13 | 14 | for j in (3..stop).step_by(2) { 15 | if i % j == 0 { 16 | status = false 17 | } 18 | } 19 | if status { 20 | result.push(i) 21 | } 22 | } 23 | 24 | result 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::*; 30 | 31 | #[test] 32 | fn basic() { 33 | assert_eq!(prime_numbers(0), vec![]); 34 | assert_eq!(prime_numbers(11), vec![2, 3, 5, 7, 11]); 35 | assert_eq!(prime_numbers(25), vec![2, 3, 5, 7, 11, 13, 17, 19, 23]); 36 | assert_eq!( 37 | prime_numbers(33), 38 | vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31] 39 | ); 40 | } 41 | } 42 | ``` -------------------------------------------------------------------------------- /src/math/trial-division.md: -------------------------------------------------------------------------------- 1 | # 试除法 2 | 3 | ```rust 4 | fn floor(value: f64, scale: u8) -> f64 { 5 | let multiplier = 10i64.pow(scale as u32) as f64; 6 | (value * multiplier).floor() 7 | } 8 | 9 | fn double_to_int(amount: f64) -> i128 { 10 | amount.round() as i128 11 | } 12 | 13 | pub fn trial_division(mut num: i128) -> Vec { 14 | let mut result: Vec = vec![]; 15 | 16 | while num % 2 == 0 { 17 | result.push(2); 18 | num /= 2; 19 | num = double_to_int(floor(num as f64, 0)) 20 | } 21 | let mut f: i128 = 3; 22 | 23 | while f.pow(2) <= num { 24 | if num % f == 0 { 25 | result.push(f); 26 | num /= f; 27 | num = double_to_int(floor(num as f64, 0)) 28 | } else { 29 | f += 2 30 | } 31 | } 32 | 33 | if num != 1 { 34 | result.push(num) 35 | } 36 | result 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use super::*; 42 | 43 | #[test] 44 | fn basic() { 45 | assert_eq!(trial_division(9), vec!(3, 3)); 46 | assert_eq!(trial_division(10), vec!(2, 5)); 47 | assert_eq!(trial_division(11), vec!(11)); 48 | assert_eq!(trial_division(33), vec!(3, 11)); 49 | assert_eq!(trial_division(2003), vec!(2003)); 50 | assert_eq!(trial_division(100001), vec!(11, 9091)); 51 | } 52 | } 53 | ``` -------------------------------------------------------------------------------- /src/searching/binary-search-recursive.md: -------------------------------------------------------------------------------- 1 | # 递归二分查找 2 | 3 | ```rust 4 | use std::cmp::Ordering; 5 | 6 | pub fn binary_search_rec( 7 | list_of_items: &[T], 8 | target: &T, 9 | left: &usize, 10 | right: &usize, 11 | ) -> Option { 12 | if left >= right { 13 | return None; 14 | } 15 | 16 | let middle: usize = left + (right - left) / 2; 17 | match target.cmp(&list_of_items[middle]) { 18 | Ordering::Less => binary_search_rec(list_of_items, target, left, &middle), 19 | Ordering::Greater => binary_search_rec(list_of_items, target, &(middle + 1), right), 20 | Ordering::Equal => Some(middle), 21 | } 22 | } 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | use super::*; 27 | 28 | const LEFT: usize = 0; 29 | 30 | #[test] 31 | fn fail_empty_list() { 32 | let list_of_items = vec![]; 33 | assert_eq!( 34 | binary_search_rec(&list_of_items, &1, &LEFT, &list_of_items.len()), 35 | None 36 | ); 37 | } 38 | 39 | #[test] 40 | fn success_one_item() { 41 | let list_of_items = vec![30]; 42 | assert_eq!( 43 | binary_search_rec(&list_of_items, &30, &LEFT, &list_of_items.len()), 44 | Some(0) 45 | ); 46 | } 47 | 48 | #[test] 49 | fn success_search_strings() { 50 | let say_hello_list = vec!["hi", "olá", "salut"]; 51 | let right = say_hello_list.len(); 52 | assert_eq!( 53 | binary_search_rec(&say_hello_list, &"hi", &LEFT, &right), 54 | Some(0) 55 | ); 56 | assert_eq!( 57 | binary_search_rec(&say_hello_list, &"salut", &LEFT, &right), 58 | Some(2) 59 | ); 60 | } 61 | 62 | #[test] 63 | fn fail_search_strings() { 64 | let say_hello_list = vec!["hi", "olá", "salut"]; 65 | for target in &["adiós", "你好"] { 66 | assert_eq!( 67 | binary_search_rec(&say_hello_list, target, &LEFT, &say_hello_list.len()), 68 | None 69 | ); 70 | } 71 | } 72 | 73 | #[test] 74 | fn success_search_integers() { 75 | let integers = vec![0, 10, 20, 30, 40, 50, 60, 70, 80, 90]; 76 | for (index, target) in integers.iter().enumerate() { 77 | assert_eq!( 78 | binary_search_rec(&integers, target, &LEFT, &integers.len()), 79 | Some(index) 80 | ) 81 | } 82 | } 83 | 84 | #[test] 85 | fn fail_search_integers() { 86 | let integers = vec![0, 10, 20, 30, 40, 50, 60, 70, 80, 90]; 87 | for target in &[100, 444, 336] { 88 | assert_eq!( 89 | binary_search_rec(&integers, target, &LEFT, &integers.len()), 90 | None 91 | ); 92 | } 93 | } 94 | 95 | #[test] 96 | fn fail_search_unsorted_strings_list() { 97 | let unsorted_strings = vec!["salut", "olá", "hi"]; 98 | for target in &["hi", "salut"] { 99 | assert_eq!( 100 | binary_search_rec(&unsorted_strings, target, &LEFT, &unsorted_strings.len()), 101 | None 102 | ); 103 | } 104 | } 105 | 106 | #[test] 107 | fn fail_search_unsorted_integers_list() { 108 | let unsorted_integers = vec![90, 80, 70, 60, 50, 40, 30, 20, 10, 0]; 109 | for target in &[0, 80, 90] { 110 | assert_eq!( 111 | binary_search_rec(&unsorted_integers, target, &LEFT, &unsorted_integers.len()), 112 | None 113 | ); 114 | } 115 | } 116 | 117 | #[test] 118 | fn success_search_string_in_middle_of_unsorted_list() { 119 | let unsorted_strings = vec!["salut", "olá", "hi"]; 120 | assert_eq!( 121 | binary_search_rec(&unsorted_strings, &"olá", &LEFT, &unsorted_strings.len()), 122 | Some(1) 123 | ); 124 | } 125 | 126 | #[test] 127 | fn success_search_integer_in_middle_of_unsorted_list() { 128 | let unsorted_integers = vec![90, 80, 70]; 129 | assert_eq!( 130 | binary_search_rec(&unsorted_integers, &80, &LEFT, &unsorted_integers.len()), 131 | Some(1) 132 | ); 133 | } 134 | } 135 | ``` -------------------------------------------------------------------------------- /src/searching/binary-search.md: -------------------------------------------------------------------------------- 1 | # 二分搜索 2 | 3 | ![alt text][binary-image] 4 | 5 | From [Wikipedia][binary-wiki]: Binary search, also known as half-interval search or logarithmic search, is a search algorithm that finds the position of a target value within a sorted array. It compares the target value to the middle element of the array; if they are unequal, the half in which the target cannot lie is eliminated and the search continues on the remaining half until it is successful. 6 | 7 | __Properties__ 8 | * Worst case performance O(log n) 9 | * Best case performance O(1) 10 | * Average case performance O(log n) 11 | * Worst case space complexity O(1) 12 | 13 | ```rust 14 | use std::cmp::Ordering; 15 | 16 | pub fn binary_search(item: &T, arr: &[T]) -> Option { 17 | let mut left = 0; 18 | let mut right = arr.len(); 19 | 20 | while left < right { 21 | let mid = left + (right - left) / 2; 22 | 23 | match item.cmp(&arr[mid]) { 24 | Ordering::Less => right = mid, 25 | Ordering::Equal => return Some(mid), 26 | Ordering::Greater => left = mid + 1, 27 | } 28 | } 29 | None 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use super::*; 35 | 36 | #[test] 37 | fn empty() { 38 | let index = binary_search(&"a", &vec![]); 39 | assert_eq!(index, None); 40 | } 41 | 42 | #[test] 43 | fn one_item() { 44 | let index = binary_search(&"a", &vec!["a"]); 45 | assert_eq!(index, Some(0)); 46 | } 47 | 48 | #[test] 49 | fn search_strings() { 50 | let index = binary_search(&"a", &vec!["a", "b", "c", "d", "google", "zoo"]); 51 | assert_eq!(index, Some(0)); 52 | } 53 | 54 | #[test] 55 | fn search_ints() { 56 | let index = binary_search(&4, &vec![1, 2, 3, 4]); 57 | assert_eq!(index, Some(3)); 58 | 59 | let index = binary_search(&3, &vec![1, 2, 3, 4]); 60 | assert_eq!(index, Some(2)); 61 | 62 | let index = binary_search(&2, &vec![1, 2, 3, 4]); 63 | assert_eq!(index, Some(1)); 64 | 65 | let index = binary_search(&1, &vec![1, 2, 3, 4]); 66 | assert_eq!(index, Some(0)); 67 | } 68 | 69 | #[test] 70 | fn not_found() { 71 | let index = binary_search(&5, &vec![1, 2, 3, 4]); 72 | assert_eq!(index, None); 73 | } 74 | } 75 | ``` 76 | 77 | [binary-wiki]: https://en.wikipedia.org/wiki/Binary_search_algorithm 78 | [binary-image]: https://upload.wikimedia.org/wikipedia/commons/f/f7/Binary_search_into_array.png -------------------------------------------------------------------------------- /src/searching/index.md: -------------------------------------------------------------------------------- 1 | # 查找算法 2 | 3 | 查找是在大量的信息中寻找一个特定的信息元素,在计算机应用中,查找是常用的基本运算,例如编译程序中符号表的查找。 4 | 5 | 把数据按照合适的方式进行排列,往往是查找的关键。 -------------------------------------------------------------------------------- /src/searching/kth-smallest.md: -------------------------------------------------------------------------------- 1 | # 查找第K小的元素 2 | 3 | ```rust 4 | use crate::sorting::partition; 5 | use std::cmp::{Ordering, PartialOrd}; 6 | 7 | /// Returns k-th smallest element of an array, i.e. its order statistics. 8 | /// Time complexity is O(n^2) in the worst case, but only O(n) on average. 9 | /// It mutates the input, and therefore does not require additional space. 10 | pub fn kth_smallest(input: &mut [T], k: usize) -> Option 11 | where 12 | T: PartialOrd + Copy, 13 | { 14 | if input.is_empty() { 15 | return None; 16 | } 17 | 18 | let kth = _kth_smallest(input, k, 0, input.len() - 1); 19 | Some(kth) 20 | } 21 | 22 | fn _kth_smallest(input: &mut [T], k: usize, lo: usize, hi: usize) -> T 23 | where 24 | T: PartialOrd + Copy, 25 | { 26 | if lo == hi { 27 | return input[lo]; 28 | } 29 | 30 | let pivot = partition(input, lo as isize, hi as isize) as usize; 31 | let i = pivot - lo + 1; 32 | 33 | match k.cmp(&i) { 34 | Ordering::Equal => input[pivot], 35 | Ordering::Less => _kth_smallest(input, k, lo, pivot - 1), 36 | Ordering::Greater => _kth_smallest(input, k - i, pivot + 1, hi), 37 | } 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use super::*; 43 | 44 | #[test] 45 | fn empty() { 46 | let mut zero: [u8; 0] = []; 47 | let first = kth_smallest(&mut zero, 1); 48 | 49 | assert_eq!(None, first); 50 | } 51 | 52 | #[test] 53 | fn one_element() { 54 | let mut one = [1]; 55 | let first = kth_smallest(&mut one, 1); 56 | 57 | assert_eq!(1, first.unwrap()); 58 | } 59 | 60 | #[test] 61 | fn many_elements() { 62 | // 0 1 3 4 5 7 8 9 9 10 12 13 16 17 63 | let mut many = [9, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0]; 64 | 65 | let first = kth_smallest(&mut many, 1); 66 | let third = kth_smallest(&mut many, 3); 67 | let sixth = kth_smallest(&mut many, 6); 68 | let fourteenth = kth_smallest(&mut many, 14); 69 | 70 | assert_eq!(0, first.unwrap()); 71 | assert_eq!(3, third.unwrap()); 72 | assert_eq!(7, sixth.unwrap()); 73 | assert_eq!(17, fourteenth.unwrap()); 74 | } 75 | } 76 | ``` -------------------------------------------------------------------------------- /src/searching/linear-search.md: -------------------------------------------------------------------------------- 1 | # 线性搜索 2 | 3 | ![alt text][linear-image] 4 | 5 | From [Wikipedia][linear-wiki]: linear search or sequential search is a method for finding a target value within a list. It sequentially checks each element of the list for the target value until a match is found or until all the elements have been searched. 6 | Linear search runs in at worst linear time and makes at most n comparisons, where n is the length of the list. 7 | 8 | __Properties__ 9 | * Worst case performance O(n) 10 | * Best case performance O(1) 11 | * Average case performance O(n) 12 | * Worst case space complexity O(1) iterative 13 | 14 | ```rust 15 | use std::cmp::PartialEq; 16 | 17 | pub fn linear_search(item: &T, arr: &[T]) -> Option { 18 | for (i, data) in arr.iter().enumerate() { 19 | if item == data { 20 | return Some(i); 21 | } 22 | } 23 | 24 | None 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::*; 30 | 31 | #[test] 32 | fn search_strings() { 33 | let index = linear_search(&"a", &vec!["a", "b", "c", "d", "google", "zoo"]); 34 | assert_eq!(index, Some(0)); 35 | } 36 | 37 | #[test] 38 | fn search_ints() { 39 | let index = linear_search(&4, &vec![1, 2, 3, 4]); 40 | assert_eq!(index, Some(3)); 41 | 42 | let index = linear_search(&3, &vec![1, 2, 3, 4]); 43 | assert_eq!(index, Some(2)); 44 | 45 | let index = linear_search(&2, &vec![1, 2, 3, 4]); 46 | assert_eq!(index, Some(1)); 47 | 48 | let index = linear_search(&1, &vec![1, 2, 3, 4]); 49 | assert_eq!(index, Some(0)); 50 | } 51 | 52 | #[test] 53 | fn not_found() { 54 | let index = linear_search(&5, &vec![1, 2, 3, 4]); 55 | assert_eq!(index, None); 56 | } 57 | 58 | #[test] 59 | fn empty() { 60 | let index = linear_search(&1, &vec![]); 61 | assert_eq!(index, None); 62 | } 63 | } 64 | ``` 65 | 66 | 67 | [linear-wiki]: https://en.wikipedia.org/wiki/Linear_search 68 | [linear-image]: http://www.tutorialspoint.com/data_structures_algorithms/images/linear_search.gif -------------------------------------------------------------------------------- /src/sorting/bubble-sort.md: -------------------------------------------------------------------------------- 1 | # 冒泡排序 2 | 3 | ```rust 4 | pub fn bubble_sort(arr: &mut [T]) { 5 | if arr.len() <= 1 { 6 | return; 7 | } 8 | 9 | let size = arr.len(); 10 | for i in 0..(size - 1) { 11 | // 标记当前循环是否发生元素交换 12 | let mut swapped = false; 13 | 14 | // 最后i个元素已经排好了顺序 15 | for j in 1..(size - i) { 16 | if arr[j - 1] > arr[j] { 17 | arr.swap(j - 1, j); 18 | swapped = true; 19 | } 20 | } 21 | 22 | // 如果当前循环没有发生元素交换,说明数组已经有序 23 | if !swapped { 24 | break; 25 | } 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | 33 | #[test] 34 | fn test_empty_vec() { 35 | let mut empty_vec: Vec = vec![]; 36 | bubble_sort(&mut empty_vec); 37 | assert_eq!(empty_vec, Vec::::new()); 38 | } 39 | 40 | #[test] 41 | fn test_number_vec() { 42 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 43 | bubble_sort(&mut vec); 44 | assert_eq!(vec, vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78]); 45 | } 46 | 47 | #[test] 48 | fn test_string_vec() { 49 | let mut vec = vec![ 50 | String::from("Bob"), 51 | String::from("David"), 52 | String::from("Carol"), 53 | String::from("Alice"), 54 | ]; 55 | bubble_sort(&mut vec); 56 | assert_eq!( 57 | vec, 58 | vec![ 59 | String::from("Alice"), 60 | String::from("Bob"), 61 | String::from("Carol"), 62 | String::from("David"), 63 | ] 64 | ); 65 | } 66 | } 67 | ``` -------------------------------------------------------------------------------- /src/sorting/bucket-sort.md: -------------------------------------------------------------------------------- 1 | # 桶排序 2 | 3 | ```rust 4 | /// Sort a slice using bucket sort algorithm. 5 | /// 6 | /// Time complexity is `O(n + k)` on average, where `n` is the number of elements, 7 | /// `k` is the number of buckets used in process. 8 | /// 9 | /// Space complexity is `O(n + k)`, as it sorts not in-place. 10 | pub fn bucket_sort(arr: &[usize]) -> Vec { 11 | if arr.is_empty() { 12 | return vec![]; 13 | } 14 | 15 | let max = *arr.iter().max().unwrap(); 16 | let len = arr.len(); 17 | let mut buckets = vec![vec![]; len + 1]; 18 | 19 | for x in arr { 20 | buckets[len * *x / max].push(*x); 21 | } 22 | 23 | for bucket in buckets.iter_mut() { 24 | super::insertion_sort(bucket); 25 | } 26 | 27 | let mut result = vec![]; 28 | for bucket in buckets { 29 | for x in bucket { 30 | result.push(x); 31 | } 32 | } 33 | 34 | result 35 | } 36 | 37 | #[cfg(test)] 38 | mod tests { 39 | use super::super::is_sorted; 40 | use super::*; 41 | 42 | #[test] 43 | fn empty() { 44 | let arr: [usize; 0] = []; 45 | let res = bucket_sort(&arr); 46 | assert!(is_sorted(&res)); 47 | } 48 | 49 | #[test] 50 | fn one_element() { 51 | let arr: [usize; 1] = [4]; 52 | let res = bucket_sort(&arr); 53 | assert!(is_sorted(&res)); 54 | } 55 | 56 | #[test] 57 | fn already_sorted() { 58 | let arr: [usize; 3] = [10, 9, 105]; 59 | let res = bucket_sort(&arr); 60 | assert!(is_sorted(&res)); 61 | } 62 | 63 | #[test] 64 | fn basic() { 65 | let arr: [usize; 4] = [35, 53, 1, 0]; 66 | let res = bucket_sort(&arr); 67 | assert!(is_sorted(&res)); 68 | } 69 | 70 | #[test] 71 | fn odd_number_of_elements() { 72 | let arr: Vec = vec![1, 21, 5, 11, 58]; 73 | let res = bucket_sort(&arr); 74 | assert!(is_sorted(&res)); 75 | } 76 | 77 | #[test] 78 | fn repeated_elements() { 79 | let arr: Vec = vec![542, 542, 542, 542]; 80 | let res = bucket_sort(&arr); 81 | assert!(is_sorted(&res)); 82 | } 83 | } 84 | ``` -------------------------------------------------------------------------------- /src/sorting/cocktail-shaker-sort.md: -------------------------------------------------------------------------------- 1 | # 鸡尾酒排序 2 | 3 | ```rust 4 | pub fn cocktail_shaker_sort(arr: &mut [T]) { 5 | let len = arr.len(); 6 | 7 | if len == 0 { 8 | return; 9 | } 10 | 11 | loop { 12 | let mut swapped = false; 13 | 14 | for i in 0..(len - 1).clamp(0, len) { 15 | if arr[i] > arr[i + 1] { 16 | arr.swap(i, i + 1); 17 | swapped = true; 18 | } 19 | } 20 | 21 | if !swapped { 22 | break; 23 | } 24 | 25 | swapped = false; 26 | 27 | for i in (0..(len - 1).clamp(0, len)).rev() { 28 | if arr[i] > arr[i + 1] { 29 | arr.swap(i, i + 1); 30 | swapped = true; 31 | } 32 | } 33 | 34 | if !swapped { 35 | break; 36 | } 37 | } 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use super::*; 43 | 44 | #[test] 45 | fn basic() { 46 | let mut arr = vec![5, 2, 1, 3, 4, 6]; 47 | cocktail_shaker_sort(&mut arr); 48 | assert_eq!(arr, vec![1, 2, 3, 4, 5, 6]); 49 | } 50 | 51 | #[test] 52 | fn empty() { 53 | let mut arr = Vec::::new(); 54 | cocktail_shaker_sort(&mut arr); 55 | assert_eq!(arr, vec![]); 56 | } 57 | 58 | #[test] 59 | fn one_element() { 60 | let mut arr = vec![1]; 61 | cocktail_shaker_sort(&mut arr); 62 | assert_eq!(arr, vec![1]); 63 | } 64 | 65 | #[test] 66 | fn pre_sorted() { 67 | let mut arr = vec![1, 2, 3, 4, 5, 6]; 68 | cocktail_shaker_sort(&mut arr); 69 | assert_eq!(arr, vec![1, 2, 3, 4, 5, 6]); 70 | } 71 | } 72 | ``` -------------------------------------------------------------------------------- /src/sorting/comb-sort.md: -------------------------------------------------------------------------------- 1 | # 梳排序 2 | 3 | ```rust 4 | pub fn comb_sort(arr: &mut [T]) { 5 | let mut gap = arr.len(); 6 | let shrink = 1.3; 7 | let mut sorted = false; 8 | 9 | while !sorted { 10 | gap = (gap as f32 / shrink).floor() as usize; 11 | if gap <= 1 { 12 | gap = 1; 13 | sorted = true; 14 | } 15 | for i in 0..arr.len() - gap { 16 | let j = i + gap; 17 | if arr[i] > arr[j] { 18 | arr.swap(i, j); 19 | sorted = false; 20 | } 21 | } 22 | } 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use super::*; 28 | 29 | #[test] 30 | fn descending() { 31 | //descending 32 | let mut ve1 = vec![6, 5, 4, 3, 2, 1]; 33 | comb_sort(&mut ve1); 34 | for i in 0..ve1.len() - 1 { 35 | assert!(ve1[i] <= ve1[i + 1]); 36 | } 37 | } 38 | 39 | #[test] 40 | fn ascending() { 41 | //pre-sorted 42 | let mut ve2 = vec![1, 2, 3, 4, 5, 6]; 43 | comb_sort(&mut ve2); 44 | for i in 0..ve2.len() - 1 { 45 | assert!(ve2[i] <= ve2[i + 1]); 46 | } 47 | } 48 | } 49 | ``` -------------------------------------------------------------------------------- /src/sorting/counting-sort.md: -------------------------------------------------------------------------------- 1 | # 计数排序 2 | 3 | ```rust 4 | /// In place counting sort for collections of u32 5 | /// O(n + maxval) in time, where maxval is the biggest value an input can possibly take 6 | /// O(maxval) in memory 7 | /// u32 is chosen arbitrarly, a counting sort probably should'nt be used on data that requires bigger types. 8 | 9 | pub fn counting_sort(arr: &mut [u32], maxval: usize) { 10 | let mut occurences: Vec = vec![0; maxval + 1]; 11 | 12 | for &data in arr.iter() { 13 | occurences[data as usize] += 1; 14 | } 15 | 16 | let mut i = 0; 17 | for (data, &number) in occurences.iter().enumerate() { 18 | for _ in 0..number { 19 | arr[i] = data as u32; 20 | i += 1; 21 | } 22 | } 23 | } 24 | 25 | use std::ops::AddAssign; 26 | /// Generic implementation of a counting sort for all usigned types 27 | pub fn generic_counting_sort + From + AddAssign + Copy>( 28 | arr: &mut [T], 29 | maxval: usize, 30 | ) { 31 | let mut occurences: Vec = vec![0; maxval + 1]; 32 | 33 | for &data in arr.iter() { 34 | occurences[data.into() as usize] += 1; 35 | } 36 | 37 | // Current index in output array 38 | let mut i = 0; 39 | 40 | // current data point, necessary to be type-safe 41 | let mut data = T::from(0); 42 | 43 | // This will iterate from 0 to the largest data point in `arr` 44 | // `number` contains the occurances of the data point `data` 45 | for &number in occurences.iter() { 46 | for _ in 0..number { 47 | arr[i] = data; 48 | i += 1; 49 | } 50 | 51 | data += T::from(1); 52 | } 53 | } 54 | 55 | #[cfg(test)] 56 | mod test { 57 | use super::super::is_sorted; 58 | use super::*; 59 | 60 | #[test] 61 | fn counting_sort_descending() { 62 | let mut ve1 = vec![6, 5, 4, 3, 2, 1]; 63 | counting_sort(&mut ve1, 6); 64 | 65 | assert!(is_sorted(&ve1)); 66 | } 67 | 68 | #[test] 69 | fn counting_sort_pre_sorted() { 70 | let mut ve2 = vec![1, 2, 3, 4, 5, 6]; 71 | counting_sort(&mut ve2, 6); 72 | 73 | assert!(is_sorted(&ve2)); 74 | } 75 | 76 | #[test] 77 | fn generic_counting_sort() { 78 | let mut ve1: Vec = vec![100, 30, 60, 10, 20, 120, 1]; 79 | super::generic_counting_sort(&mut ve1, 120); 80 | 81 | assert!(is_sorted(&ve1)); 82 | } 83 | 84 | #[test] 85 | fn presorted_u64_counting_sort() { 86 | let mut ve2: Vec = vec![1, 2, 3, 4, 5, 6]; 87 | super::generic_counting_sort(&mut ve2, 6); 88 | 89 | assert!(is_sorted(&ve2)); 90 | } 91 | } 92 | ``` -------------------------------------------------------------------------------- /src/sorting/gnome-sort.md: -------------------------------------------------------------------------------- 1 | # 地精排序 2 | 3 | ```rust 4 | use std::cmp; 5 | 6 | pub fn gnome_sort(arr: &[T]) -> Vec 7 | where 8 | T: cmp::PartialEq + cmp::PartialOrd + Clone, 9 | { 10 | let mut arr = arr.to_vec(); 11 | let mut i: usize = 1; 12 | let mut j: usize = 2; 13 | 14 | while i < arr.len() { 15 | if arr[i - 1] < arr[i] { 16 | i = j; 17 | j = i + 1; 18 | } else { 19 | arr.swap(i - 1, i); 20 | i -= 1; 21 | if i == 0 { 22 | i = j; 23 | j += 1; 24 | } 25 | } 26 | } 27 | arr 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use super::*; 33 | 34 | #[test] 35 | fn basic() { 36 | let res = gnome_sort(&vec![6, 5, -8, 3, 2, 3]); 37 | assert_eq!(res, vec![-8, 2, 3, 3, 5, 6]); 38 | } 39 | 40 | #[test] 41 | fn already_sorted() { 42 | let res = gnome_sort(&vec!["a", "b", "c"]); 43 | assert_eq!(res, vec!["a", "b", "c"]); 44 | } 45 | 46 | #[test] 47 | fn odd_number_of_elements() { 48 | let res = gnome_sort(&vec!["d", "a", "c", "e", "b"]); 49 | assert_eq!(res, vec!["a", "b", "c", "d", "e"]); 50 | } 51 | 52 | #[test] 53 | fn one_element() { 54 | let res = gnome_sort(&vec![3]); 55 | assert_eq!(res, vec![3]); 56 | } 57 | 58 | #[test] 59 | fn empty() { 60 | let res = gnome_sort(&Vec::::new()); 61 | assert_eq!(res, vec![]); 62 | } 63 | } 64 | ``` -------------------------------------------------------------------------------- /src/sorting/heap-sort.md: -------------------------------------------------------------------------------- 1 | # 堆排序 2 | 3 | ```rust 4 | pub fn heap_sort(arr: &mut [T]) { 5 | let size = arr.len(); 6 | // 构建大根堆 7 | for i in (0..size / 2).rev() { 8 | heapify(arr, i, size); 9 | } 10 | 11 | // 每轮循环将堆顶元素(也就是最大元素)放到最后 12 | for i in (1..size).rev() { 13 | arr.swap(0, i); 14 | // 恢复大根堆 15 | heapify(arr, 0, i); 16 | } 17 | } 18 | 19 | fn heapify(arr: &mut [T], root: usize, end: usize) { 20 | // 记录父节点和左右节点中最大元素的索引位置 21 | let mut largest = root; 22 | 23 | let left_child = 2 * root + 1; 24 | if left_child < end && arr[left_child] > arr[largest] { 25 | largest = left_child; 26 | } 27 | 28 | let right_child = left_child + 1; 29 | if right_child < end && arr[right_child] > arr[largest] { 30 | largest = right_child; 31 | } 32 | 33 | if largest != root { 34 | arr.swap(root, largest); 35 | heapify(arr, largest, end); 36 | } 37 | } 38 | 39 | #[cfg(test)] 40 | mod tests { 41 | use super::*; 42 | 43 | #[test] 44 | fn test_empty_vec() { 45 | let mut empty_vec: Vec = vec![]; 46 | heap_sort(&mut empty_vec); 47 | assert_eq!(empty_vec, Vec::::new()); 48 | } 49 | 50 | #[test] 51 | fn test_number_vec() { 52 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 53 | heap_sort(&mut vec); 54 | assert_eq!(vec, vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78]); 55 | } 56 | 57 | #[test] 58 | fn test_string_vec() { 59 | let mut vec = vec![ 60 | String::from("Bob"), 61 | String::from("David"), 62 | String::from("Carol"), 63 | String::from("Alice"), 64 | ]; 65 | heap_sort(&mut vec); 66 | assert_eq!( 67 | vec, 68 | vec![ 69 | String::from("Alice"), 70 | String::from("Bob"), 71 | String::from("Carol"), 72 | String::from("David"), 73 | ] 74 | ); 75 | } 76 | } 77 | ``` -------------------------------------------------------------------------------- /src/sorting/index.md: -------------------------------------------------------------------------------- 1 | # 排序算法 2 | 3 | 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。一个优秀的算法可以节省大量的资源。在各个领域中考虑到数据的各种限制和规范,要得到一个符合实际的优秀算法,得经过大量的推理和分析。 4 | 5 | -------------------------------------------------------------------------------- /src/sorting/insertion-sort.md: -------------------------------------------------------------------------------- 1 | # 插入排序 2 | 3 | ```rust 4 | pub fn insertion_sort(arr: &mut [T]) { 5 | // 从第二个元素开始排序 6 | for i in 1..arr.len() { 7 | // 找到 arr[i] 该插入的位置 8 | let mut j = i; 9 | while j > 0 && arr[j - 1] > arr[j] { 10 | arr.swap(j - 1, j); 11 | j -= 1; 12 | } 13 | } 14 | } 15 | 16 | // 这里需要 T: Ord 是因为 binary_search() 方法的限制 17 | pub fn insertion_sort_binary_search(arr: &mut[T]) { 18 | // 从第二个元素开始排序 19 | for i in 1..arr.len() { 20 | // 利用二分查找获取 arr[i] 应该插入的位置 21 | let pos = arr[..i].binary_search(&arr[i]).unwrap_or_else(|pos| pos); 22 | let mut j = i; 23 | while j > pos { 24 | arr.swap(j - 1, j); 25 | j -= 1; 26 | } 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use super::*; 33 | 34 | mod insertion_sort { 35 | use super::*; 36 | 37 | #[test] 38 | fn test_empty_vec() { 39 | let mut empty_vec: Vec = vec![]; 40 | insertion_sort(&mut empty_vec); 41 | assert_eq!(empty_vec, Vec::::new()); 42 | } 43 | 44 | #[test] 45 | fn test_number_vec() { 46 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 47 | insertion_sort(&mut vec); 48 | assert_eq!(vec, vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78]); 49 | } 50 | 51 | #[test] 52 | fn test_string_vec() { 53 | let mut vec = vec![ 54 | String::from("Bob"), 55 | String::from("David"), 56 | String::from("Carol"), 57 | String::from("Alice"), 58 | ]; 59 | insertion_sort(&mut vec); 60 | assert_eq!( 61 | vec, 62 | vec![ 63 | String::from("Alice"), 64 | String::from("Bob"), 65 | String::from("Carol"), 66 | String::from("David"), 67 | ] 68 | ); 69 | } 70 | } 71 | 72 | mod insertion_sort_binary_search { 73 | use super::*; 74 | 75 | #[test] 76 | fn test_empty_vec() { 77 | let mut empty_vec: Vec = vec![]; 78 | insertion_sort_binary_search(&mut empty_vec); 79 | assert_eq!(empty_vec, Vec::::new()); 80 | } 81 | 82 | #[test] 83 | fn test_number_vec() { 84 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 85 | insertion_sort_binary_search(&mut vec); 86 | assert_eq!(vec, vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78]); 87 | } 88 | 89 | #[test] 90 | fn test_string_vec() { 91 | let mut vec = vec![ 92 | String::from("Bob"), 93 | String::from("David"), 94 | String::from("Carol"), 95 | String::from("Alice"), 96 | ]; 97 | insertion_sort_binary_search(&mut vec); 98 | assert_eq!( 99 | vec, 100 | vec![ 101 | String::from("Alice"), 102 | String::from("Bob"), 103 | String::from("Carol"), 104 | String::from("David"), 105 | ] 106 | ); 107 | } 108 | } 109 | } 110 | ``` -------------------------------------------------------------------------------- /src/sorting/merge-sort.md: -------------------------------------------------------------------------------- 1 | # 归并排序 2 | 3 | ```rust 4 | pub fn merge_sort(arr: &mut [T]) 5 | where 6 | T: PartialOrd + Clone + Default, 7 | { 8 | if arr.len() > 1 { 9 | merge_sort_range(arr, 0, arr.len() - 1); 10 | } 11 | } 12 | 13 | fn merge_sort_range(arr: &mut [T], lo: usize, hi: usize) 14 | where 15 | T: PartialOrd + Clone + Default, 16 | { 17 | // 只有当元素个数大于一时才进行排序 18 | if lo < hi { 19 | let mid = lo + ((hi - lo) >> 1); 20 | merge_sort_range(arr, lo, mid); 21 | merge_sort_range(arr, mid + 1, hi); 22 | merge_two_arrays(arr, lo, mid, hi); 23 | } 24 | } 25 | 26 | // 合并两个有序数组: arr[lo..=mid], arr[mid + 1..=hi] 27 | fn merge_two_arrays(arr: &mut [T], lo: usize, mid: usize, hi: usize) 28 | where 29 | T: PartialOrd + Clone + Default, 30 | { 31 | // 这里需要 clone 数组元素 32 | let mut arr1 = arr[lo..=mid].to_vec(); 33 | let mut arr2 = arr[mid + 1..=hi].to_vec(); 34 | 35 | let (mut i, mut j) = (0, 0); 36 | while i < arr1.len() && j < arr2.len() { 37 | if arr1[i] < arr2[j] { 38 | arr[i + j + lo] = std::mem::take(&mut arr1[i]); 39 | i += 1; 40 | } else { 41 | arr[i + j + lo] = std::mem::take(&mut arr2[j]); 42 | j += 1; 43 | } 44 | } 45 | 46 | while i < arr1.len() { 47 | arr[i + j + lo] = std::mem::take(&mut arr1[i]); 48 | i += 1; 49 | } 50 | 51 | while j < arr2.len() { 52 | arr[i + j + lo] = std::mem::take(&mut arr2[j]); 53 | j += 1; 54 | } 55 | } 56 | 57 | #[cfg(test)] 58 | mod tests { 59 | use super::*; 60 | 61 | #[test] 62 | fn test_empty_vec() { 63 | let mut empty_vec: Vec = vec![]; 64 | merge_sort(&mut empty_vec); 65 | assert_eq!(empty_vec, Vec::::new()); 66 | } 67 | 68 | #[test] 69 | fn test_number_vec() { 70 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 71 | merge_sort(&mut vec); 72 | assert_eq!(vec, vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78]); 73 | } 74 | 75 | #[test] 76 | fn test_string_vec() { 77 | let mut vec = vec![ 78 | String::from("Bob"), 79 | String::from("David"), 80 | String::from("Carol"), 81 | String::from("Alice"), 82 | ]; 83 | merge_sort(&mut vec); 84 | assert_eq!( 85 | vec, 86 | vec![ 87 | String::from("Alice"), 88 | String::from("Bob"), 89 | String::from("Carol"), 90 | String::from("David"), 91 | ] 92 | ); 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /src/sorting/odd-even.md: -------------------------------------------------------------------------------- 1 | # 奇偶排序 2 | 3 | ```rust 4 | pub fn odd_even_sort(arr: &mut [T]) { 5 | let len = arr.len(); 6 | if len == 0 { 7 | return; 8 | } 9 | 10 | let mut sorted = false; 11 | while !sorted { 12 | sorted = true; 13 | 14 | for i in (1..len - 1).step_by(2) { 15 | if arr[i] > arr[i + 1] { 16 | arr.swap(i, i + 1); 17 | sorted = false; 18 | } 19 | } 20 | 21 | for i in (0..len - 1).step_by(2) { 22 | if arr[i] > arr[i + 1] { 23 | arr.swap(i, i + 1); 24 | sorted = false; 25 | } 26 | } 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use super::*; 33 | 34 | #[test] 35 | fn basic() { 36 | let mut arr = vec![3, 5, 1, 2, 4, 6]; 37 | odd_even_sort(&mut arr); 38 | assert_eq!(arr, vec![1, 2, 3, 4, 5, 6]); 39 | } 40 | 41 | #[test] 42 | fn empty() { 43 | let mut arr = Vec::::new(); 44 | odd_even_sort(&mut arr); 45 | assert_eq!(arr, vec![]); 46 | } 47 | 48 | #[test] 49 | fn one_element() { 50 | let mut arr = vec![3]; 51 | odd_even_sort(&mut arr); 52 | assert_eq!(arr, vec![3]); 53 | } 54 | 55 | #[test] 56 | fn pre_sorted() { 57 | let mut arr = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 58 | odd_even_sort(&mut arr); 59 | assert_eq!(arr, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 60 | } 61 | } 62 | ``` -------------------------------------------------------------------------------- /src/sorting/quick-sort.md: -------------------------------------------------------------------------------- 1 | # 快速排序 2 | 3 | ```rust 4 | pub fn quick_sort(arr: &mut [T]) { 5 | if arr.len() > 1 { 6 | quick_sort_range(arr, 0, arr.len() - 1); 7 | } 8 | } 9 | 10 | fn quick_sort_range(arr: &mut [T], lo: usize, hi: usize) { 11 | // 只有当元素个数大于一时才进行排序 12 | if lo < hi { 13 | let pos = partition(arr, lo, hi); 14 | // let pos = partition_random(arr, lo, hi); 15 | if pos != 0 { 16 | // 如果 pos == 0, pos - 1 会发生溢出错误 17 | quick_sort_range(arr, lo, pos - 1); 18 | } 19 | quick_sort_range(arr, pos + 1, hi); 20 | } 21 | } 22 | 23 | fn partition(arr: &mut [T], lo: usize, hi: usize) -> usize { 24 | // 默认选取 lo 作为 pivot 25 | let pivot = lo; 26 | 27 | let (mut left, mut right) = (lo, hi); 28 | while left < right { 29 | // 找到右边第一个不大于等于 arr[pivot] 的元素 30 | while left < right && arr[right] >= arr[pivot] { 31 | right -= 1; 32 | } 33 | 34 | // 找到左边第一个不小于等于 arr[pivot] 的元素 35 | while left < right && arr[left] <= arr[pivot] { 36 | left += 1; 37 | } 38 | 39 | // 交换前面找到的两个元素 40 | if left != right { 41 | arr.swap(left, right); 42 | } 43 | } 44 | 45 | arr.swap(pivot, left); 46 | 47 | // 返回正确的分割位置 48 | left 49 | } 50 | 51 | // 随机选取 pivot 的位置 52 | fn partition_random(arr: &mut [T], lo: usize, hi: usize) -> usize { 53 | // 在 Cargo.toml 的依赖中添加 rand 库 54 | use rand::Rng; 55 | let mut rng = rand::thread_rng(); 56 | let pivot = rng.gen_range(lo..=hi); 57 | 58 | // 交换 lo 和 pivot 位置上的元素,从而间接使得 pivot = lo 59 | // 因此后序操作和 partition() 函数一致 60 | arr.swap(lo, pivot); 61 | 62 | let pivot = lo; 63 | let (mut left, mut right) = (lo, hi); 64 | while left < right { 65 | // 找到右边第一个不大于等于 arr[pivot] 的元素 66 | while left < right && arr[right] >= arr[pivot] { 67 | right -= 1; 68 | } 69 | 70 | // 找到左边第一个不小于等于 arr[pivot] 的元素 71 | while left < right && arr[left] <= arr[pivot] { 72 | left += 1; 73 | } 74 | 75 | // 交换前面找到的两个元素 76 | if left != right { 77 | arr.swap(left, right); 78 | } 79 | } 80 | 81 | arr.swap(pivot, left); 82 | 83 | // 返回正确的分割位置 84 | left 85 | } 86 | 87 | #[cfg(test)] 88 | mod tests { 89 | use super::*; 90 | 91 | #[test] 92 | fn test_empty_vec() { 93 | let mut empty_vec: Vec = vec![]; 94 | quick_sort(&mut empty_vec); 95 | assert_eq!(empty_vec, Vec::::new()); 96 | } 97 | 98 | #[test] 99 | fn test_number_vec() { 100 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 101 | quick_sort(&mut vec); 102 | assert_eq!(vec, vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78]); 103 | } 104 | 105 | #[test] 106 | fn test_string_vec() { 107 | let mut vec = vec![ 108 | String::from("Bob"), 109 | String::from("David"), 110 | String::from("Carol"), 111 | String::from("Alice"), 112 | ]; 113 | quick_sort(&mut vec); 114 | assert_eq!( 115 | vec, 116 | vec![ 117 | String::from("Alice"), 118 | String::from("Bob"), 119 | String::from("Carol"), 120 | String::from("David"), 121 | ] 122 | ); 123 | } 124 | } 125 | ``` -------------------------------------------------------------------------------- /src/sorting/radix-sort.md: -------------------------------------------------------------------------------- 1 | # 基数排序 2 | 3 | ```rust 4 | /// Sorts the elements of `arr` in-place using radix sort. 5 | /// 6 | /// Time complexity is `O((n + b) * logb(k))`, where `n` is the number of elements, 7 | /// `b` is the base (the radix), and `k` is the largest element. 8 | /// When `n` and `b` are roughly the same maginitude, this algorithm runs in linear time. 9 | /// 10 | /// Space complexity is `O(n + b)`. 11 | pub fn radix_sort(arr: &mut [u64]) { 12 | let max: usize = match arr.iter().max() { 13 | Some(&x) => x as usize, 14 | None => return, 15 | }; 16 | // Make radix a power of 2 close to arr.len() for optimal runtime 17 | let radix = arr.len().next_power_of_two(); 18 | // Counting sort by each digit from least to most significant 19 | let mut place = 1; 20 | while place <= max { 21 | let digit_of = |x| x as usize / place % radix; 22 | // Count digit occurrences 23 | let mut counter = vec![0; radix]; 24 | for &x in arr.iter() { 25 | counter[digit_of(x)] += 1; 26 | } 27 | // Compute last index of each digit 28 | for i in 1..radix { 29 | counter[i] += counter[i - 1]; 30 | } 31 | // Write elements to their new indices 32 | for &x in arr.to_owned().iter().rev() { 33 | counter[digit_of(x)] -= 1; 34 | arr[counter[digit_of(x)]] = x; 35 | } 36 | place *= radix; 37 | } 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use super::super::is_sorted; 43 | use super::radix_sort; 44 | 45 | #[test] 46 | fn empty() { 47 | let mut a: [u64; 0] = []; 48 | radix_sort(&mut a); 49 | assert!(is_sorted(&a)); 50 | } 51 | 52 | #[test] 53 | fn descending() { 54 | let mut v = vec![201, 127, 64, 37, 24, 4, 1]; 55 | radix_sort(&mut v); 56 | assert!(is_sorted(&v)); 57 | } 58 | 59 | #[test] 60 | fn ascending() { 61 | let mut v = vec![1, 4, 24, 37, 64, 127, 201]; 62 | radix_sort(&mut v); 63 | assert!(is_sorted(&v)); 64 | } 65 | } 66 | ``` -------------------------------------------------------------------------------- /src/sorting/selection-sort.md: -------------------------------------------------------------------------------- 1 | # 选择排序 2 | 3 | ```rust 4 | pub fn selection_sort(arr: &mut [T]) { 5 | if arr.len() <= 1 { 6 | return; 7 | } 8 | 9 | let size = arr.len(); 10 | for i in 0..(size - 1) { 11 | // 找到最小元素的索引值 12 | let mut min_index = i; 13 | for j in (i + 1)..size { 14 | if arr[j] < arr[min_index] { 15 | min_index = j; 16 | } 17 | } 18 | 19 | if min_index != i { 20 | arr.swap(i, min_index); 21 | } 22 | } 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use super::*; 28 | 29 | #[test] 30 | fn test_empty_vec() { 31 | let mut empty_vec: Vec = vec![]; 32 | selection_sort(&mut empty_vec); 33 | assert_eq!(empty_vec, Vec::::new()); 34 | } 35 | 36 | #[test] 37 | fn test_number_vec() { 38 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 39 | selection_sort(&mut vec); 40 | assert_eq!(vec, vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78]); 41 | } 42 | 43 | #[test] 44 | fn test_string_vec() { 45 | let mut vec = vec![ 46 | String::from("Bob"), 47 | String::from("David"), 48 | String::from("Carol"), 49 | String::from("Alice"), 50 | ]; 51 | selection_sort(&mut vec); 52 | assert_eq!( 53 | vec, 54 | vec![ 55 | String::from("Alice"), 56 | String::from("Bob"), 57 | String::from("Carol"), 58 | String::from("David"), 59 | ] 60 | ); 61 | } 62 | } 63 | ``` -------------------------------------------------------------------------------- /src/sorting/shell-sort.md: -------------------------------------------------------------------------------- 1 | # 希尔排序 2 | 3 | ```rust 4 | pub fn shell_sort(values: &mut Vec) { 5 | // shell sort works by swiping the value at a given gap and decreasing the gap to 1 6 | fn insertion(values: &mut Vec, start: usize, gap: usize) { 7 | for i in ((start + gap)..values.len()).step_by(gap) { 8 | let val_current = values[i]; 9 | let mut pos = i; 10 | // make swaps 11 | while pos >= gap && values[pos - gap] > val_current { 12 | values[pos] = values[pos - gap]; 13 | pos -= gap; 14 | } 15 | values[pos] = val_current; 16 | } 17 | } 18 | 19 | let mut count_sublist = values.len() / 2; // makes gap as long as half of the array 20 | while count_sublist > 0 { 21 | for pos_start in 0..count_sublist { 22 | insertion(values, pos_start, count_sublist); 23 | } 24 | count_sublist /= 2; // makes gap as half of previous 25 | } 26 | } 27 | 28 | #[cfg(test)] 29 | mod test { 30 | use super::shell_sort; 31 | 32 | #[test] 33 | fn basic() { 34 | let mut vec = vec![3, 5, 6, 3, 1, 4]; 35 | shell_sort(&mut vec); 36 | for i in 0..vec.len() - 1 { 37 | assert!(vec[i] <= vec[i + 1]); 38 | } 39 | } 40 | 41 | #[test] 42 | fn empty() { 43 | let mut vec: Vec = vec![]; 44 | shell_sort(&mut vec); 45 | assert_eq!(vec, vec![]); 46 | } 47 | 48 | #[test] 49 | fn reverse() { 50 | let mut vec = vec![6, 5, 4, 3, 2, 1]; 51 | shell_sort(&mut vec); 52 | for i in 0..vec.len() - 1 { 53 | assert!(vec[i] <= vec[i + 1]); 54 | } 55 | } 56 | 57 | #[test] 58 | fn already_sorted() { 59 | let mut vec = vec![1, 2, 3, 4, 5, 6]; 60 | shell_sort(&mut vec); 61 | for i in 0..vec.len() - 1 { 62 | assert!(vec[i] <= vec[i + 1]); 63 | } 64 | } 65 | } 66 | ``` -------------------------------------------------------------------------------- /src/sorting/stooge-sort.md: -------------------------------------------------------------------------------- 1 | # 臭皮匠排序 2 | 3 | ```rust 4 | fn _stooge_sort(arr: &mut [T], start: usize, end: usize) { 5 | if arr[start] > arr[end] { 6 | arr.swap(start, end); 7 | } 8 | 9 | if start + 1 >= end { 10 | return; 11 | } 12 | 13 | let k = (end - start + 1) / 3; 14 | 15 | _stooge_sort(arr, start, end - k); 16 | _stooge_sort(arr, start + k, end); 17 | _stooge_sort(arr, start, end - k); 18 | } 19 | 20 | pub fn stooge_sort(arr: &mut [T]) { 21 | let len = arr.len(); 22 | if len == 0 { 23 | return; 24 | } 25 | 26 | _stooge_sort(arr, 0, len - 1); 27 | } 28 | 29 | #[cfg(test)] 30 | mod test { 31 | use super::*; 32 | 33 | #[test] 34 | fn basic() { 35 | let mut vec = vec![3, 5, 6, 3, 1, 4]; 36 | stooge_sort(&mut vec); 37 | for i in 0..vec.len() - 1 { 38 | assert!(vec[i] <= vec[i + 1]); 39 | } 40 | } 41 | 42 | #[test] 43 | fn empty() { 44 | let mut vec: Vec = vec![]; 45 | stooge_sort(&mut vec); 46 | assert_eq!(vec, vec![]); 47 | } 48 | 49 | #[test] 50 | fn reverse() { 51 | let mut vec = vec![6, 5, 4, 3, 2, 1]; 52 | stooge_sort(&mut vec); 53 | for i in 0..vec.len() - 1 { 54 | assert!(vec[i] <= vec[i + 1]); 55 | } 56 | } 57 | 58 | #[test] 59 | fn already_sorted() { 60 | let mut vec = vec![1, 2, 3, 4, 5, 6]; 61 | stooge_sort(&mut vec); 62 | for i in 0..vec.len() - 1 { 63 | assert!(vec[i] <= vec[i + 1]); 64 | } 65 | } 66 | } 67 | ``` -------------------------------------------------------------------------------- /src/sorting/timsort.md: -------------------------------------------------------------------------------- 1 | # Timsort 2 | 3 | > 算法由 [xieyu567](https://github.com/xieyu567) 提交 4 | 5 | ```rust,editable 6 | use std::cmp::min; 7 | 8 | pub fn find_min_run(mut n: usize) -> usize { 9 | let mut r = 0; 10 | let minimum = 64; 11 | while n >= minimum { 12 | r |= n & 1; 13 | n >>= 1; 14 | } 15 | n + r 16 | } 17 | 18 | pub fn insert_sort(arr: &mut [T], left: usize, right: usize) 19 | where T: PartialOrd + Copy, { 20 | for i in left + 1..right + 1 { 21 | let element = arr[i]; 22 | let mut j = i - 1; 23 | while element < arr[j] && j >= left { 24 | arr[j + 1] = arr[j]; 25 | j -= 1; 26 | } 27 | arr[j + 1] = element; 28 | } 29 | } 30 | 31 | pub fn merge(arr: &mut [T], left: usize, mid: usize, right: usize) 32 | where T: PartialOrd + Copy, { 33 | let array_length1 = mid - left + 1; 34 | let array_length2 = right - mid; 35 | let left_arr = Vec::from(&arr[left..left + array_length1]); 36 | let right_arr = Vec::from(&arr[mid + 1..mid + 1 + array_length2]); 37 | 38 | let (mut i, mut j, mut k) = (0, 0, left); 39 | while j < array_length2 && i < array_length1 { 40 | if left_arr[i] <= right_arr[j] { 41 | arr[k] = left_arr[i]; 42 | i += 1; 43 | } else { 44 | arr[k] = right_arr[j]; 45 | j += 1 46 | } 47 | k += 1 48 | } 49 | while i < array_length1 { 50 | arr[k] = left_arr[i]; 51 | k += 1; 52 | i += 1 53 | } 54 | while j < array_length2 { 55 | arr[k] = right_arr[j]; 56 | k += 1; 57 | j += 1 58 | } 59 | } 60 | 61 | pub fn tim_sort(arr: &mut [T]) 62 | where T: PartialOrd + Copy, { 63 | let n = arr.len(); 64 | let min_run = find_min_run(n); 65 | 66 | for start in (0..n).filter(|x| x % min_run == 0) { 67 | let end = min(start + min_run - 1, n - 1); 68 | insert_sort(arr, start, end) 69 | } 70 | let mut size = min_run; 71 | while size < n { 72 | for left in (0..n).filter(|x| x % (2 * size) == 0) { 73 | let mid = min(n - 1, left + size - 1); 74 | let right = min(left + 2 * size - 1, n - 1); 75 | merge(arr, left, mid, right) 76 | } 77 | size = 2 * size 78 | } 79 | } 80 | 81 | #[cfg(test)] 82 | mod tests { 83 | use super::*; 84 | 85 | #[test] 86 | fn cal_min() { 87 | let n = 189; 88 | let min_run = find_min_run(n); 89 | assert_eq!(48, min_run); 90 | assert_eq!(61, find_min_run(976)); 91 | } 92 | 93 | #[test] 94 | fn insert_test() { 95 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 96 | insert_sort(&mut vec, 0, 9); 97 | assert_eq!(vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78], vec) 98 | } 99 | 100 | #[test] 101 | fn tim_test() { 102 | let mut vec = vec![7, 49, 73, 58, 30, 72, 44, 78, 23, 9]; 103 | tim_sort(&mut vec); 104 | assert_eq!(vec, vec![7, 9, 23, 30, 44, 49, 58, 72, 73, 78]); 105 | } 106 | } 107 | 108 | ``` -------------------------------------------------------------------------------- /src/string/burrows-wheeler-transform.md: -------------------------------------------------------------------------------- 1 | # 数据转换算法(Burrows Wheeler Transform) 2 | 3 | ```rust 4 | pub fn burrows_wheeler_transform(input: String) -> (String, usize) { 5 | let len = input.len(); 6 | 7 | let mut table = Vec::::with_capacity(len); 8 | for i in 0..len { 9 | table.push(input[i..].to_owned() + &input[..i]); 10 | } 11 | table.sort_by_key(|a| a.to_lowercase()); 12 | 13 | let mut encoded = String::new(); 14 | let mut index: usize = 0; 15 | for (i, item) in table.iter().enumerate().take(len) { 16 | encoded.push(item.chars().last().unwrap()); 17 | if item.eq(&input) { 18 | index = i; 19 | } 20 | } 21 | 22 | (encoded, index) 23 | } 24 | 25 | pub fn inv_burrows_wheeler_transform(input: (String, usize)) -> String { 26 | let len = input.0.len(); 27 | let mut table = Vec::<(usize, char)>::with_capacity(len); 28 | for i in 0..len { 29 | table.push((i, input.0.chars().nth(i).unwrap())); 30 | } 31 | 32 | table.sort_by(|a, b| a.1.cmp(&b.1)); 33 | 34 | let mut decoded = String::new(); 35 | let mut idx = input.1; 36 | for _ in 0..len { 37 | decoded.push(table[idx].1); 38 | idx = table[idx].0; 39 | } 40 | 41 | decoded 42 | } 43 | 44 | #[cfg(test)] 45 | mod tests { 46 | use super::*; 47 | 48 | #[test] 49 | fn basic() { 50 | assert_eq!( 51 | inv_burrows_wheeler_transform(burrows_wheeler_transform("CARROT".to_string())), 52 | "CARROT" 53 | ); 54 | assert_eq!( 55 | inv_burrows_wheeler_transform(burrows_wheeler_transform("TOMATO".to_string())), 56 | "TOMATO" 57 | ); 58 | assert_eq!( 59 | inv_burrows_wheeler_transform(burrows_wheeler_transform("THISISATEST".to_string())), 60 | "THISISATEST" 61 | ); 62 | assert_eq!( 63 | inv_burrows_wheeler_transform(burrows_wheeler_transform("THEALGORITHMS".to_string())), 64 | "THEALGORITHMS" 65 | ); 66 | assert_eq!( 67 | inv_burrows_wheeler_transform(burrows_wheeler_transform("RUST".to_string())), 68 | "RUST" 69 | ); 70 | } 71 | 72 | #[test] 73 | fn special_characters() { 74 | assert_eq!( 75 | inv_burrows_wheeler_transform(burrows_wheeler_transform("!.!.!??.=::".to_string())), 76 | "!.!.!??.=::" 77 | ); 78 | assert_eq!( 79 | inv_burrows_wheeler_transform(burrows_wheeler_transform( 80 | "!{}{}(((&&%%!??.=::".to_string() 81 | )), 82 | "!{}{}(((&&%%!??.=::" 83 | ); 84 | assert_eq!( 85 | inv_burrows_wheeler_transform(burrows_wheeler_transform("//&$[]".to_string())), 86 | "//&$[]" 87 | ); 88 | } 89 | 90 | #[test] 91 | fn empty() { 92 | assert_eq!( 93 | inv_burrows_wheeler_transform(burrows_wheeler_transform("".to_string())), 94 | "" 95 | ); 96 | } 97 | } 98 | ``` -------------------------------------------------------------------------------- /src/string/index.md: -------------------------------------------------------------------------------- 1 | # 字符串 2 | 3 | 字符串相关的算法往往和子串匹配、顺序调整相关,如何高效的处理字符串,有时会成为一个程序性能的关键。 -------------------------------------------------------------------------------- /src/string/knuth-morris-pratt.md: -------------------------------------------------------------------------------- 1 | # KMP算法(Knuth Morris Pratt) 2 | 3 | ```rust 4 | pub fn knuth_morris_pratt(st: String, pat: String) -> Vec { 5 | if st.is_empty() || pat.is_empty() { 6 | return vec![]; 7 | } 8 | 9 | let string = st.into_bytes(); 10 | let pattern = pat.into_bytes(); 11 | 12 | // build the partial match table 13 | let mut partial = vec![0]; 14 | for i in 1..pattern.len() { 15 | let mut j = partial[i - 1]; 16 | while j > 0 && pattern[j] != pattern[i] { 17 | j = partial[j - 1]; 18 | } 19 | partial.push(if pattern[j] == pattern[i] { j + 1 } else { j }); 20 | } 21 | 22 | // and read 'string' to find 'pattern' 23 | let mut ret = vec![]; 24 | let mut j = 0; 25 | 26 | for (i, &c) in string.iter().enumerate() { 27 | while j > 0 && c != pattern[j] { 28 | j = partial[j - 1]; 29 | } 30 | if c == pattern[j] { 31 | j += 1; 32 | } 33 | if j == pattern.len() { 34 | ret.push(i + 1 - j); 35 | j = partial[j - 1]; 36 | } 37 | } 38 | 39 | ret 40 | } 41 | 42 | #[cfg(test)] 43 | mod tests { 44 | use super::*; 45 | 46 | #[test] 47 | fn each_letter_matches() { 48 | let index = knuth_morris_pratt("aaa".to_string(), "a".to_string()); 49 | assert_eq!(index, vec![0, 1, 2]); 50 | } 51 | 52 | #[test] 53 | fn a_few_separate_matches() { 54 | let index = knuth_morris_pratt("abababa".to_string(), "ab".to_string()); 55 | assert_eq!(index, vec![0, 2, 4]); 56 | } 57 | 58 | #[test] 59 | fn one_match() { 60 | let index = 61 | knuth_morris_pratt("ABC ABCDAB ABCDABCDABDE".to_string(), "ABCDABD".to_string()); 62 | assert_eq!(index, vec![15]); 63 | } 64 | 65 | #[test] 66 | fn lots_of_matches() { 67 | let index = knuth_morris_pratt("aaabaabaaaaa".to_string(), "aa".to_string()); 68 | assert_eq!(index, vec![0, 1, 4, 7, 8, 9, 10]); 69 | } 70 | 71 | #[test] 72 | fn lots_of_intricate_matches() { 73 | let index = knuth_morris_pratt("ababababa".to_string(), "aba".to_string()); 74 | assert_eq!(index, vec![0, 2, 4, 6]); 75 | } 76 | 77 | #[test] 78 | fn not_found0() { 79 | let index = knuth_morris_pratt("abcde".to_string(), "f".to_string()); 80 | assert_eq!(index, vec![]); 81 | } 82 | 83 | #[test] 84 | fn not_found1() { 85 | let index = knuth_morris_pratt("abcde".to_string(), "ac".to_string()); 86 | assert_eq!(index, vec![]); 87 | } 88 | 89 | #[test] 90 | fn not_found2() { 91 | let index = knuth_morris_pratt("ababab".to_string(), "bababa".to_string()); 92 | assert_eq!(index, vec![]); 93 | } 94 | 95 | #[test] 96 | fn empty_string() { 97 | let index = knuth_morris_pratt("".to_string(), "abcdef".to_string()); 98 | assert_eq!(index, vec![]); 99 | } 100 | } 101 | ``` -------------------------------------------------------------------------------- /src/string/manacher.md: -------------------------------------------------------------------------------- 1 | # 马拉车算法(Manacher) 2 | 3 | ```rust 4 | pub fn manacher(s: String) -> String { 5 | let l = s.len(); 6 | if l <= 1 { 7 | return s; 8 | } 9 | 10 | // MEMO: We need to detect odd palindrome as well, 11 | // therefore, inserting dummy string so that 12 | // we can find a pair with dummy center character. 13 | let mut chars: Vec = Vec::with_capacity(s.len() * 2 + 1); 14 | for c in s.chars() { 15 | chars.push('#'); 16 | chars.push(c); 17 | } 18 | chars.push('#'); 19 | 20 | // List: storing the length of palindrome at each index of string 21 | let mut length_of_palindrome = vec![1usize; chars.len()]; 22 | // Integer: Current checking palindrome's center index 23 | let mut current_center: usize = 0; 24 | // Integer: Right edge index existing the radius away from current center 25 | let mut right_from_current_center: usize = 0; 26 | 27 | for i in 0..chars.len() { 28 | // 1: Check if we are looking at right side of palindrome. 29 | if right_from_current_center > i && i > current_center { 30 | // 1-1: If so copy from the left side of palindrome. 31 | // If the value + index exceeds the right edge index, we should cut and check palindrome later #3. 32 | length_of_palindrome[i] = std::cmp::min( 33 | right_from_current_center - i, 34 | length_of_palindrome[2 * current_center - i], 35 | ); 36 | // 1-2: Move the checking palindrome to new index if it exceeds the right edge. 37 | if length_of_palindrome[i] + i >= right_from_current_center { 38 | current_center = i; 39 | right_from_current_center = length_of_palindrome[i] + i; 40 | // 1-3: If radius exceeds the end of list, it means checking is over. 41 | // You will never get the larger value because the string will get only shorter. 42 | if right_from_current_center >= chars.len() - 1 { 43 | break; 44 | } 45 | } else { 46 | // 1-4: If the checking index doesn't exceeds the right edge, 47 | // it means the length is just as same as the left side. 48 | // You don't need to check anymore. 49 | continue; 50 | } 51 | } 52 | 53 | // Integer: Current radius from checking index 54 | // If it's copied from left side and more than 1, 55 | // it means it's ensured so you don't need to check inside radius. 56 | let mut radius: usize = (length_of_palindrome[i] - 1) / 2; 57 | radius += 1; 58 | // 2: Checking palindrome. 59 | // Need to care about overflow usize. 60 | while i >= radius && i + radius <= chars.len() - 1 && chars[i - radius] == chars[i + radius] 61 | { 62 | length_of_palindrome[i] += 2; 63 | radius += 1; 64 | } 65 | } 66 | 67 | // 3: Find the maximum length and generate answer. 68 | let center_of_max = length_of_palindrome 69 | .iter() 70 | .enumerate() 71 | .max_by_key(|(_, &value)| value) 72 | .map(|(idx, _)| idx) 73 | .unwrap(); 74 | let radius_of_max = (length_of_palindrome[center_of_max] - 1) / 2; 75 | let answer = &chars[(center_of_max - radius_of_max)..(center_of_max + radius_of_max + 1)] 76 | .iter() 77 | .collect::(); 78 | answer.replace("#", "") 79 | } 80 | 81 | #[cfg(test)] 82 | mod tests { 83 | use super::manacher; 84 | 85 | #[test] 86 | fn get_longest_palindrome_by_manacher() { 87 | assert_eq!(manacher("babad".to_string()), "aba".to_string()); 88 | assert_eq!(manacher("cbbd".to_string()), "bb".to_string()); 89 | assert_eq!(manacher("a".to_string()), "a".to_string()); 90 | 91 | let ac_ans = manacher("ac".to_string()); 92 | assert!(ac_ans == "a".to_string() || ac_ans == "c".to_string()); 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /src/string/rabin-karp.md: -------------------------------------------------------------------------------- 1 | # Rabin Karp算法 2 | 3 | ```rust 4 | pub fn rabin_karp(target: String, pattern: String) -> Vec { 5 | // Quick exit 6 | if target.is_empty() || pattern.is_empty() || pattern.len() > target.len() { 7 | return vec![]; 8 | } 9 | 10 | let string: String = (&pattern[0..pattern.len()]).to_string(); 11 | let hash_pattern = hash(string.clone()); 12 | let mut ret = vec![]; 13 | for i in 0..(target.len() - pattern.len() + 1) { 14 | let s = (&target[i..(i + pattern.len())]).to_string(); 15 | let string_hash = hash(s.clone()); 16 | 17 | if string_hash == hash_pattern && s == string { 18 | ret.push(i); 19 | } 20 | } 21 | ret 22 | } 23 | 24 | fn hash(mut s: String) -> u16 { 25 | let prime: u16 = 101; 26 | let last_char = s 27 | .drain(s.len() - 1..) 28 | .next() 29 | .expect("Failed to get the last char of the string"); 30 | let mut res: u16 = 0; 31 | for (i, &c) in s.as_bytes().iter().enumerate() { 32 | if i == 0 { 33 | res = (c as u16 * 256) % prime; 34 | } else { 35 | res = (((res + c as u16) % 101) * 256) % 101; 36 | } 37 | } 38 | (res + last_char as u16) % prime 39 | } 40 | 41 | #[cfg(test)] 42 | mod tests { 43 | use super::*; 44 | 45 | #[test] 46 | fn hi_hash() { 47 | let hash_result = hash("hi".to_string()); 48 | assert_eq!(hash_result, 65); 49 | } 50 | 51 | #[test] 52 | fn abr_hash() { 53 | let hash_result = hash("abr".to_string()); 54 | assert_eq!(hash_result, 4); 55 | } 56 | 57 | #[test] 58 | fn bra_hash() { 59 | let hash_result = hash("bra".to_string()); 60 | assert_eq!(hash_result, 30); 61 | } 62 | 63 | // Attribution to @pgimalac for his tests from Knuth-Morris-Pratt 64 | #[test] 65 | fn each_letter_matches() { 66 | let index = rabin_karp("aaa".to_string(), "a".to_string()); 67 | assert_eq!(index, vec![0, 1, 2]); 68 | } 69 | 70 | #[test] 71 | fn a_few_separate_matches() { 72 | let index = rabin_karp("abababa".to_string(), "ab".to_string()); 73 | assert_eq!(index, vec![0, 2, 4]); 74 | } 75 | 76 | #[test] 77 | fn one_match() { 78 | let index = rabin_karp("ABC ABCDAB ABCDABCDABDE".to_string(), "ABCDABD".to_string()); 79 | assert_eq!(index, vec![15]); 80 | } 81 | 82 | #[test] 83 | fn lots_of_matches() { 84 | let index = rabin_karp("aaabaabaaaaa".to_string(), "aa".to_string()); 85 | assert_eq!(index, vec![0, 1, 4, 7, 8, 9, 10]); 86 | } 87 | 88 | #[test] 89 | fn lots_of_intricate_matches() { 90 | let index = rabin_karp("ababababa".to_string(), "aba".to_string()); 91 | assert_eq!(index, vec![0, 2, 4, 6]); 92 | } 93 | 94 | #[test] 95 | fn not_found0() { 96 | let index = rabin_karp("abcde".to_string(), "f".to_string()); 97 | assert_eq!(index, vec![]); 98 | } 99 | 100 | #[test] 101 | fn not_found1() { 102 | let index = rabin_karp("abcde".to_string(), "ac".to_string()); 103 | assert_eq!(index, vec![]); 104 | } 105 | 106 | #[test] 107 | fn not_found2() { 108 | let index = rabin_karp("ababab".to_string(), "bababa".to_string()); 109 | assert_eq!(index, vec![]); 110 | } 111 | 112 | #[test] 113 | fn empty_string() { 114 | let index = rabin_karp("".to_string(), "abcdef".to_string()); 115 | assert_eq!(index, vec![]); 116 | } 117 | } 118 | ``` -------------------------------------------------------------------------------- /src/string/reverse.md: -------------------------------------------------------------------------------- 1 | # 逆序倒转 2 | 3 | ```rust 4 | pub fn reverse(text: &str) -> String { 5 | text.chars().rev().collect() 6 | } 7 | 8 | #[cfg(test)] 9 | mod tests { 10 | use super::*; 11 | 12 | #[test] 13 | fn test_simple() { 14 | assert_eq!(reverse("racecar"), "racecar"); 15 | } 16 | 17 | #[test] 18 | fn test_sentence() { 19 | assert_eq!(reverse("step on no pets"), "step on no pets"); 20 | } 21 | } 22 | ``` --------------------------------------------------------------------------------