# Weekly leetcode - realize the basic functions of binary search tree

Posted by blackhawk08 on Wed, 17 Nov 2021 05:37:54 +0100

Data structure and algorithm website recommendation:

http://520it.com/binarytrees/
http://btv.melezinek.cz/binary-search-tree.html
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
https://yangez.github.io/btree-js
https://www.codelike.in

public class BinarySearchTree<E extends Comparable<E>> {

// Number of elements
private int size;

// Root node
private Node<E> root;

/**
* Adding nodes to a binary search tree
* 1,Find the parent node (under which node to add)
* @param element
*/
// Parameter verification
elementNotNullCheck(element);

if(root==null){
root = new Node<E>(element,null);
size++;
return;
}
// Parent node found
// Record the root node found
Node<E> parent = root;
Node<E> node = root;
// Record whether the node should be added to the left or right of the root node
int compare = 0;
while (node!=null){
parent = node;
compare = compare(element,node.element);
// compare(o1,o2). If 1 is returned, O1 > O2, return - 1, O1 < O2, return 0, o1=o2
if(compare>0){
node = node.right;
}else if(compare<0){
node = node.lefe;
}else{
node.element = element;
return;
}
}

// After finding the parent node, see where to insert it into the parent node
if(compare>0){
parent.right = new Node<>(element,parent);
}else{
parent.lefe = new Node<>(element,parent);
}
size++;
}

private int compare(E element1,E element2) {
return 0;
}

/**
* Parameter verification
* @param element
*/
public void elementNotNullCheck(E element){
if(element==null){
throw new IllegalArgumentException("element must not null");
}
}

/**
* Define node classes
* @param <E>
*/
private static class Node<E>{
private E element;
private Node<E> lefe;
private Node<E> right;
private Node<E> parent;

public Node(E element, Node<E> parent) {
this.element = element;
this.parent = parent;
}
}
}

### 2. Judge the adding direction when adding nodes: compare(E e1,E e2)

Nodes may not be directly comparable. For example, there is a Person class. The comparison method is through the age in the Person class

#### 2.1 Comparable interface

① Write an interface Comparable to compare:

public interface Comparable<E> {
public int compareTo(E e);
}

② Let the current class implement the Comparable interface and customize the comparison rules

public class Person implements Comparable<Person> {
private int age;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Person() {
}

public Person(int age) {
this.age = age;
}

@Override
public int compareTo(Person o) {
// If 1 is returned, this. Age > person. Age
return this.age-o.age;
}
}

③ Here, the default E has implemented the Comparable interface, so the element has the comparison function

public class BinarySearchTree<E extends Comparable>> {
/**
* Compare the size of two node values
* @param element1
* @param element2
* @return
*/
private int compare(E element1,E element2) {
return element1.compareTo(element2);
}
}

④ Test:

public class Main {
public static void main(String[] args) {
BinarySearchTree<Person> binarySearchTree = new BinarySearchTree<Person>();
}
}

#### 2.2 Comparator interface

① Define comparator interface:

public interface Comparator<E> {
int compare(E e1,E e2);
}

② Specify a comparator when creating a tree:

public class BinarySearchTree<E> {
// comparator
private Comparator<E> comparator;

public BinarySearchTree(Comparator<E> comparator){
this.comparator = comparator;
}

/**
* Compare the size of two node values
*/
private int compare(E element1,E element2) {
return comparator.compare(element1,element2);
}
}

③ Person class:

public class Person {
private int age;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Person() {
}

public Person(int age) {
this.age = age;
}
}

④ Test: the comparator is defined externally and uses an external class

public class Main {
// External class: comparator
private static class MyComparator1 implements Comparator<Person>{
@Override
public int compare(Person e1, Person e2) {
return e1.getAge()-e2.getAge();
}
}
private static class MyComparator2 implements Comparator<Person>{
@Override
public int compare(Person e1, Person e2) {
return e2.getAge()-e1.getAge();
}
}

public static void main(String[] args) {
// The advantage of using the Comparator interface is that the comparison logic can be customized: different comparators are passed in
// Using the Comparable interface requires following the comparison logic implemented in the Person class
BinarySearchTree<Person> binarySearchTree = new BinarySearchTree<Person>(new MyComparator1());

BinarySearchTree<Person> binarySearchTree2 = new BinarySearchTree<Person>(new MyComparator2());
}
}

You can also define a comparator using an internal class:

public class Main {
// Internal class: comparator
public static void main(String[] args) {
BinarySearchTree<Person> binarySearchTree = new BinarySearchTree<Person>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge()-o2.getAge();
}
});

