You are on page 1of 17

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: parent
• label: LabelType
• left, right, parent: Node pointer left right

Tree = Node pointer A


label

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

T A

B C

D E F

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
...
}

1/17
In this case, root and T are two different pointers (two different arrows) which point to a
same node (i.e., root).
root
T
A

B C

D E F

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);
...
}

root
T
X

B C

D E F

2/17
However, if we change root, for example, make root point to another node, T rests
unchanged!

void foo(Tree root) {


root = (Tree)malloc(sizeof(Node));
...
}

int main() {
Tree T;
T = buildATree(); //Build a tree and
//let T point to the root of the tree
foo(T);
...
}

root

T
A
x

A C

D E F

3/17
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.

(*pT) pT

T
A

A C

D E F

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

4/17
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

}

(*pT) pT (*pT) pT

T T
A NULL

A C

D E F

Before After

5/17
If we try to pass T as value, the result is not what we want.

void makeNull(Tree root) {


root = NULL;
}

int main() {
Tree T;
T = buildATree(); //Build a tree and
//let T point to the root of the tree
makeNull(T); //Pass value of T to root
...
}

root root

T T
A A
NULL

A C A C

D E F D E F

Before After

6/17
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.

7/17
insert 7

1
0
parent
5 2
0

4 8 1
5
1 1
4 8
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;

8/17
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
Node *node = *pT, *parent;
while (node != NULL) {
parent = node;
if (x == node->label) break;
if (x < node->label)
node = node->left;
else
node = node->right;
}
if (x == parent->label) return; //x existed in T

//2b. Insert a new node


Node *child = (Node)malloc(sizeof(Node));
child->label = x;
if (x < parent)
parent->left = child;
else
parent->right = child;
}

b. Using recursion
Recursive version is a bit difficult to understand in compared to loop version, but it’s very
compact and clean. 😉

Just compare x to label of the root (i.e., (*pT)->label) and use recursion
If x == (*pT)->label => return
If x < ((*pT)->label) => recursively insert x into the left subtree of (*pT)
else => recursively insert x into the right subtree of (*pT)

The left subtree of (*pT) is (*pT)->left.


So, we will pass the address of the left subtree: &((*pT)->left).

9/17
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;

//2b. x < (*pT)->label => recursively insert to left subtree


if (x == (*pT)->label)
insert(x, &((*pT)->left));

//2c. x > (*pT)->label => recursively insert to right subtree


else
insert(x, &((*pT)->right));
}

10/17
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.

11/17
delete 8
parent
1
0
node
5 2
0

4 8 1
5
1 1
4 8
To delete the node “node”, there are 3 cases to consider:

Case 1: “node” has no child


• Set parent->left or parent->right to NULL. If parent is NULL, the node to be deleted is
root.

if (parent == NULL)
*pT = NULL; //Tree has only one node
else if (node == parent->left)
parent->left = NULL;
else
parent->right = NULL;

Case 2: “node” has two children


• Delete the smallest node in the right subtree of “node”
• Copy label of the deleted node to node->label

node->label = deleteMin(&(node->right));

12/17
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;

13/17
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;

14/17
b. Using recursion
Instead of using loop to find the node to be deleted, we compare x to (*pT)->label and
recursively delete x from the left subtree or the right subtree.

if (*pT == NULL) => return


if (x < (*pT)->label)
delete x from the left subtree
else if (x > (*pT)->label)
delete x from the right subtree
else {
//*pT is the node to be deleted
Case 1
Case 2
Case 3
}

void delete(LabelType x, Tree *pT) {


if ((*pT) == NULL) return;

if (x < (*pT)->label) //delete x from the left subtree


delete(x, &((*pT)->left));
else if (x > (*pT)->label) //delete x from the right subtree
delete(x, &((*pT)->right));
else {

//*pT is the node to be deleted


Case 1
if ((*pT)->left == NULL && (*pT)->right == NULL) {
*pT == NULL;
return;
}

Case 2: *pT has two children


if ((*pT)->left != NULL && (*pT)->right != NULL) {
(*pT)->label = deleteMin(&((*pT)->right));
return;
}

Case 3: *pT has only one child


Node *child;
if ((*pT)->left == NULL) child = (*pT)->right;
else child = (*pT)->left;

(*pT) = child;
}
}

15/17
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;
}

16/17
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));
}

17/17

You might also like