Code Monkey home page Code Monkey logo

rustbook's Introduction

Description []

A book about Rust programming language written in Simplified, Tranditional Chinese and English. This book contains 10 chapters in which are some data structures and algorithms with demos.

  • Chapter 1: Rust basic
    • Review of Rust fundamentals
    • Learning resources
  • Chapter 2: Computer Science
    • Computer science concepts
  • Chapter 3: Algorithm Analysis
    • Big-O notation
  • Chapter 4: Basic Data Structures
    • Stack, Queue, Deque, List, Vec
  • Chapter 5: Recursion
    • Recursion theory, Tail-recursion ,Dynamic programming
  • Chapter 6: Search
    • Sequencial search, Binary search, Hashing search
  • Chapter 7: Sort
    • Ten basic sort algorithms
  • Chapter 8: Tree
    • Binary tree, Binary heap, Binary search tree, AVL tree
  • Chapter 9: Graph
    • Graph representation, BFS, DFS, Shortest path
  • Chapter 10: Practice
    • Edit Distance, Trie, Filter, LRU
    • Consistent hashing, Base58, Blockchain

Code

All demo codes are saved by chapter under publication/code/.

code_statistics

Changelog

  • 2023-06-18 add publication edition info
  • 2023-04-29 add english version of the book
  • 2022-05-15 add a new directory publication
  • 2022-02-27 change the book cover
  • 2022-02-15 add stargazer chart
  • 2022-02-12 add code statistics
  • 2022-02-09 fix typo and substract with overflow panic
  • 2022-02-06 change code font to monospaced font: Source Code Pro
  • 2022-02-02 update to rust version 1.58
  • 2022-01-31 upload code and the implementation [Simplified and Traditional Chinese Version]
  • 2021-04-24 upload first draft

Publication

Now, Chinese edition has been published with 40% more contents than the open-sourced one.

PublishCover

rustbook's People

Contributors

hulufei avatar qmhtmy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rustbook's Issues

第五章 5.4.3节内插查找算法编写有点小问题

https://github.com/QMHTMY/RustBook/blob/main/code/chapter05/interpolation_search.rs
不应该用上界处是否是 target来判断查找的结果
原来的代码:

fn interpolation_search(nums: &[i32], target: i32) -> bool {
    if nums.is_empty() { return false; }

    let mut high = nums.len() - 1;
    let mut low  = 0usize;
    loop {
        let low_val  = nums[low];
        let high_val = nums[high];
        if high <= low || target < low_val || target > high_val {
            break;
        }

        let offset = (target - low_val)*(high - low) as i32 / (high_val - low_val);
        let interpolant = low + offset as usize;

        if nums[interpolant] > target {
            high = interpolant - 1;
        } else if nums[interpolant] < target {
            low = interpolant + 1;
        } else {
            break;
        }
    }

    if target == nums[high] {
        true
    } else {
        false
    }
}

修改如下:

fn interpolation_search(nums: &[i32], target: i32) -> bool {
    if nums.is_empty() { return false; }

    let mut high = nums.len() - 1;
    let mut low  = 0usize;

    loop {
        let low_val  = nums[low];
        let high_val = nums[high];
        if high <= low || target < low_val || target > high_val {
           return false; 
        }

        let offset = (target - low_val)*(high - low) as i32 / (high_val - low_val);
        let interpolant = low + offset as usize;

        if nums[interpolant] > target {
            high = interpolant - 1;
        } else if nums[interpolant] < target {
            low = interpolant + 1;
        } else {
            return true;
        }
    }
}

Chinese characters could not be loaded in pdf

