Skip to content

Commit f23d709

Browse files
Merge pull request #367 from Librazy/ds
数据结构章节更新
2 parents e1d3825 + 5948013 commit f23d709

3 files changed

Lines changed: 50 additions & 36 deletions

File tree

data-structure/binary_tree.md

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,54 +3,66 @@
33
## 二叉树简介
44
在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
55

6-
1. 二叉树**左节点的值通常少于父亲节点的值**
7-
2. 二叉树**右节点的值通常大于父亲节点的值**
6+
>二叉查找树的子节点与父节点的键一般满足一定的顺序关系,习惯上,左节点的键少于父亲节点的键,右节点的键大于父亲节点的键。
7+
8+
>二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键总是大于或等于任何一个子节点的键;最小堆:父结点的键总是小于或等于任何一个子节点的键。
89
910
>二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^{i-1}个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。
1011
1112
>一棵深度为k,且有2^k-1个节点称之为满二叉树;深度为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中,序号为1至n的节点对应时,称之为完全二叉树。
1213
1314
## 二叉树与树的区别
14-
二叉树不是树的一种特殊情形,尽管其与树有许多相似之处,但树和二叉树有两个主要差别:
15+
二叉树*不是*树的一种特殊情形,尽管其与树有许多相似之处,但树和二叉树有两个主要差别:
1516

1617
1. 树中结点的最大度数没有限制,而二叉树结点的最大度数为2。
1718
2. 树的结点无左、右之分,而二叉树的结点有左、右之分。
1819

1920
## 定义二叉树的结构
21+
二叉树的每个节点由键key、值value与左右子树left/right组成,这里我们把节点声明为一个泛型结构。
2022
```rust
21-
type TreeNode = Option<Box<Node>>;
22-
type BinaryTree = Node;
23-
23+
type TreeNode<K,V> = Option<Box<Node<K,V>>>;
2424
#[derive(Debug)]
25-
struct Node {
26-
left: TreeNode,
27-
right: TreeNode,
28-
value: i32,
25+
struct Node<K,V: std::fmt::Display> {
26+
left: TreeNode<K,V>,
27+
right: TreeNode<K,V>,
28+
key: K,
29+
value: V,
2930
}
3031
```
31-
## 实现二叉树的插入和初始化
32+
## 实现二叉树的初始化与二叉查找树的插入
33+
由于二叉查找树要求键可排序,我们要求K实现PartialOrd
3234
```rust
33-
impl Node {
34-
fn new(value: i32) -> Self {
35-
Node {
35+
trait BinaryTree<K,V> {
36+
fn pre_order(&self);
37+
fn in_order(&self);
38+
fn pos_order(&self);
39+
}
40+
trait BinarySearchTree<K:PartialOrd,V>:BinaryTree<K,V> {
41+
fn insert(&mut self, key:K,value: V);
42+
}
43+
impl<K,V:std::fmt::Display> Node<K,V> {
44+
fn new(key: K,value: V) -> Self {
45+
Node{
3646
left: None,
3747
right: None,
3848
value: value,
49+
key: key,
3950
}
4051
}
41-
42-
fn insert(&mut self, value: i32) {
43-
if self.value < value {
52+
}
53+
impl<K:PartialOrd,V:std::fmt::Display> BinarySearchTree<K,V> for Node<K,V>{
54+
fn insert(&mut self, key:K,value:V) {
55+
if self.key < key {
4456
if let Some(ref mut right) = self.right {
45-
right.insert(value);
57+
right.insert(key,value);
4658
} else {
47-
self.right = Some(Box::new(Node::new(value)));
59+
self.right = Some(Box::new(Node::new(key,value)));
4860
}
4961
} else {
5062
if let Some(ref mut left) = self.left {
51-
left.insert(value);
63+
left.insert(key,value);
5264
} else {
53-
self.left = Some(Box::new(Node::new(value)));
65+
self.left = Some(Box::new(Node::new(key,value)));
5466
}
5567
}
5668
}
@@ -64,7 +76,7 @@ impl Node {
6476

6577
下面是代码实现:
6678
```rust
67-
impl Node {
79+
impl<K,V:std::fmt::Display> BinaryTree<K,V> for Node<K,V> {
6880
fn pre_order(&self) {
6981
println!("{}", self.value);
7082

@@ -98,19 +110,21 @@ impl Node {
98110
```
99111
## 测试代码
100112
```rust
113+
type BST<K,V> = Node<K,V>;
114+
101115
fn test_insert() {
102-
let mut root = BinaryTree::new(3);
103-
root.insert(2);
104-
root.insert(4);
105-
root.insert(5);
106-
root.insert(6);
107-
root.insert(1);
116+
let mut root = BST::<i32,i32>::new(3,4);
117+
root.insert(2,3);
118+
root.insert(4,6);
119+
root.insert(5,5);
120+
root.insert(6,6);
121+
root.insert(1,8);
108122
if let Some(ref left) = root.left {
109-
assert_eq!(left.value, 2);
123+
assert_eq!(left.value, 3);
110124
}
111125

112126
if let Some(ref right) = root.right {
113-
assert_eq!(right.value, 4);
127+
assert_eq!(right.value, 6);
114128
if let Some(ref right) = right.right {
115129
assert_eq!(right.value, 5);
116130
}
@@ -119,7 +133,6 @@ fn test_insert() {
119133
root.pre_order();
120134
println!("In Order traversal");
121135
root.in_order();
122-
println!("\n");
123136
println!("Pos Order traversal");
124137
root.pos_order();
125138
}
@@ -131,5 +144,3 @@ fn main() {
131144

132145
## 练习
133146
基于以上代码,修改成二叉堆的形式。
134-
135-
>二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。

data-structure/linked_list.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# 链表
22

33
## 链表简介
4-
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
4+
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 由于不必须按顺序存储,链表在给定位置插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是在有序数据中查找一个节点或者访问特定下标的节点则需要O(n)的时间,而线性表相应的时间复杂度分别是O(logn)和O(1)。
55

6-
>使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
6+
>使用链表结构可以克服数组需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在内存或磁盘上的顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
77
88
下面看我们一步步实现链表:
99

data-structure/priority_queue.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ struct PriorityQueue<T> where T: PartialOrd + Clone {
2020
```
2121
第二行的`where T: PartialOrd + Clone`指的是 PriorityQueue 存储的泛型 T 是满足 `PartialOrd``Clone` trait 约束的,意味着泛型 T 是可排序和克隆的。
2222

23-
后面是一些基本的方法实现,比较简单,就直接看代码吧。
23+
后面是一些基本的方法实现,比较简单,就直接看代码吧。这个优先队列是基于Vec实现的,有O(1)的插入和O(n)的最大/最小值出列。
2424
```rust
2525
impl<T> PriorityQueue<T> where T: PartialOrd + Clone {
2626
fn new() -> PriorityQueue<T> {
@@ -153,3 +153,6 @@ fn main() {
153153
test_keep_min();
154154
}
155155
```
156+
157+
## 练习
158+
基于二叉堆实现一个优先队列,以达到O(1)的出列和O(log n)的入列

0 commit comments

Comments
 (0)