Binary Search Tree Operations: Pointer-Based Implementation, Cheat Sheet of Information Technology

Comprehensive notes on binary search tree operations using a pointer-based implementation. It covers essential concepts such as node structure, tree representation, and methods for passing trees to functions. Detailed explanations and code snippets illustrate key operations like makenull, insert, and delete, including both iterative and recursive approaches. The notes also address the intricacies of deleting the smallest node from the tree, making it a valuable resource for understanding and implementing binary search trees. Useful for university students.

Typology: Cheat Sheet

2023/2024

Uploaded on 10/21/2025

nguyen-cao-tri-b2409019
nguyen-cao-tri-b2409019 🇸🇬

1 document

1 / 17

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
1/17
Notes on Binary Search Tree operations (pointer – based implementation)
By Phm Nguyên Khang
Attention: It is just the idea. You must check yourself the below code.
1. Introduction
Node = struct of members:
label: LabelType
left, right, parent: Node pointer
Tree = Node pointer
Tree T;
T = buildATree(); //Build a tree and let T point to the root of the tree
Two ways to pass a tree to a function as parameters:
Pass as a value
Pass as an address
a. Pass a tree as a value
void foo(Tree root) {
//Do something
}
int main() {
Tree T;
T = buildATree(); //Build a tree and
//let T point to the root of the tree
foo(T); //Pass value of T (address of node) to root
...
}
left
right
A
label
parent
A
B
C
D
E
F
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff

Partial preview of the text

Download Binary Search Tree Operations: Pointer-Based Implementation and more Cheat Sheet Information Technology in PDF only on Docsity!

Notes on Binary Search Tree operations (pointer – based implementation)

By Phạm Nguyên Khang

Attention: It is just the idea. You must check yourself the below code.

1. Introduction

Node = struct of members:

  • label: LabelType
  • left, right, parent: Node pointer

Tree = Node pointer

Tree T;

T = buildATree(); //Build a tree and let T point to the root of the tree

Two ways to pass a tree to a function as parameters:

  • Pass as a value
  • Pass as an address

a. Pass a tree as a value

