Lecture 27 Trees

Joseph Haugh

University of New Mexico

Free Recall

Review Question 1

What is the purpose of the malloc function in C?

  1. To de-allocate memory
  2. To allocate memory dynamically
  3. To initialize a pointer
  4. To free memory

Review Question 1

What is the purpose of the malloc function in C?

  1. To allocate memory dynamically

Review Question 2

Which operator is used to access the members of a struct through a pointer?

  1. .
  2. *
  3. &
  4. ->

Review Question 2

Which operator is used to access the members of a struct through a pointer?

  1. ->

Review Question 3

What is the time complexity of inserting a node at the beginning of a singly linked list?

  1. O(1)
  2. O(n)
  3. O(log n)
  4. O(n^2)

Review Question 3

What is the time complexity of inserting a node at the beginning of a singly linked list?

  1. O(1)

Review Question 4

What happens if you try to access memory that has already been freed using free?

  1. The program will crash
  2. The memory will be reallocated
  3. The behavior is undefined
  4. Nothing, it is a valid operation

Review Question 4

What happens if you try to access memory that has already been freed using free?

  1. The behavior is undefined

Review Question 5

What is the output of the following code snippet?

int x = 5;
int *p = &x;
printf("%d", *p);

5

Review Question 6

struct Person {
    char name[20];
    int age;
};

struct Person p1 = {"John", 25};
printf("%s", p1.name);

John

Review Question 7

int *p = (int *)malloc(sizeof(int));
*p = 10;
printf("%d", *p);
free(p);

10

Review Question 8

struct Node {
    int data;
    struct Node *next;
};

struct Node *head = NULL;
printf("%p", head);

(nil)

Review Question 9

int arr[] = {1, 2, 3, 4, 5};
int *ptr = arr;
printf("%d", *(ptr + 2));

3

Review Question 10

char str[] = "Hello";
char *ptr = str;
ptr++;
printf("%c", *ptr);

e

Review Question 11

int x = 10;
int y = 20;
int *ptr1 = &x;
int *ptr2 = &y;
int temp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = temp;
printf("%d %d", x, y);

20 10

Review Question 12

struct Point {
    int x;
    int y;
};

struct Point p1 = {1, 2};
struct Point *ptr = &p1;
printf("%d", ptr->y);

2

Review Question 13

int *ptr = (int *)malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++) {
    *(ptr + i) = i;
}
printf("%d", *(ptr + 3));
free(ptr);

3

Review Question 14

struct Node {
    int data;
    struct Node *next;
};

struct Node *head = NULL;
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = 5;
new_node->next = NULL;
head = new_node;
printf("%d", head->data);

5

Binary Tree: Kernighan and Ritchie 6.5

Read a file and count the occurrences of each word.

now is the time for all good men to come to the aid of their party

Adding Node to Ordered Tree

If a node were added with the word “hello”, where would it be placed?

Binary Tree: tnode

The structure, tnode, is used for each node of the binary tree.

struct tnode {
    char *word;
    int count;
    struct tnode *left;
    struct tnode *right;
};

This is called a self-referential structure since it contains pointers to other tnodes.

An instance of this struct allocates space for a pointer to a char array, an int, and two pointers to other tnodes. On my 64-bit address machine, this is a total of 8 + 4 + 8 + 8 = 28 bytes.

Binary Tree: talloc (NOT a Library Function)

  1. Allocate memory for a tree node.

  2. In this binary tree, nodes are added to leaves. Thus, initialize the node’s children to NULL.

  3. Call strCopyMalloc to allocate space for the word and to copy it from the input buffer into the allocated space.

struct tnode *talloc(char *newWord) {
    struct tnode *node = malloc(sizeof(struct tnode));
    node->word = strCopyMalloc(newWord);
    node->left = NULL;
    node->right = NULL;
    node->count = 1;
    return node;
}

Binary Tree: strCopyMalloc

  1. Allocated memory for a copy of newWord.

  2. Copy each character from newWord into the allocated block.

  3. Return a pointer to the start of the allocated block.

char *strCopyMalloc(char *source) {
    char *sink;
    sink = malloc(strlen(source) + 1);
    if (sink != NULL) strcpy(sink, source);
    return sink;
}

Binary Tree: Memory Leaks

In Kernighan and Ritchie’s binary tree, memory is allocated and never freed!

MEMORY LEAK WARNING: DO NOT free a node until:

  • Its children have been freed, or pointers to its children have been saved somewhere else.

  • Its word has been freed.

struct tnode *root;
root = talloc("Memory");
root->right = talloc("Leak");
root->left = talloc("Bad");
free(root); /* Leaves "unreachable" memory. */

Binary Tree: freeSubTree

Recursive function that frees all allocated memory in a subtree.

void freeSubtree(struct tnode *node) {
    if (node == NULL) return;
    freeSubtree(node->left);
    freeSubtree(node->right);
    free(node->word);
    free(node);
}

Any references to node (such as would be in node’s parent) MUST NOT BE USED AFTER calling this. Best practice is to set such references to NULL.

Binary Tree: Simple Test Case

This main() demonstrates usage and offers a simple test of creating, setting, printing, and freeing tnode.

void main(void) {
    struct tnode *root;
    root = talloc("geralt");
    root->left = talloc("ciri");
    root->right = talloc("yen");
    printf("node: %s (L)=%s, (R)=%s\n", root->word,
           root->left->word, root->right->word);
    freeSubtree(root);
    root = NULL; /* "Best practice" */
}

Tree Traversal

  • Depth First: Explore as far as possible along each branch before backtracking
    • Pre-order – Root, left subtree, right subtree
    • In-order – Left subtree, root, right subtree
    • Post-order – Left subtree, right subtree, root
  • Breadth First: Visit every node on a level before going to lower level. (Also known as level-order)

Tree Traversal – Example

Pre-Order: Root, then children:

now is for all aid come good men the of party time their to

Tree Traversal – Example

In-Order: Left, root, right:

aid all come for good is men now of party the their time to

Tree Traversal – Example

Post-Order: Children, then root:

aid come all good for men is party of their to time the now

Tree Traversal – Example

Breadth-first: One level at a time:

now is the for men of time all good party their to aid come

Tree Traversal – Code

void treeprint(struct tnode *node)
{
   if(node != NULL)
   {
       treeprint(node->left);
       printf("%4d %s\n", node->count, node->word);
       treeprint(node->right);
   }
}

What sort of traversal happens here?

How could we traverse the tree in a different order?

Breadth-first Traversal Algorithm

  1. Create a queue to hold tree nodes

  2. Add root node to the queue

  3. While queue is not empty:

    • Remove node from queue and visit it.
    • Add node’s children to queue.

A queue is a FIFO structure. How might we implement it?

A stack is a LIFO structure. What would happen if we replaced the queue with a stack?