BinarySearchTree<Person> binarySearchTree2 = new BinarySearchTree<Person>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o2.getAge()-o1.getAge();
}
});
}
}

#### 2.3 combination of comparable and Comparator interfaces

Comparator interface is a more flexible comparator, which is generally used in projects, and the two comparators can also be combined more perfectly.

If the Comparator is not passed in, it means that the class (Person) is Comparable, that is, it has implemented the Comparable interface. In fact, the java class library has implemented the Comparator and the Comparable interface, and many Comparable classes have also implemented the Comparable interface with the comparison function, such as:

public final class Integer implements Comparable<Integer{}
public final class String implements Comparable<String> {}

① Two comparators are used:

public class BinarySearchTree<E> {
// comparator
private Comparator<E> comparator;

public BinarySearchTree(){
}

public BinarySearchTree(Comparator<E> comparator){
this.comparator = comparator;
}

/**
* Compare the size of two node values
*/
private int compare(E element1,E element2) {
if(comparator!=null){
return comparator.compare(element1,element2);
}
// If no comparator is passed in, it means that the class E has implemented the Comparable interface. You can force it to (Comparable < E >) and call the comprareTo () method
return ((Comparable<E>)element1).compareTo(element2);
}
}

② If the Person class implements Comparable, you can construct BinarySearchTree without passing in the comparator

public class Person implements Comparable<Person> {
private int age;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Person() {
}

public Person(int age) {
this.age = age;
}

@Override
public int compareTo(Person o) {
// If 1 is returned, this. Age > person. Age
return this.age-o.age;
}
}

③ Test:

public class Main {
// External class: comparator
private static class MyComparator1 implements Comparator<Person> {
@Override
public int compare(Person e1, Person e2) {
return e1.getAge()-e2.getAge();
}
}
private static class MyComparator2 implements Comparator<Person>{
@Override
public int compare(Person e1, Person e2) {
return e2.getAge()-e1.getAge();
}
}

public static void main(String[] args) {
BinarySearchTree<Person> binarySearchTree = new BinarySearchTree<Person>(new MyComparator1());

BinarySearchTree<Person> binarySearchTree2 = new BinarySearchTree<Person>(new MyComparator2());

// If no comparator is passed in, the Person class must implement the Comparable interface to customize the comparison rules
BinarySearchTree<Person> binarySearchTree1 = new BinarySearchTree<>();
}
}

### 3. Binary tree printer

① Copy the following code in the printer folder provided by the project into the project:

② The BinarySearchTree class implements the BinaryTreeInfo interface and overrides the four methods inside:

public class BinarySearchTree<E> implements BinaryTreeInfo {

/**
* The following four methods are used to print binary trees
*/
@Override
public Object root() {
return root;
}

@Override
public Object left(Object node) {
return ((Node<E>)node).left;
}

@Override
public Object right(Object node) {
return ((Node<E>)node).right;
}

@Override
public Object string(Object node) {
return  ((Node<E>)node).element;
}
}

③ Test printer:

public class Main {
public static void main(String[] args) {
test2();
}

static void test2() {
Integer[] data = new Integer[] {7, 4, 9, 2, 5, 8, 11, 3};
BinarySearchTree<Integer> bst = new BinarySearchTree<>();
for (int i = 0; i < data.length; i++) {
}
//Print the binary tree and combine the printed binary tree with https://520it.com/binarytrees/ The binary search tree generated in is compared. If it is the same, it is right
BinaryTrees.println(bst);
}
}

Print results:

### 4. Traversal of binary tree

① Binary tree sequence traversal, pre order traversal, middle order traversal, post order traversal