void foo(Tree root) { //Do something } int main() { Tree T; T = buildATree(); //Build a tree and //let T point to the root of the tree foo(T); //Pass value of T (address of node) to root ... }

left right

A

label

parent

A

B C

D E F

T

In this case, root and T are two different pointers (two different arrows) which point to a

same node (i.e., root).

Because T and root point to the same node, if we change the content of the node using

root, for example, make set the label of the node to ‘X’, T->label will change.

void foo(Tree root) { root->label = ‘X’; ... } int main() { Tree T; T = buildATree(); //Build a tree and //let T point to the root of the tree foo(T); ... } A B C D E F

T

root

X B C D E F

T

root

b. Pass a tree as an address

“ Address can be considered as another name (alias) of a variable. ”

void foo( *Tree pT ) { //Do something } int main() { Tree T; T = buildATree(); //Build a tree and //let T point to the root of the tree foo( &T ); //Pass address of T to pT … }

Now, pT and T are different pointers but T and (*pT) are the same pointer. So, we can say

that (*pT) is another name of T.

If we change (*pT), T will change!

A

pT

T

A C D E F

(*pT)

1. makeNull(T) – makes T be an empty tree

In this function, we want to make the pointer T point to NULL. So we must change T in the

makeNull() function. There is only one way to do this, that is passing T by address!

void makeNull( Tree pT ) { (pT) = NULL; } int main() { Tree T; T = buildATree(); //Build a tree and //let T point to the root of the tree makeNull( &T ); //Pass address of T to root … }

Before After

A

pT

T

A C D E F

(*pT) pT

T

(*pT)

NULL

2. insert(x, T) – inserts x into tree T

  • If T is a null tree (a null pointer), inserting a new node makes T point to the new

node. Therefore, T must be changed.

  • If T is not null, inserting a new node will change the content of some node.

So, T must be passed by address!

void insert(LabelType x, *Tree pT ) { Case 1: If pT is a null tree, if (pT == NULL) { //1a. create a node, Node root = (Node)malloc(sizeof(Node); //1b. place x and root->label = x; //1c. make pT point to the new node (pT) = root; return; } Case 2: //2a. Find a right position to insert //2b. Insert a new node }

Find a right position to insert x into tree T, can be done by loop or recursion.

a. Using loop

We start from root of T (i.e., *pT).

Node *node = *pT;

Loop until node is NULL (we left the tree) or node contains x. In the loop we compare x to

node->label and go left or right according to comparison result.

while (node != NULL) { parent = node if x == node->label => break if x < node->label node = node->left else node = node->right }

When the loop finishes, “parent” is the last node we meet before leaving the tree.

Depending on relation between x and parent->label, we will insert x into the left or the right

of parent.

If x = parent->label, x has been existed in T, just return.

The next step is to create a new node, place x, and set parent->left or parent->right point to

the new node.

Node child = (Node)malloc(sizeof(Node)); child->label = x; if (x < parent) parent->left = child; else parent->right = child; 1 0 5 1 5 2 0 4 8 1 4 1 8

insert 7

parent

void insert(LabelType x, Tree pT ) { Case 1: If pT is a null tree, if (pT == NULL) { //1a. create a node, Node root = (Node)malloc(sizeof(Node); //1b. place x and root->label = x; //1c. make pT point to the new node (pT) = root; return; } Case 2: Compare x to (pT)->label //2a. x == (pT)->label if (x == (pT)->label) return; // 2 b. x < (pT)->label => recursively insert to left subtree if (x == (pT)->label) insert(x, &((pT)->left)); // 2 c. x > (pT)->label => recursively insert to right subtree else insert(x, &((*pT)->right)); }

3. delete(x, T) – deletes x from tree T

  • If the deleted node is root, T must be changed.
  • Otherwise, we change the content of some node.

So, T must be passed by address!

void delete(LabelType x, *Tree pT ) { Step 1 : find the node content x Step 2: delete the node and adjust the tree }

Suppose *pT is not empty (if *pT is empty just do nothing).

Find the node content x can be done by loop or recursion.

a. Using loop

We will find the node containing x and its parent.

We start from root of T (i.e., *pT).

Node *node = *pT;

Loop until node is NULL (we left the tree) or node contains x. In the loop we compare x to

node->label and go left or right according to comparison result.

Node *parent = NULL; while (node != NULL) { if (x == node->label) break; parent = node; if (x < node->label) node = node->left; else node = node->right; }

When the loop finishes, if node == NULL, x does not appear in T, just return.

Otherwise, x == node->label and “parent” is the parent of node.

Case 3 : “node” has one child

  • Take the unique child of “node”
  • Set parent->left or parent->right to the child. Beware of the case parent == NULL. Node child; if (node->left == NULL) child = node->right; else child = node->left; if (parent == NULL) (pT) = child; else if (node == parent->left) parent->left = child; else parent->right = child;

void delete(LabelType x, Tree pT ) { if ((pT) == NULL) return; Step 1 : find the node containing x Node *node = *pT, parent; while (node != NULL) { if (x == node->label) break; parent = node; //keep parent before moving node if (x < node->label) node = node->left; else node = node->right; } if (node == NUL) return; //x does not appear in tree Step 2: delete the node and adjust the tree Case 1: node has no child if (node->left == NULL && node->right == NULL) { if (parent == NULL) (pT) = NULL; else if (node == parent->left) parent->left = NULL; else parent->right = NULL; return; } Case 2 : node has two children if (node->left != NULL && node->right != NULL) { node->label = deleteMin(&(node->right)); return; } Case 3 : node has only one child Node child; if (node->left == NULL) child = node->right; else child = node->left; if (parent == NULL) (pT) = child; else if node = parent->left) parent->left = child; else parent->right = child; }

4. deleteMin(T) – deletes the smallest node from T (T is not empty)

LabelType deleteMin( *Tree pT ) { Step 1: find the smallest node Step 2 : delete it }

a. Using loop

To find the smallest node, from the root, we go left until node->left == NULL. We must also

keep the parent of the node.

Node *node = *pT; Node *parent = NULL; while (node->left != NULL) { parent = node; node = node->left; }

Because node->left == NULL (as case 3 in delete function), we will set parent->left or parent-

>right to node->right.

LabelType deleteMin( *Tree pT ) { Step 1: find the smallest node Node *node = *pT; Node parent = NULL; while (node->left != NULL) { parent = node; node = node->left; } Step 2 : delete it, and return its label if (parent == NULL) //node to be delete is the root (pT) = node->right; else if (node == parent->left) parent->left = node->right; else parent->right = node->right; return node->label; }

b. Using recursion

  • If (pT)->left != NULL, (pT) is the node to be delete
  • Otherwise, recursively delete the left subtree LabelType deleteMin( Tree pT ) { Case 1 : if (pT) has no left child if ((pT)->left == NULL) { LabelType label = (pT)->label; (pT) = (pT)->right; return label; } Case 2: return deleteMin(&((*pT)->left)); }