Skip to content

Commit

Permalink
Add Binary Search Tree implementation to datastruct module.
Browse files Browse the repository at this point in the history
  • Loading branch information
DaviRain-Su committed Jun 15, 2023
1 parent 3b3602d commit 59f4122
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 1 deletion.
179 changes: 179 additions & 0 deletions rust/src/datastruct/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#[derive(Debug, Default, PartialEq)]
pub struct Node<T> {
data: T,
left: Option<Box<Node<T>>>,
right: Option<Box<Node<T>>>,
}

/// Binary search tree
#[derive(Debug, Default)]
pub struct BinarySearchTree<T> {
root: Option<Box<Node<T>>>,
}

impl<T> BinarySearchTree<T>
where
T: std::cmp::PartialEq + std::cmp::PartialOrd + std::clone::Clone,
{
pub fn new() -> Self {
BinarySearchTree { root: None }
}

pub fn sort(&self) -> Vec<T> {
let mut result = Vec::new();
self.inorder(self.root.as_ref(), &mut result);
result
}

pub fn inorder_tree_walk(&self) -> Vec<T> {
let mut result = Vec::new();
self.inorder(self.root.as_ref(), &mut result);
result
}

pub fn tree_search(&self, data: T) -> Option<&Box<Node<T>>> {
let mut node = self.root.as_ref();
while let Some(n) = node {
if n.data == data {
return node;
} else if n.data > data {
node = n.left.as_ref();
} else {
node = n.right.as_ref();
}
}
None
}

pub fn interative_tree_search(&self, data: T) -> Option<&Box<Node<T>>> {
let mut node = self.root.as_ref();
while let Some(n) = node {
if n.data == data {
return node;
} else if n.data > data {
node = n.left.as_ref();
} else {
node = n.right.as_ref();
}
}
None
}

pub fn tree_minmum(&self) -> Option<&Box<Node<T>>> {
let mut node = self.root.as_ref();
while let Some(n) = node {
if n.left.is_none() {
return node;
} else {
node = n.left.as_ref();
}
}
None
}

pub fn tree_maxmum(&self) -> Option<&Box<Node<T>>> {
let mut node = self.root.as_ref();
while let Some(n) = node {
if n.right.is_none() {
return node;
} else {
node = n.right.as_ref();
}
}
None
}

pub fn tree_search_with_path(&self, data: T) -> Option<(Vec<&Node<T>>, &Node<T>)> {
let mut path = Vec::new();
let mut current = &self.root;
while let Some(node) = current {
if data < node.data {
current = &node.left;
} else if data > node.data {
current = &node.right;
} else {
return Some((path, node));
}
path.push(node);
}
None
}

pub fn tree_successor(&self, data: T) -> Option<&Node<T>> {
let (mut path, mut node) = self.tree_search_with_path(data)?;
if let Some(right) = &node.right {
let mut node = right;
while let Some(left) = &node.left {
node = left;
}
return Some(node);
}
while let Some(parent) = path.pop() {
if parent.right.as_deref() != Some(node) {
return Some(parent);
}
node = parent;
}
None
}

pub fn inorder(&self, node: Option<&Box<Node<T>>>, result: &mut Vec<T>) {
if let Some(node) = node {
self.inorder(node.left.as_ref(), result);
result.push(node.data.clone());
self.inorder(node.right.as_ref(), result);
}
}

pub fn contains(&self, data: T) -> bool {
let mut node = self.root.as_ref();
while let Some(n) = node {
if n.data == data {
return true;
} else if n.data > data {
node = n.left.as_ref();
} else {
node = n.right.as_ref();
}
}
false
}

pub fn tree_insert(&mut self, data: T) {
let mut node = &mut self.root;
while let Some(n) = node {
if n.data > data {
node = &mut n.left;
} else {
node = &mut n.right;
}
}
*node = Some(Box::new(Node {
data,
left: None,
right: None,
}));
}
}

#[cfg(test)]
mod test {

#[test]
fn test_search_binary_tree() {
use super::BinarySearchTree;
let mut tree = BinarySearchTree::new();
tree.tree_insert(5);
tree.tree_insert(3);
tree.tree_insert(7);
tree.tree_insert(2);

let ret = tree.sort();
println!("ret = {:?}", ret);

let min = tree.tree_minmum();
println!("min = {:?}", min);
let max = tree.tree_maxmum();
println!("max = {:?}", max);
}
}
3 changes: 3 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ pub mod sort;
/// search algorithm
pub mod search;

/// data struct
pub mod datastruct;

#[cfg(test)]
mod tests;
pub mod utils;
Expand Down
13 changes: 12 additions & 1 deletion rust/src/sort/quick_sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,18 @@ pub fn partition<T: Ord + std::fmt::Debug>(arr: &mut [T]) -> usize {
/// 在 `quickify` 函数中,我们会对 `pivot` 左侧的元素(索引 `0` 到 `pivot - 1`,
/// 即 `[5, 2, 3]`)和右侧的元素(索引 `pivot + 1` 到 `n - 1`,即 `[12, 9, 14, 7, 10, 11]`)进行递归排序。
/// 这样,在几轮递归后,整个数组就会被完全排序。

///
/// 上述代码实现了快速排序算法的基本形式,它对于大多数情况已经非常高效了。然而,如果你对此有特别的需求,以下是一些可能的优化方向:
///
/// 1. **Pivot 的选择**:在上述代码中,Pivot 是固定选择的每一轮数组的最后一个元素,这可能会导致在处理已经接近有序的数据时效率降低。一个常见的优化是使用"三数取中"法来选取 Pivot,即从数组的首元素、中间元素和尾元素中选取中位数作为 Pivot。
///
/// 2. **插入排序的应用**:对于小数组,快速排序并不一定是最高效的。在这种情况下,一种常见的优化是当数组的大小降到某个阈值(比如 10)时,切换到插入排序。
///
/// 3. **去除尾递归**:上述代码使用了两次递归,但其实你可以去除一个递归。方法是将对右侧数组的递归操作改为迭代,在每次迭代中,仅对左侧数组进行递归。
///
/// 4. **并行化**:如果你处理的是非常大的数据,或者你的硬件具有多个处理核心,你可以考虑并行化快速排序算法。简单来说,就是让每个核心处理数组的一部分。这需要更复杂的编程技术,并且必须小心地处理并发操作,以避免数据的不一致。
///
/// 这些优化对于基本的快速排序算法来说可能会有所帮助,但是在应用之前,你应该先确定你的代码的性能瓶颈在哪里,以及这些优化是否值得你的时间和精力去实现。
#[test]
fn test_quickify() {
let mut arr = [1, 3, 2, 5, 4, 7, 9, 8, 6];
Expand Down

0 comments on commit 59f4122

Please sign in to comment.