Tutorial 9
🌴
Binary Search Tree
9618 A-Level
i
For binary trees, the following operations are required for A2: insert, search and traverse (pre-order, in-order, post-order). Removing nodes isn't required
It may be useful to search (CTRL + F) for "binary tree" questions in the (combined) past papers
If you find any bugs/edge cases in this code, please contact me
1
Binary Search Tree
Below shows the full code for an ordered linked list
TYPE Node
DECLARE leftPointer, rightPointer, data : INTEGER
ENDTYPE
DECLARE tree : ARRAY[1:9] OF Node
DECLARE rootPointer, freePointer : INTEGER
CALL InitialiseTree()
CALL InsertNode(5)
CALL InsertNode(3)
CALL InsertNode(6)
CALL InsertNode(2)
CALL InsertNode(8)
CALL InsertNode(4)
CALL InsertNode(1)
CALL InsertNode(9)
CALL InsertNode(7)
//populate with random values instead
// FOR n ← 1 TO 9
// CALL InsertNode(INT(RAND(9) + 1))
// NEXT n
OUTPUT Search(3)
OUTPUT Search(2)
OUTPUT Search(0)
OUTPUT Search(7)
OUTPUT RecursiveSearch(3, rootPointer)
OUTPUT RecursiveSearch(2, rootPointer)
OUTPUT RecursiveSearch(0, rootPointer)
OUTPUT RecursiveSearch(7, rootPointer)
CALL DisplayNodeArray()
OUTPUT "---InOrderTraversal ---"
CALL InOrderTraversal(rootPointer)
OUTPUT "---PreOrderTraversal ---"
CALL PreOrderTraversal(rootPointer)
OUTPUT "---PostOrderTraversal ---"
CALL PostOrderTraversal(rootPointer)
CALL DrawTree()
PROCEDURE InitialiseTree()
rootPointer ← -1 //empty tree
freePointer ← 1 //set start of free list to add new nodes frmo
DECLARE index : INTEGER
//each node in free list (except last) should point to next node
FOR index ← 1 TO LENGTH(tree) - 1
tree[index].leftPointer ← index + 1
NEXT index
//last node should point to null pointer
tree[LENGTH(tree)].leftPointer ← -1
ENDPROCEDURE
PROCEDURE InsertNode(data : INTEGER)
DECLARE newNodePointer, currentPointer, previousPointer : INTEGER
DECLARE turnedLeft : BOOLEAN
//if tree not full
IF freePointer <> -1 THEN
newNodePointer ← freePointer //get pointer of node to add
freePointer ← tree[freePointer].leftPointer //since we initialised the leftPointer as pointing to next node, use this to update freePointer to point to next node
//insert new node data - assume it's a leaf node - pointers will be updated in subsequent code if not
tree[newNodePointer].data ← data
tree[newNodePointer].leftPointer ← -1
tree[newNodePointer].rightPointer ← -1
//if empty
IF rootPointer = -1 THEN
rootPointer ← newNodePointer //set root node
ELSE
//find insert position
currentPointer ← rootPointer
WHILE currentPointer <> -1 DO
previousPointer ← currentPointer //store previousPointer - will be used to point to new node if correct position
//data less that current node's data, go left
IF data < tree[currentPointer].data THEN
turnedLeft ← TRUE
currentPointer ← tree[currentPointer].leftPointer //go left
ELSE
turnedLeft ← FALSE
currentPointer ← tree[currentPointer].rightPointer //go right
ENDIF
ENDWHILE
//found correct position to insert
//update left or right pointer accordingly
IF turnedLeft = TRUE THEN
tree[previousPointer].leftPointer ← newNodePointer
ELSE
tree[previousPointer].rightPointer ← newNodePointer
ENDIF
ENDIF
ENDIF
ENDPROCEDURE
FUNCTION Search(data : INTEGER) RETURNS BOOLEAN
DECLARE currentPointer : INTEGER
currentPointer ← rootPointer //start searching from root
//while valid node
WHILE currentPointer <> -1 DO
//if found
IF data = tree[currentPointer].data THEN
RETURN TRUE
ELSE
//check direction to travel
IF data < tree[currentPointer].data THEN
currentPointer ← tree[currentPointer].leftPointer
ELSE
currentPointer ← tree[currentPointer].rightPointer
ENDIF
ENDIF
ENDWHILE
//if not found, then value doesn't exist - hence return false
RETURN FALSE
ENDFUNCTION
FUNCTION RecursiveSearch(data : INTEGER, currentPointer : INTEGER) RETURNS BOOLEAN
//base case - reached null pointer and not found item - hence return false
IF currentPointer = -1 THEN
RETURN FALSE
ELSE
//base case - found item
IF data = tree[currentPointer].data THEN
RETURN TRUE
ELSE
//general case - search correct sub-tree
IF data < tree[currentPointer].data THEN
RETURN RecursiveSearch(data, tree[currentPointer].leftPointer)
ELSE
RETURN RecursiveSearch(data, tree[currentPointer].rightPointer)
ENDIF
ENDIF
ENDIF
ENDFUNCTION
//output nodes in ascending order
PROCEDURE InOrderTraversal(currentPointer : INTEGER)
//prevents empty tree giving an array index out of bounds error
IF currentPointer <> -1 THEN
//if left pointer doesn't point to leaf node, then traverse
IF tree[currentPointer].leftPointer <> -1 THEN
CALL InOrderTraversal(tree[currentPointer].leftPointer)
ENDIF
OUTPUT tree[currentPointer].data
//if right pointer doesn't point to leaf node, then traverse
IF tree[currentPointer].rightPointer <> -1 THEN
CALL InOrderTraversal(tree[currentPointer].rightPointer)
ENDIF
ENDIF
ENDPROCEDURE
//outputs nodes in order they were visited
PROCEDURE PreOrderTraversal(currentPointer : INTEGER)
//prevents empty tree giving an array index out of bounds error
IF currentPointer <> -1 THEN
OUTPUT tree[currentPointer].data
//if left pointer doesn't point to leaf node, then traverse
IF tree[currentPointer].leftPointer <> -1 THEN
CALL PreOrderTraversal(tree[currentPointer].leftPointer)
ENDIF
//if right pointer doesn't point to leaf node, then traverse
IF tree[currentPointer].rightPointer <> -1 THEN
CALL PreOrderTraversal(tree[currentPointer].rightPointer)
ENDIF
ENDIF
ENDPROCEDURE
//outputs nodes in order they are fully visited (i.e. both left and right subtrees)
PROCEDURE PostOrderTraversal(currentPointer : INTEGER)
//prevents empty tree giving an array index out of bounds error
IF currentPointer <> -1 THEN
//if left pointer doesn't point to leaf node, then traverse
IF tree[currentPointer].leftPointer <> -1 THEN
CALL PostOrderTraversal(tree[currentPointer].leftPointer)
ENDIF
//if right pointer doesn't point to leaf node, then traverse
IF tree[currentPointer].rightPointer <> -1 THEN
CALL PostOrderTraversal(tree[currentPointer].rightPointer)
ENDIF
OUTPUT tree[currentPointer].data
ENDIF
ENDPROCEDURE
//helped procedure to output array details - for understanding/debugging
PROCEDURE DisplayNodeArray()
DECLARE index : INTEGER
OUTPUT "---DisplayNodeArray --- \n"
//left, right, data
OUTPUT " L | R | D"
FOR index ← 1 TO LENGTH(tree)
OUTPUT " ", tree[index].leftPointer, " | ", tree[index].rightPointer, " | ", tree[index].data
NEXT index
OUTPUT ""
ENDPROCEDURE
//additional procedures - not required for exam. Just helps visualise the tree :)
PROCEDURE DrawTree()
CALL CREATECANVAS("tree", 500, 500)
CALL DrawNode(rootPointer, 1, 0)
ENDPROCEDURE
PROCEDURE DrawNode(currentPointer, yLevel, xLevel : INTEGER)
//prevents empty tree giving an array index out of bounds error
IF currentPointer <> -1 THEN
DECLARE x, y : INTEGER
x ← 250 + (xLevel * 60)
y ← 50 + (yLevel * 60)
CALL DRAWTEXT("tree", NUM_TO_STR(tree[currentPointer].data), "center", x, y, 20, "Arial", "white", "white", 1)
IF tree[currentPointer].leftPointer <> -1 THEN
CALL DRAWLINE("tree", x, y + 5, x - 50, y + 42, "white", 2)
CALL DrawNode(tree[currentPointer].leftPointer, yLevel + 1, xLevel - 1)
ENDIF
IF tree[currentPointer].rightPointer <> -1 THEN
CALL DRAWLINE("tree", x, y + 5, x + 50, y + 42, "white", 2)
CALL DrawNode(tree[currentPointer].rightPointer, yLevel + 1, xLevel + 1)
ENDIF
ENDIF
ENDPROCEDURE
Extension details/answers will be added: