Binary Tree program

+- HP Forums (https://www.hpmuseum.org/forum)
+-- Forum: HP Software Libraries (https://www.hpmuseum.org/forum/forum-10.html)
+--- Forum: HP Prime Software Library (https://www.hpmuseum.org/forum/forum-15.html)
+--- Thread: Binary Tree program (/thread-24085.html)



Binary Tree program - Namir - 2025-09-22 08:45

Here is an HP Prime program (generated by Claude AI and needed some slight edits) that implements a binary tree structure using a global set of lists/arrays that store keys, data, and indices to left and right child nodes. After you run the program, you can view this information using the List option (Shift 7). You can run various programs to work with the binary tree:
1. TreeDemo performs a demo usage of the binary tree.
2. TreeInteractive is an interactive program that allows you to insert key/data information, delete nodes, print the binary tree, and so on.
3. TreeTest performs a comprhensive3 tree test.
4. TreeStats display the statistics of the binary tree.
5. TreePrint prints the nodes of the tree using indentation spaces.

The constant MAX_NODE specifies the maximum number of tree nodes and is currently set at 100.

I ran the code on my virtual emulator and not all PRINT command display results in the Terminal windows.

Save the list using a program name (e.g. binArrTree) and when you click on Run menu option you see the list of exported functions (including the ones i listed above). Click on the function you want to run.

Here is the code:

Code:
// HP Prime Binary Tree Implementation Using Global Arrays
// Maximum number of nodes that can be stored
EXPORT MAX_NODES := 100;

// Global variables for the binary tree
EXPORT NodeCount;     // Current number of nodes (0 = empty tree)
EXPORT nodeKeys;      // Array of strings for key values
EXPORT nodeData;      // Array of strings for data values
EXPORT nodeLeft;      // Array of integers for left child indices (0 = null)
EXPORT nodeRight;     // Array of integers for right child indices (0 = null)
EXPORT RootIndex;     // Index of root node (0 = empty tree)
EXPORT FreeList;      // List of available indices for reuse

// Initialize the binary tree data structures
EXPORT TreeInit()
BEGIN
  LOCAL i;
 
  NodeCount := 0;
  RootIndex := 0;
  FreeList := {};
 
  // Initialize arrays with empty values
  nodeKeys := {};
  nodeData := {};
  nodeLeft := {};
  nodeRight := {};
 
  // Pre-allocate arrays to MAX_NODES size
  FOR i FROM 1 TO MAX_NODES DO
    nodeKeys := CONCAT(nodeKeys, {""});
    nodeData := CONCAT(nodeData, {""});
    nodeLeft := CONCAT(nodeLeft, {0});
    nodeRight := CONCAT(nodeRight, {0});
  END;
 
  RETURN "Tree initialized with " + STRING(MAX_NODES) + " slots";
END;

// Get next available index for a new node
EXPORT GetAvailableIndex()
BEGIN
  LOCAL index;
 
  // Check if we can reuse a freed index
  IF SIZE(FreeList) > 0 THEN
    index := FreeList[1];
    FreeList := SUB(FreeList, 2, SIZE(FreeList));
    RETURN index;
  END;
 
  // Find first unused index
  FOR index FROM 1 TO MAX_NODES DO
    IF nodeKeys[index] == "" THEN
      RETURN index;
    END;
  END;
 
  RETURN 0; // No space available
END;

// Create a new node at the given index
EXPORT CreateNode(index, key, data)
BEGIN
  IF index <= 0 OR index > MAX_NODES THEN
    RETURN 0; // Invalid index
  END;
 
  IF nodeKeys[index] <> "" THEN
    RETURN 0; // Index already in use
  END;
 
  nodeKeys[index] := key;
  nodeData[index] := data;
  nodeLeft[index] := 0;
  nodeRight[index] := 0;
  NodeCount := NodeCount + 1;
 
  RETURN 1; // Success
END;

// Delete node at given index (mark as free)
EXPORT DeleteNodeAt(index)
BEGIN
  IF index <= 0 OR index > MAX_NODES THEN
    RETURN 0;
  END;
 
  IF nodeKeys[index] == "" THEN
    RETURN 0; // Already empty
  END;
 
  nodeKeys[index] := "";
  nodeData[index] := "";
  nodeLeft[index] := 0;
  nodeRight[index] := 0;
  NodeCount := NodeCount - 1;
 
  // Add to free list for reuse
  FreeList := CONCAT(FreeList, {index});
 
  RETURN 1; // Success
END;

// Check if index represents a valid node
EXPORT IsValidNode(index)
BEGIN
  IF index <= 0 OR index > MAX_NODES THEN
    RETURN 0;
  END;
 
  RETURN nodeKeys[index] <> "";
END;

// Insert a new key-data pair into the tree
EXPORT TreeInsert(key, data)
BEGIN
  LOCAL newIndex;
 
  IF RootIndex == 0 THEN
    // Tree is empty, create root
    newIndex := GetAvailableIndex();
    IF newIndex == 0 THEN
      RETURN "Error: Tree is full!";
    END;
   
    IF CreateNode(newIndex, key, data) THEN
      RootIndex := newIndex;
      RETURN "Inserted root: " + STRING(key) + " = " + STRING(data);
    ELSE
      RETURN "Error: Could not create root node";
    END;
  ELSE
    // Insert into existing tree
    RootIndex := InsertHelper(RootIndex, key, data);
    RETURN "Inserted: " + STRING(key) + " = " + STRING(data);
  END;
END;

// Helper function for recursive insertion
EXPORT InsertHelper(currentIndex, key, data)
BEGIN
  LOCAL newIndex;
 
  // Base case: create new node
  IF currentIndex == 0 THEN
    newIndex := GetAvailableIndex();
    IF newIndex == 0 THEN
      PRINT("Error: No space available for new node");
      RETURN 0;
    END;
   
    IF CreateNode(newIndex, key, data) THEN
      RETURN newIndex;
    ELSE
      RETURN 0;
    END;
  END;
 
  // Insert based on key comparison
  IF key < nodeKeys[currentIndex] THEN
    nodeLeft[currentIndex] := InsertHelper(nodeLeft[currentIndex], key, data);
  ELSE
    IF key > nodeKeys[currentIndex] THEN
      nodeRight[currentIndex] := InsertHelper(nodeRight[currentIndex], key, data);
    ELSE
      // Key already exists, update data
      nodeData[currentIndex] := data;
    END;
  END;
 
  RETURN currentIndex;
END;

// Search for a key in the tree
EXPORT TreeSearch(key)
BEGIN
  LOCAL foundIndex;
 
  IF RootIndex == 0 THEN
    RETURN "Tree is empty";
  END;
 
  foundIndex := SearchHelper(RootIndex, key);
 
  IF foundIndex == 0 THEN
    RETURN "Key '" + STRING(key) + "' not found";
  ELSE
    RETURN "Found: " + STRING(nodeKeys[foundIndex]) + " = " + STRING(nodeData[foundIndex]) + " at index " + STRING(foundIndex);
  END;
END;

// Helper function for recursive search
EXPORT SearchHelper(currentIndex, key)
BEGIN
  IF currentIndex == 0 OR NOT IsValidNode(currentIndex) THEN
    RETURN 0; // Not found
  END;
 
  IF key == nodeKeys[currentIndex] THEN
    RETURN currentIndex; // Found!
  ELSE
    IF key < nodeKeys[currentIndex] THEN
      RETURN SearchHelper(nodeLeft[currentIndex], key);
    ELSE
      RETURN SearchHelper(nodeRight[currentIndex], key);
    END;
  END;
END;

// Find minimum node in subtree
EXPORT FindMin(currentIndex)
BEGIN
  IF currentIndex == 0 THEN
    RETURN 0;
  END;
 
  WHILE nodeLeft[currentIndex] <> 0 DO
    currentIndex := nodeLeft[currentIndex];
  END;
 
  RETURN currentIndex;
END;

// Delete a node with the specified key
EXPORT TreeDelete(key)
BEGIN
  LOCAL oldRoot;
 
  IF RootIndex == 0 THEN
    RETURN "Tree is empty - cannot delete";
  END;
 
  oldRoot := RootIndex;
  RootIndex := DeleteHelper(RootIndex, key);
 
  // Check if deletion was successful
  IF SearchHelper(RootIndex, key) == 0 THEN
    RETURN "Deleted: " + STRING(key);
  ELSE
    RETURN "Key '" + STRING(key) + "' not found for deletion";
  END;
END;

// Helper function for recursive deletion
EXPORT DeleteHelper(currentIndex, key)
BEGIN
  LOCAL successorIndex, temp;
 
  IF currentIndex == 0 OR NOT IsValidNode(currentIndex) THEN
    RETURN 0; // Key not found
  END;
 
  IF key < nodeKeys[currentIndex] THEN
    nodeLeft[currentIndex] := DeleteHelper(nodeLeft[currentIndex], key);
  ELSE
    IF key > nodeKeys[currentIndex] THEN
      nodeRight[currentIndex] := DeleteHelper(nodeRight[currentIndex], key);
    ELSE
      // Node to delete found
     
      // Case 1: No left child
      IF nodeLeft[currentIndex] == 0 THEN
        temp := nodeRight[currentIndex];
        DeleteNodeAt(currentIndex);
        RETURN temp;
      ELSE
        // Case 2: No right child
        IF nodeRight[currentIndex] == 0 THEN
          temp := nodeLeft[currentIndex];
          DeleteNodeAt(currentIndex);
          RETURN temp;
        END;
      END;
     
      // Case 3: Two children
      successorIndex := FindMin(nodeRight[currentIndex]);
     
      // Copy successor's content to current node
      nodeKeys[currentIndex] := nodeKeys[successorIndex];
      nodeData[currentIndex] := nodeData[successorIndex];
     
      // Delete the successor
      nodeRight[currentIndex] := DeleteHelper(nodeRight[currentIndex], nodeKeys[successorIndex]);
    END;
  END;
 
  RETURN currentIndex;
END;

// In-order traversal of the tree
EXPORT TreeTraverse()
BEGIN
  LOCAL result;
 
  IF RootIndex == 0 THEN
    RETURN "Tree is empty";
  END;
 
  result := {};
  InOrderHelper(RootIndex, result);
 
  RETURN result;
END;

// Helper function for in-order traversal
EXPORT InOrderHelper(currentIndex, result)
BEGIN
  IF currentIndex <> 0 AND IsValidNode(currentIndex) THEN
    // Traverse left
    InOrderHelper(nodeLeft[currentIndex], result);
   
    // Visit current
    result := CONCAT(result, {{nodeKeys[currentIndex], nodeData[currentIndex]}});
   
    // Traverse right
    InOrderHelper(nodeRight[currentIndex], result);
  END;
END;

// Print the tree structure
EXPORT TreePrint()
BEGIN
  PRINT("Tree Structure:");
  PRINT("===============");
 
  IF RootIndex == 0 THEN
    PRINT("Tree is empty");
  ELSE
    PRINT("Root index: " + STRING(RootIndex));
    PrintTreeHelper(RootIndex, 0);
  END;
 
  PRINT("===============");
END;

// Helper function for printing tree structure
EXPORT PrintTreeHelper(currentIndex, indent)
BEGIN
  LOCAL spaces, i;
 
  IF currentIndex <> 0 AND IsValidNode(currentIndex) THEN
    // Print right subtree
    PrintTreeHelper(nodeRight[currentIndex], indent + 4);
   
    // Print current node with indentation
    spaces := "";
    FOR i FROM 1 TO indent DO
      spaces := spaces + " ";
    END;
   
    PRINT(spaces + STRING(nodeKeys[currentIndex]) + "(" + STRING(nodeData[currentIndex]) + ")[" + STRING(currentIndex) + "]");
   
    // Print left subtree
    PrintTreeHelper(nodeLeft[currentIndex], indent + 4);
  END;
END;

// Display tree statistics
EXPORT TreeStats()
BEGIN
  LOCAL usedNodes, i;
 
  usedNodes := 0;
  FOR i FROM 1 TO MAX_NODES DO
    IF nodeKeys[i] <> "" THEN
      usedNodes := usedNodes + 1;
    END;
  END;
 
  PRINT("Tree Statistics:");
  PRINT("================");
  PRINT("Nodes in use: " + STRING(usedNodes) + "/" + STRING(MAX_NODES));
  PRINT("NodeCount variable: " + STRING(NodeCount));
  PRINT("Root index: " + STRING(RootIndex));
  PRINT("Free indices available: " + STRING(SIZE(FreeList)));
  PRINT("Memory utilization: " + STRING(IP(1000 * usedNodes / MAX_NODES) / 10) + "%");
  PRINT("================");
END;

// Level-order traversal
EXPORT TreeLevelOrder()
BEGIN
  LOCAL queue, result, currentIndex, front;
 
  IF RootIndex == 0 THEN
    RETURN "Tree is empty";
  END;
 
  queue := {RootIndex};
  result := {};
 
  WHILE SIZE(queue) > 0 DO
    currentIndex := queue[1];
    queue := SUB(queue, 2, SIZE(queue));
   
    IF IsValidNode(currentIndex) THEN
      result := CONCAT(result, {{nodeKeys[currentIndex], nodeData[currentIndex], currentIndex}});
     
      IF nodeLeft[currentIndex] <> 0 THEN
        queue := CONCAT(queue, {nodeLeft[currentIndex]});
      END;
     
      IF nodeRight[currentIndex] <> 0 THEN
        queue := CONCAT(queue, {nodeRight[currentIndex]});
      END;
    END;
  END;
 
  RETURN result;
END;

// Display array contents for debugging
EXPORT DebugArrays()
BEGIN
  LOCAL i;
 
  PRINT("Array Contents (first 20 slots):");
  PRINT("=================================");
  PRINT("Idx | Key      | Data     | Left | Right");
  PRINT("----|----------|----------|------|------");
 
  FOR i FROM 1 TO MIN(20, MAX_NODES) DO
    IF nodeKeys[i] <> "" THEN
      PRINT(STRING(i) + "   | " + nodeKeys[i] + " | " + nodeData[i] + " | " + STRING(nodeLeft[i]) + "    | " + STRING(nodeRight[i]));
    END;
  END;
 
  PRINT("=================================");
 
  IF NodeCount > 20 THEN
    PRINT("... and " + STRING(NodeCount - 20) + " more nodes");
  END;
END;

// Comprehensive test function
EXPORT TreeTest()
BEGIN
  LOCAL i, pair, inOrderResult, item, afterDeleteResult;
  LOCAL levelOrderResult;
  PRINT("=== HP Prime Array-Based Binary Tree Test ===");
  PRINT("");
 
  // Test 1: Initialize tree
  PRINT("Test 1: Initialization");
  PRINT("----------------------");
  PRINT(TreeInit());
  TreeStats();
  PRINT("");
 
  // Test 2: Basic insertions
  PRINT("Test 2: Basic insertions");
  PRINT("------------------------");
  PRINT(TreeInsert("dog", "loyal pet"));
  PRINT(TreeInsert("cat", "independent"));
  PRINT(TreeInsert("bird", "flies"));
  PRINT(TreeInsert("fish", "swims"));
  PRINT(TreeInsert("elephant", "large mammal"));
  PRINT(TreeInsert("ant", "tiny insect"));
  PRINT(TreeInsert("zebra", "striped"));
  PRINT("");
 
  TreeStats();
  PRINT("");
 
  // Test 3: Search operations
  PRINT("Test 3: Search operations");
  PRINT("-------------------------");
  PRINT(TreeSearch("cat"));
  PRINT(TreeSearch("dog"));
  PRINT(TreeSearch("elephant"));
  PRINT(TreeSearch("unicorn")); // Not found
  PRINT("");
 
  // Test 4: Tree traversals
  PRINT("Test 4: Tree traversals");
  PRINT("-----------------------");
 
  inOrderResult := TreeTraverse();
  PRINT("In-order traversal:");
  FOR i FROM 1 TO SIZE(inOrderResult) DO
    pair := inOrderResult[i];
    PRINT("  " + STRING(pair[1]) + " : " + STRING(pair[2]));
  END;
  PRINT("");
 
  levelOrderResult := TreeLevelOrder();
  PRINT("Level-order traversal:");
  FOR i FROM 1 TO SIZE(levelOrderResult) DO
    item := levelOrderResult[i];
    PRINT("  " + STRING(item[1]) + " : " + STRING(item[2]) + " [index " + STRING(item[3]) + "]");
  END;
  PRINT("");
 
  // Test 5: Tree structure
  PRINT("Test 5: Tree structure");
  PRINT("----------------------");
  TreePrint();
  PRINT("");
 
  // Test 6: Array debugging
  PRINT("Test 6: Array contents");
  PRINT("----------------------");
  DebugArrays();
  PRINT("");
 
  // Test 7: Deletion operations
  PRINT("Test 7: Deletion operations");
  PRINT("---------------------------");
  PRINT(TreeDelete("cat"));
  PRINT(TreeDelete("elephant"));
  PRINT(TreeDelete("unicorn")); // Not found
  PRINT("");
 
  PRINT("Tree after deletions:");
  afterDeleteResult := TreeTraverse();
  FOR i FROM 1 TO SIZE(afterDeleteResult) DO
     pair := afterDeleteResult[i];
    PRINT("  " + STRING(pair[1]) + " : " + STRING(pair[2]));
  END;
  PRINT("");
 
  TreePrint();
  PRINT("");
 
  // Test 8: Test index reuse
  PRINT("Test 8: Index reuse after deletion");
  PRINT("-----------------------------------");
  PRINT(TreeInsert("bear", "omnivore"));
  PRINT(TreeInsert("rabbit", "herbivore"));
  PRINT("");
 
  DebugArrays();
  TreeStats();
  PRINT("");
 
  RETURN "All tests completed!";
END;

// Interactive tree operations
EXPORT TreeInteractive()
BEGIN
  LOCAL choice, key, data;
  LOCAL i, result, pair;
  PRINT("=== Interactive HP Prime Tree ===");
  TreeInit();
 
  REPEAT
    PRINT("");
    PRINT("1. Insert key-data pair");
    PRINT("2. Search for key");
    PRINT("3. Delete key");
    PRINT("4. Show tree structure");
    PRINT("5. Show traversal");
    PRINT("6. Show statistics");
    PRINT("7. Debug arrays");
    PRINT("0. Exit");
   
    INPUT(choice, "Enter choice (0-7):");
   
    CASE
      IF choice == 1 THEN
        INPUT(key, "Enter key:");
        INPUT(data, "Enter data:");
        PRINT(TreeInsert(key, data));
      END;
     
      IF choice == 2 THEN
        INPUT(key, "Enter key to search:");
        PRINT(TreeSearch(key));
      END;
     
      IF choice == 3 THEN
        INPUT(key, "Enter key to delete:");
        PRINT(TreeDelete(key));
      END;
     
      IF choice == 4 THEN
        TreePrint();
      END;
     
      IF choice == 5 THEN
        result := TreeTraverse();
        PRINT("Tree traversal:");
        FOR i FROM 1 TO SIZE(result) DO
          pair := result[i];
          PRINT("  " + STRING(pair[1]) + " : " + STRING(pair[2]));
        END;
      END;
     
      IF choice == 6 THEN
        TreeStats();
      END;
     
      IF choice == 7 THEN
        DebugArrays();
      END;
     
      DEFAULT
        // choice == 0 or invalid
    END;
   
  UNTIL choice == 0;
 
  RETURN "Interactive session ended";
END;

// Quick demo function
EXPORT TreeDemo()
BEGIN
  LOCAL i, result, pair;
  PRINT("=== Quick HP Prime Tree Demo ===");
 
  TreeInit();
 
  // Add some sample data
  TreeInsert("cherry", "small red fruit");
  TreeInsert("banana", "yellow fruit");
  TreeInsert("apple", "red fruit");
  TreeInsert("date", "sweet fruit");
  TreeInsert("elderberry", "purple berry");
 
  PRINT("");
  PRINT("Sample tree created:");
 
  result := TreeTraverse();
  FOR i FROM 1 TO SIZE(result) DO
    pair := result[i];
    PRINT(STRING(pair[1]) + " : " + STRING(pair[2]));
  END;
 
  PRINT("");
  TreePrint();
 
  PRINT("");
  PRINT("Search test:");
  PRINT(TreeSearch("banana"));
  PRINT(TreeSearch("grape")); // Not found
 
  TreeStats();
 
  RETURN "Demo completed!";
END;