public class BinarySearchTree<E> implements BinaryTreeInfo {

// Number of elements
private int size;

// Root node
private Node<E> root;

// comparator
private Comparator<E> comparator;

public BinarySearchTree(){

}

public BinarySearchTree(Comparator<E> comparator){
this.comparator = comparator;
}

/**
* level traversal
*/
public void levelOrderTraversal(){
if(root==null ) return;
queue.offer(root);
while (!queue.isEmpty()){
Node<E> node = queue.poll();
System.out.println(node.element);
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
}

/**
* Subsequent traversal
*/
public void postorderTraversal(){
postorderTraversal(root);
}
public void postorderTraversal(Node<E> node){
if(node==null) return;
postorderTraversal(node.left);
postorderTraversal(node.right);
System.out.println(node.element);
}

/**
* Medium order traversal
*/
public void inorderTraversal(){
inorderTraversal(root);
}
public void inorderTraversal(Node<E> node){
if(node==null) return;
inorderTraversal(node.left);
System.out.println(node.element);
inorderTraversal(node.right);
}

/**
* Preorder traversal
*/
public void preorderTraversal(){
preorderTraversal(root);
}
public void preorderTraversal(Node<E> node){
if(node==null) return;
System.out.println(node.element);
preorderTraversal(node.left);
preorderTraversal(node.right);
}
}

② Test:

public class Main {
public static void main(String[] args) {
test();
}

public static void test(){
BinarySearchTree<Integer> binarySearchTree = new BinarySearchTree<>();
int[] arr = {7, 4, 9, 2, 5, 8, 11, 3, 12, 1};
for(int i=0;i<arr.length;i++){
}
BinaryTrees.println(binarySearchTree);
binarySearchTree.preorderTraversal();
System.out.println();
binarySearchTree.inorderTraversal();
System.out.println();
binarySearchTree.postorderTraversal();
System.out.println();
binarySearchTree.levelOrderTraversal();
}
}

### 5. Design the interface of traversing binary tree

① In the original traversal method, after traversing the node, it is written directly, that is, the value of the node is printed directly. We can design an traversal interface and do some operations after traversing the node

public class BinarySearchTree<E> implements BinaryTreeInfo {

// Number of elements
private int size;

// Root node
private Node<E> root;

// comparator
private Comparator<E> comparator;

public BinarySearchTree(){

}

public BinarySearchTree(Comparator<E> comparator){
this.comparator = comparator;
}

/**
* Traversal interface of binary tree
*/
public static interface Visitor<E>{
void visit(E element);
}

/**
* level traversal
*/
public void levelOrderTraversal(Visitor<E> visitor){
if(root==null ) return;
queue.offer(root);
while (!queue.isEmpty()){
Node<E> node = queue.poll();
visitor.visit(node.element);
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
}
/**
* Subsequent traversal
*/
public void postorderTraversal(Visitor<E> visitor){
postorderTraversal(root,visitor);
}
public void postorderTraversal(Node<E> node,Visitor<E> visitor){
if(node==null || visitor==null) return;
postorderTraversal(node.left,visitor);
postorderTraversal(node.right,visitor);
visitor.visit(node.element);
}
/**
* Medium order traversal
*/
public void inorderTraversal(Visitor<E> visitor){
inorderTraversal(root,visitor);
}
public void inorderTraversal(Node<E> node,Visitor<E> visitor){
if(node==null) return;
inorderTraversal(node.left,visitor);
visitor.visit(node.element);
inorderTraversal(node.right,visitor);
}
/**
* Preorder traversal
*/
public void preorderTraversal(Visitor<E> visitor){
preorderTraversal(root,visitor);
}
public void preorderTraversal(Node<E> node,Visitor<E> visitor){
if(node==null) return;
visitor.visit(node.element);
preorderTraversal(node.left,visitor);
preorderTraversal(node.right,visitor);
}
}

② Test:

public class Main {
public static void main(String[] args) {
BinarySearchTree<Integer> binarySearchTree = new BinarySearchTree<>();
int[] arr = {7, 4, 9, 2, 5, 8, 11, 3, 12, 1};
for(int i=0;i<arr.length;i++){
}
BinaryTrees.println(binarySearchTree);

// Preorder traversal
binarySearchTree.preorderTraversal(new Visitor<Integer>() {
@Override
public void visit(Integer element) {
System.out.print("_"+element+"_");
}
});
System.out.println("Preorder traversal");
// Medium order traversal
binarySearchTree.inorderTraversal(new Visitor<Integer>() {
@Override
public void visit(Integer element) {
System.out.print("_"+element+"_");
}
});
System.out.println("Medium order traversal");
// Subsequent traversal
binarySearchTree.postorderTraversal(new Visitor<Integer>() {
@Override
public void visit(Integer element) {
System.out.print("_"+element+"_");
}
});
System.out.println("Postorder traversal");
// level traversal
binarySearchTree.levelOrderTraversal(new Visitor<Integer>() {
@Override
public void visit(Integer element) {
System.out.print("_"+element+"_");
}
});
System.out.println("level traversal ");
}
}
┌──7──┐
│     │
┌─4─┐ ┌─9─┐
│   │ │   │
┌─2─┐ 5 8   11─┐
│   │          │
1   3          12
_7__4__2__1__3__5__9__8__11__12_Preorder traversal
_1__2__3__4__5__7__8__9__11__12_Medium order traversal
_1__3__2__5__4__8__12__11__9__7_Postorder traversal
_7__4__9__2__5__8__11__1__3__12_level traversal

### 6. Enhance the traversal binary tree interface

Demand analysis: after printing to a node, the remaining nodes will not be printed

public class BinarySearchTree<E> implements BinaryTreeInfo {

// Number of elements
private int size;

// Root node
private Node<E> root;

/**
* Traversal interface of binary tree
*/
public static abstract class Visitor<E>{
boolean stop;
/**
* If it returns true, stop the traversal
*/
abstract boolean visit(E element);
}

/**
* level traversal
*/
public void levelOrderTraversal(Visitor<E> visitor){
if(root==null ) return;
queue.offer(root);
while (!queue.isEmpty()){
Node<E> node = queue.poll();
if(visitor.visit(node.element)) return;
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
}
}
/**
* Subsequent traversal
*/
public void postorderTraversal(Visitor<E> visitor){
if(visitor==null) return;
postorderTraversal(root,visitor);
}
public void postorderTraversal(Node<E> node,Visitor<E> visitor){
// Stop traversal when visitor=true
if(node==null || visitor.stop) return;
postorderTraversal(node.left,visitor);
postorderTraversal(node.right,visitor);

if(visitor.stop) return;
// Store the results of the currently traversed element. For example, when traversing to 4, visitor=true. When traversing down to the next element, it will not be printed
visitor.stop  = visitor.visit(node.element);
}
/**
* Medium order traversal
*/
public void inorderTraversal(Visitor<E> visitor){
if(visitor==null) return;
inorderTraversal(root,visitor);
}
public void inorderTraversal(Node<E> node,Visitor<E> visitor){
// When traversing the next element, judge stop. If stop=true, it indicates that printing needs to be stopped
if(node==null || visitor.stop) return;
inorderTraversal(node.left,visitor);
if(visitor.stop) return;
// Save the traversal results of the current element. When traversing the next element, judge stop. If stop=true, it means that printing needs to be stopped
visitor.stop = visitor.visit(node.element);
inorderTraversal(node.right,visitor);
}
/**
* Preorder traversal
*/
public void preorderTraversal(Visitor<E> visitor){
if(visitor==null) return;
preorderTraversal(root,visitor);
}
public void preorderTraversal(Node<E> node,Visitor<E> visitor){
if(node==null || visitor.stop) return;
visitor.stop = visitor.visit(node.element);
preorderTraversal(node.left,visitor);
preorderTraversal(node.right,visitor);
}
}

Test:

public class Main {
public static void main(String[] args) {
BinarySearchTree<Integer> binarySearchTree = new BinarySearchTree<>();
int[] arr = {7, 4, 9, 2, 5, 8, 11, 3, 12, 1};
for(int i=0;i<arr.length;i++){
}
BinaryTrees.println(binarySearchTree);

// Preorder traversal
binarySearchTree.preorderTraversal(new Visitor<Integer>() {
@Override
public boolean visit(Integer element) {
System.out.print("_"+element+"_");
return element==2 ? true : false;
}
});
System.out.println();
// Medium order traversal
binarySearchTree.inorderTraversal(new Visitor<Integer>() {
@Override
public boolean visit(Integer element) {
System.out.print("_"+element+"_");
return element==4 ? true : false;
}
});
System.out.println();
// Subsequent traversal
binarySearchTree.postorderTraversal(new Visitor<Integer>() {
@Override
public boolean visit(Integer element) {
System.out.print("_"+element+"_");
return element==4 ? true : false;
}
});
System.out.println();
// level traversal
binarySearchTree.levelOrderTraversal(new Visitor<Integer>() {
@Override
public boolean visit(Integer element) {
System.out.print("_"+element+"_");
return element==9 ? true : false;
}
});
System.out.println();
}
}

### 7. Find the height of binary tree

public class BinarySearchTree<E> implements BinaryTreeInfo {

// Number of elements
private int size;

// Root node
private Node<E> root;

/**
* Printing the height of a binary tree: a recursive method
*/
public int height(){
return height(root);
}
private int height(Node<E> node){
// If node is null, the level is 0
if(node==null) return 0;
return Math.max(height(node.left),height(node.right))+1;
}

/**
* Printing the height of a binary tree: an iterative method
*/
public int height1(){
if(root==null) return 0;
int levelSize = 1;
int height = 0;
while (!queue.isEmpty()){
Node<E> node = queue.poll();
// The number of elements in this layer is reduced by 1
levelSize--;