Hi Shieber, thanks for the book! However, it appears that the pdf could not be loaded/rendered on web browser (specifically Chrome that I'm currently using), any plan to fix that (by the way the download version is perfect) ?

Thanks!

The errors about the implement of queue

// queue.rs

// 队列
#[derive(Debug)]
struct Queue {
cap: usize, // 容量
data: Vec, // 数据容器
}

impl Queue {
fn new(size: usize) -> Self {
Queue {
cap: size,
data: Vec::with_capacity(size),
}
}

// 判断是否有剩余空间、有则数据加入队列
fn enqueue(&mut self, val: T) -> Result<(), String> {
    if Self::size(&self) == self.cap {
        return Err("No space available".to_string());
    }
    self.data.insert(0, val);

    Ok(())
}

fn size(&self) -> usize {
    self.data.len()
}

}


Because the function of "size(&self) " is a method belongs to one instance, so that we can't use the Self::size(&self) to obtain the size of self, the better choice is using self.size()......

p175 图示有误

7.4.2 Rust 实现二叉查找树 p175
二叉查找树删除节点的图示有误。
image
这幅图删除了 93 之后应该是 76 或者 94 代替 93 的位置吧。 图示的结果不满足 p168 说的要求。

不同于堆的左右子节点不考虑大小关系,二叉查找树左子节点键要小于父节点的键,右
子节点的键要大于父节点键。也就是 left < parent < right 这个规律,其递归地适用于所有
子树。

项目非常棒

看得出来作者很用心,质量也很高,总之非常赞。

Some typos to be corrected

简中版 3.6.2 节 59页有 typo
image
高亮部分应为 IntoIter

Section 5.5.1 哈希函数

分组求和法可以求哈希值,平法取中法也可以,这是另一种哈希算法。

此处 平法取中法 应为 平方取中法

关于 String 类型描述的问题

第25页:

2.5.2 集合类型

Rust 实现的 String 底层基于数组,所以 String 同数组一样不可更改。

这里描述是有问题的,标准库中 String 类型是由 Vec 实现的,也是可变的。

bin_insertion_sort.rs 中存在usize类型 Attempt to subtract with overflow 的问题

bin_insertion_sort.rs 17行开始的以下代码段中

// 二分法找到 temp 的位置
        while left <= right {
            mid = (left + right) >> 1;
            if temp < nums[mid] {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

midusize 类型,若待排序数组为 [2,3,1,4] ,则会出现 0 usize - 1 的情况,造成程序 panic ,加上一段对 mid 为 0 的处理就好,代码如下

while left <= right {
            mid = (left + right) >> 1;
            if temp < nums[mid] {
                if mid == 0 {break;}
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

堆排序计算父节点下标宏不正确

131页开头的
macro_rules! parent { ($child:ident) => { $child >> 1 }; }
应当修改为
macro_rules! parent { ($child:ident) => { ($child-1) >> 1 }; }

129页讲解堆排序时下标从1开始,所以左右子节点分别是2n和2n+1,父节点为子节点除以2。131页的代码是以下标0开始,所以左右子节点分别是2n+1和2n+2,父节点应当为子节点减一后除以2,否则右子节点计算得到的是n+1而非n。
书中代码可以正常运行,是因为parent宏只在初始化时使用以减少move_down的次数,即使计算错误多执行一次也不影响正确性。

Spelling Mistakes

  1. First paragraph of README.md: witten should be written;
  2. Section 1.7.2 of the book on page 11: tooolchain should be toolchain.

9.5 lru

LeetCode146 lru

example:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)  
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

get error:

预期结果:[null, null, null, 1, null, -1, null, -1, 3, 4]
输出结果:[null, null, null, 1, null, -1, null, 1, 3, 4]

code:

use std::collections::HashMap;
use std::hash::Hash;

/// 具体实现 参考 https://github.com/jeromefroe/lru-rs/blob/master/src/lib.result
/// Least Recently Used, 最近最少使用, 关键在于追踪每一个 entry 的 age, 每次淘汰最小的那一个 key
/// 假如淘汰逻辑要做到 O(1) 复杂度, 我们可以引入一个链表, 每次 touch 一个值时, 就删掉它重新 push_back, 而当达到容量要驱逐时, 则 pop_front
/// Rust 的链表不支持根据引用删除任意元素,也没有 LinkedHashMap,需要自己实现一个

// LRU 上的元素项
struct Entry<K, V> {
    key: K,
    val: Option<V>,
    next: Option<usize>,
    prev: Option<usize>,
}

struct LruCache<K, V> {
    cap: usize,
    head: Option<usize>,
    tail: Option<usize>,
    map: HashMap<K, usize>,
    entries: Vec<Entry<K, V>>,
}

/**
 * `&self` means the method takes an immutable reference.
 * If you need a mutable reference, change it to `&mut self` instead.
 */
impl<K: Clone + Hash + Eq, V> LruCache<K, V> {
    fn new(cap: usize) -> Self {
        Self::with_capacity(cap)
    }

    fn with_capacity(cap: usize) -> Self {
        LruCache {
            cap,
            head: None,
            tail: None,
            map: HashMap::with_capacity(cap),
            entries: Vec::with_capacity(cap),
        }
    }

    fn insert(&mut self, key: K, val: V) -> Option<V> {
        if self.map.contains_key(&key) {
            self.access(&key);
            let entry = &mut self.entries[self.head.unwrap()];
            let old_val = entry.val.take();
            entry.val = Some(val);
            old_val
        } else {
            self.ensure_room();

            // 更新原始头指针
            let index = self.entries.len();
            self.head.map(|e| {
                self.entries[e].prev = Some(index);
            });

            // 新的头结点
            self.entries.push(Entry {
                key: key.clone(),
                val: Some(val),
                prev: None,
                next: self.head,
            });
            self.head = Some(index);
            self.tail = self.tail.or(self.head);
            self.map.insert(key, index);

            None
        }
    }

    fn remove(&mut self, key: &K) -> Option<V> {
        self.map.remove(&key).map(|index| {
            self.remove_from_list(index);
            self.entries[index].val.take().unwrap()
        })
    }

    fn get(&mut self, key: &K) -> Option<&V> {
        if self.contains(key) {
            self.access(key);
        }

        let entries = &self.entries;
        self.map
            .get(key)
            .and_then(move |&i| entries[i].val.as_ref())
    }

    fn get_mut(&mut self, key: &K) -> Option<&mut V> {
        if self.contains(key) {
            self.access(key);
        }

        let entries = &mut self.entries;
        self.map
            .get(key)
            .and_then(move |&i| entries[i].val.as_mut())
    }

    fn contains(&mut self, key: &K) -> bool {
        self.map.contains_key(key)
    }

    fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    fn is_full(&self) -> bool {
        self.map.len() == self.cap
    }

    fn len(&self) -> usize {
        self.map.len()
    }

    // 获取某个 key 的值,移除原来位置的值并在头部加入
    fn access(&mut self, key: &K) {
        let i = *self.map.get(key).unwrap();
        self.remove_from_list(i);
        self.head = Some(i);
    }

    fn remove_from_list(&mut self, i: usize) {
        let (prev, next) = {
            let entry = self.entries.get_mut(i).unwrap();
            (entry.prev, entry.next)
        };

        match (prev, next) {
            // 数据项在缓存中间
            (Some(j), Some(k)) => {
                let head = &mut self.entries[j];
                head.next = next;
                let next = &mut self.entries[k];
                next.prev = prev;
            }
            // 数据项在缓存末尾
            (Some(j), None) => {
                let head = &mut self.entries[j];
                head.next = None;
                self.tail = prev;
            }
            // 数据项在缓存头部
            _ => {
                if self.len() > 1 {
                    let head = &mut self.entries[0];
                    head.next = None;
                    let next = &mut self.entries[1];
                    next.prev = None;
                }
            }
        }
    }

    // 确保容量足够,满了就移除末尾的元素
    fn ensure_room(&mut self) {
        if self.cap == self.len() {
            self.remove_tail();
        }
    }

    fn remove_tail(&mut self) {
        if let Some(index) = self.tail {
            self.remove_from_list(index);
            let key = &self.entries[index].key;
            self.map.remove(key);
        }

        if self.tail.is_none() {
            self.head = None;
        }
    }
}

struct LRUCache {
    cache: LruCache<i32, i32>,
}

impl LRUCache {
    fn new(capacity: i32) -> Self {
        Self {
            cache: LruCache::new(capacity as usize),
        }
    }

    fn get(&mut self, key: i32) -> i32 {
        if let Some(v) = self.cache.get(&key) {
            *v
        } else {
            -1
        }
    }

    fn put(&mut self, key: i32, value: i32) {
        self.cache.insert(key, value);
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * let obj = LRUCache::new(capacity);
 * let ret_1: i32 = obj.get(key);
 * obj.put(key, value);
 */

 #[test]
  fn it_works2() {
      let mut obj = LRUCache::new(2);
      obj.put(1, 1);
      obj.put(2, 2);
      assert_eq!(obj.get(1), 1);
      obj.put(3, 3);
      assert_eq!(obj.get(2), -1);
      obj.put(4, 4);
      assert_eq!(obj.get(1), -1);
      assert_eq!(obj.get(3), 3);
      assert_eq!(obj.get(4), 4);
  }

English version

Has there been any progress on the English version of this textbook? Would really love to read it.

PDF文件字体大小

我想在电子阅读器上阅读本书,但是pdf文件很难重新编辑改变字体大小。
麻烦可以提供一个字体更大的版本吗?(如果可以的话
如果转换格式的话会对阅读有很大的影响。
谢谢。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.