Trees
What is a tree data structure?
Definition: is a non-linear hierarchical structure that is used to represent and organize data in a way that is easy to navigate and search. It is a collection of nodes that are connected by edges and has a hierarchical relationship between the nodes. The topmost node of the tree is called the root, and the nodes below it are called the child nodes, and these child nodes can also have their own child nodes, forming a recursive structure.
Basic Operation of tree
Create-create a tree in data structure.
Insert- inserts data in a tree.
Search-
Preorder Traversal-per form Traveling a tree in a pre-order manner in data structure.
In order traversal – perform traveling a tree in an in-order manner.
Post order traversal- perform Traveling a tree in a post-order manner.
Types of tree data structures.
- General tree
public class BinaryTree {
Node root;
public class Node {
public int data;
public Node leftNode;
public Node rightNode;
public Node(int key) {
data = key;
}
Node findNode(int key) {
Node currentNode = root;
if (currentNode == null) {
return null;
}
// //暴力查找
// if (currentNode.data == key) {
// return currentNode;
// }
//
// //查找左节点
// while (currentNode.leftNode != null) {
// if (currentNode.leftNode.data == key) {
// return currentNode.leftNode;
// }
// currentNode = currentNode.leftNode;
// }
// //查找右节点
// while (currentNode.rightNode != null) {
// if (currentNode.rightNode.data == key) {
// return currentNode.rightNode;
// }
// currentNode = currentNode.rightNode;
// }
//二分法查找
while (currentNode != null) {
if (currentNode.data > key) {
//当前值比查找值大 则继续遍历左子树
currentNode = currentNode.leftNode;
} else if (currentNode.data < key) {
//当前值小于查找值 则继续遍历右子树
currentNode = currentNode.rightNode;
} else {
//查找到 返回
return currentNode;
}
}
return null;
}
}
void insert(int value, BinaryTree binaryTree) {
if (binaryTree == null || binaryTree.root == null) {
binaryTree = new BinaryTree();
binaryTree.root = new Node(value);
return;
}
//compare the key value
Node currentNode = binaryTree.root;
while (currentNode != null) {
if (currentNode.data > value) {
currentNode = currentNode.leftNode;
if (currentNode == null) {
currentNode.leftNode = new Node(value);
}
} else {
currentNode = currentNode.rightNode;
if (currentNode == null) {
currentNode.rightNode = currentNode;
}
}
}
}
boolean deleteNode(int value) {
Node current = root;
Node parent = root;
boolean isLeft = false;
//Check the node exists
while (current != null) {
if (root == null) {
return false;
} else {
if (root.data < value) {
isLeft = true;
current = current.rightNode;
parent = current;
} else if (root.data > value) {
parent = current;
current = current.leftNode;
}
}
}
//case 1: the node is a left
if (current.leftNode == null && current.rightNode == null) {
if (isLeft) {
parent.leftNode = null;
} else {
parent.rightNode = null;
}
}
//case 2: the node has a child
else if (current.leftNode != null || current.rightNode != null) {
Node childNode = current.leftNode != null ? current.leftNode : current.rightNode;
if (isLeft) {
parent.leftNode = childNode;
} else {
parent.rightNode = childNode;
}
}
//case 3: the node has two children.
else {
}
return true;
}
}
- Binary tree
- Balanced tree
- Binary search tree
- AVL tree
- It likes a binary search tree. But the root of this tree changes when a new item is added.
- It speeds up searching with insertion and deletion(That means dynamic searching).
- If this tree is null, the height will be -1. An empty binary tree is height balanced. If T is a nonempty binary tree with TL and TR as its left and right subtrees, then T is height balanced if and only if.
- The balance factor BF(node) = hL- hR. In an AVL tree , BF(node) =-1, 0 ,or1. If it’s over 1, we call this node troublemaker.
- Therefor, if a tree has troublemaker, we can have single rotation, RR/LL rotation, or RL/LR rotation. And several bf’s might be changed even if we don’t need to reconstruct the tree.
- The minimum number of nodes nh can be calculated as nh=Fh+2 -1 ,for h>=0. Or nh = n(h-1)+n(h-2)+1
- Some example
First step is an R rotation ,followed by an L rotation. The third step is another R rotation and finally an L rotation.
-
F(1) = 1
F(2)=F(1)+1
F(3)=F(1)+F(2)+1
```
F(7)=F(6)+F(5)+1
We already know height = depth + 1 and n(h) = n(h-1)+n(h-2)+1
package tree;
/**
* @ClassName AVLTree
* @Description AVLTree
* @Author
* @Date 4/4/2023 9:55 AM
* @Version 1.0
*/
public class AVLTree {
class Node {
int key;
int height;
Node left;
Node right;
Node() {
}
Node(int d) {
key = d;
height = 1;
}
}
Node root;
int getRootHeight() {
if (root == null) {
return 0;
}
return root.height;
}
int getHeight(Node target) {
if (target == null) {
return 0;
}
return target.height;
}
int max(int x, int y) {
return x > y ? x : y;
}
// right rotate the subtree's root with target node
Node rightRotate(Node target) {
Node left = target.left;
Node right = left.right;
//perform rotate —— get a tree
left.right = target;
target.left = right;
//update height
target.height = max(getHeight(target.left), getHeight(target.right)) + 1;
left.height = max(getHeight(left.left), getHeight(left.right)) + 1;
// Return new root
return left;
}
// left rotate subtree rooted with x
Node leftRotate(Node x) {
Node y = x.right;
Node T2 = y.left;
// Perform rotation
y.left = x;
x.right = T2;
// Update heights
x.height = max(getHeight(x.left), getHeight(x.right)) + 1;
y.height = max(getHeight(y.left), getHeight(y.right)) + 1;
// Return new root
return y;
}
// Get Balance factor of node N
int getBalance(Node N) {
if (N == null) {
return 0;
}
return getHeight(N.left) - getHeight(N.right);
}
Node insert(Node node, int key) {
/* 1. Perform the normal BST insertion */
if (node == null)
return (new Node(key));
if (key < node.key)
node.left = insert(node.left, key);
else if (key > node.key)
node.right = insert(node.right, key);
else // Duplicate keys not allowed
return node;
/* 2. Update height of this ancestor node */
node.height = 1 + max(getHeight(node.left),
getHeight(node.right));
/* 3. Get the balance factor of this ancestor
node to check whether this node became
unbalanced */
int balance = getBalance(node);
// If this node becomes unbalanced, then there
// are 4 cases Left Left Case
if (balance > 1 && key < node.left.key)
return rightRotate(node);
// Right Right Case
if (balance < -1 && key > node.right.key)
return leftRotate(node);
// Left Right Case
if (balance > 1 && key > node.left.key) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
// Right Left Case
if (balance < -1 && key < node.right.key) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
/* return the (unchanged) node pointer */
return node;
}
// A utility function to print preorder traversal
// of the tree.
// The function also prints height of every node
void preOrder(Node node) {
if (node != null) {
System.out.print(node.key + " ");
preOrder(node.left);
preOrder(node.right);
}
}
public static void main(String[] args) {
AVLTree tree = new AVLTree();
/* Constructing tree given in the above figure */
tree.root = tree.insert(tree.root, 10);
tree.root = tree.insert(tree.root, 20);
tree.root = tree.insert(tree.root, 30);
tree.root = tree.insert(tree.root, 40);
tree.root = tree.insert(tree.root, 50);
tree.root = tree.insert(tree.root, 25);
System.out.println("Preorder traversal" +
" of constructed tree is : ");
tree.preOrder(tree.root);
}
}
}
- Splay tree
- Red-black tree
- B+ tree