Advanced Pointers and Structures Pointers in structures Memory

  • Slides: 32
Download presentation
Advanced Pointers and Structures • Pointers in structures • Memory allocation • Linked Lists

Advanced Pointers and Structures • Pointers in structures • Memory allocation • Linked Lists – Stacks and queues • Trees – Binary tree example

Structs which contain themselves • Sometimes programmers want structs in C to contain themselves.

Structs which contain themselves • Sometimes programmers want structs in C to contain themselves. • For example, we might design an electronic dictionary which has a struct for each word and we might want to refer to synonyms which are also word structures. word 2: sprint synonym 1 synonym 2 word 1: run synonym 1 synonym 2 word 3: jog synonym 1 synonym 2

How structs can contain themselves • Clearly a struct cannot literally contain itself. struct

How structs can contain themselves • Clearly a struct cannot literally contain itself. struct silly_struct { /* This doesn't work */ … struct silly_struct s 1; }; • But it can contain a pointer to the same type of struct good_struct { /* This does work */ … struct *good_struct s 2; };

Memory allocation • How to allocate memory dynamically? – void *malloc(unsigned int); – Example:

Memory allocation • How to allocate memory dynamically? – void *malloc(unsigned int); – Example: char *str; str = malloc(80); Now str can hold up to 80 Bytes.

Freeing memory To free memory that was allocated using malloc we use free function.

Freeing memory To free memory that was allocated using malloc we use free function. free returns the memory pointed by a given pointer to the OS. free(pointer) pointer = NULL:

The linked list - a common use of structs which contain themselves • Imagine

The linked list - a common use of structs which contain themselves • Imagine we are reading lines from a file but don't know how many lines will be read. • We need a structure which can extend itself. This is known as a linked list. By passing the value of the head of the list to a function we can pass ALL the information.

How to set up a linked list typedef struct list_item { information in each

How to set up a linked list typedef struct list_item { information in each item struct list_item *nextptr; } LIST_ITEM; This structure (where information is what you want each "node" of your linked list to contain). It is important that the nextptr of the last bit of the list contains NULL so that you know when to stop. head of NULL list

Example -- Address book typedef struct list { char name[MAXLEN]; char address[MAXLEN]; char phone[MAXLEN];

Example -- Address book typedef struct list { char name[MAXLEN]; char address[MAXLEN]; char phone[MAXLEN]; struct list *next; } ADDRESS; ADDRESS *myabook= NULL; /* Set the head of the list */

Linked list concepts head of list NULL Adding an item to the middle of

Linked list concepts head of list NULL Adding an item to the middle of the list head of list NULL move this link head of list new item points at next item Deleting an item from the middle of the list move this link NULL delete this node

Stacks and Queues • Stacks use push and pop – Push add a node

Stacks and Queues • Stacks use push and pop – Push add a node at the head of a linked list. – Pop remove the head node • Queues – Adding nodes at the head of the list – Removing nodes at the end of a list • So we need 2 pointers, one for the head and one for the tail.

Tree • A tree is a method for data (for example a dictionary of

Tree • A tree is a method for data (for example a dictionary of words) where we wish to easily be able to add items and find items • Each element in the tree can lead to two (or more) further elements. struct Tree. Node {. . . Data part Tree. Node* child 1; Tree. Node* child 2; . . . };

Binary Tree – Structure Example • A binary tree is a data “structure” •

Binary Tree – Structure Example • A binary tree is a data “structure” • The basic data structure is a node which includes: – The data contained in that node – Pointers to two children nodes (left and right) • 2 pointers == binary • Left node pointer points to a node with data that is less than the current node • Right node pointer points to a node with data that is greater than the current node • All nodes to the left contain data less • All nodes to the right contain data greater – A leaf node is a node with no children

Binary Tree: Adding a node • Simply add a leaf to the tree. –

Binary Tree: Adding a node • Simply add a leaf to the tree. – Add 20 10 8 5 10 30 8 40 5 30 20 40

Binary Tree 10 8 5 30 20 40 • All nodes on the left

Binary Tree 10 8 5 30 20 40 • All nodes on the left are less than 10 and all on the right are greater than 10 • Add 15?

Binary Tree 10 8 30 5 20 40 15 • All nodes on the

Binary Tree 10 8 30 5 20 40 15 • All nodes on the left are less than 10 and all on the right are greater than 10 • Add the value 9?

Insert 10 8 5 30 9 20 40 15 • All nodes on the

Insert 10 8 5 30 9 20 40 15 • All nodes on the left are less than 10 and all on the right are greater than 10 • Add 25?

Insert 10 8 5 30 9 20 15 40 25 • All nodes on

Insert 10 8 5 30 9 20 15 40 25 • All nodes on the left are less than 10 and all on the right are greater than 10 • Remove 5?

Removing a node from a binary tree • Node has no children – Simply

Removing a node from a binary tree • Node has no children – Simply remove it from tree • Node has one child – Remove the node and replace it with it’s child • Node has two children – Replace the node’s value with (2 options): • the left-most value of the right tree. • the right-most value of the left tree.

Remove Leaf 10 8 5 30 9 20 15 40 25 • All nodes

Remove Leaf 10 8 5 30 9 20 15 40 25 • All nodes on the left are less than 10 and all on the right are greater than 10 • Remove 8?

Remove node with one child 10 9 30 20 15 40 25 • All

Remove node with one child 10 9 30 20 15 40 25 • All nodes on the left are less than 10 and all on the right are greater than 10 • Remove 20?

Remove node with two children 10 9 30 25 15 40 25 • Replace

Remove node with two children 10 9 30 25 15 40 25 • Replace value with left-most value of the right tree • All nodes on the left are less than 10 and all on the right are greater than 10 • Remove 10?

Remove node with two children 15 9 30 25 40 15 • Replace value

Remove node with two children 15 9 30 25 40 15 • Replace value with left-most value of the right tree • All nodes on the left are less than 15 and all on the right are greater than 15

The Binary Tree Node Structure struct Binary. Tree. Node { int value; Binary. Tree.

The Binary Tree Node Structure struct Binary. Tree. Node { int value; Binary. Tree. Node* left; Binary. Tree. Node* right; };

Removing a node from a binary tree Remove. Node(node* head) { if (head->left ==

Removing a node from a binary tree Remove. Node(node* head) { if (head->left == null) { node* t = head; head = head->right; free_node(t); } else if (head->right == null) { node* t = head; head = head->left; free_node(t); } else { node * t = head->right; while(t->left) t = t->left; head->value = t->value; Remove. Node(t); }

The binary tree NULL NULL typedef struct tree { char word[100]; NULL struct tree

The binary tree NULL NULL typedef struct tree { char word[100]; NULL struct tree *left; struct tree *right; } TREE;

Binary Tree Pros & Cons • Finding an element is O(log n) • Adding

Binary Tree Pros & Cons • Finding an element is O(log n) • Adding an element is O(log n) – O(1) if we already know where to add it. • Deleting an element may be complex • Programming complexity is higher than a linked list (just about)

Deleting an entire binary tree • I think this code is elegant and worth

Deleting an entire binary tree • I think this code is elegant and worth looking at: void delete_tree (TREE *ptr) { if (ptr == NULL) return; delete_tree(ptr->left); delete_tree(ptr->right); free (ptr); } We can delete the whole tree with: delete_tree(root_of_tree);

A binary tree example - words. c • • • /******************************* * * words

A binary tree example - words. c • • • /******************************* * * words -- scan a file and print out a list of words * * in ASCII order. * * Usage: * * words <file> * ******************************* */ #include <stdio. h> #include <ctype. h> #include <string. h> #include <stdlib. h> • • • struct node { struct node *left; struct node *right; char *word; }; • • /* the top of the tree */ static struct node *root = NULL; • • • /* tree to the left */ /* tree to the right */ /* word for this tree */

void memory_error(void) { fprintf(stderr, "Error: Out of memoryn"); exit(8); } char *save_string(char *string) {

void memory_error(void) { fprintf(stderr, "Error: Out of memoryn"); exit(8); } char *save_string(char *string) { char *new_string; /* where we are going to put string */ new_string = malloc((unsigned) (strlen(string) + 1)); if (new_string == NULL) memory_error(); strcpy(new_string, string); return (new_string); }

void enter(struct node **node, char *word) { int result; /* result of strcmp */

void enter(struct node **node, char *word) { int result; /* result of strcmp */ char *save_string(char *); /* save a string on the heap */ /* If the current node is null, we have reached the bottom * of the tree and must create a new node. */ if ((*node) == NULL) { /* Allocate memory for a new node */ (*node) = malloc(sizeof(struct node)); if ((*node) == NULL) memory_error(); /* Initialize the new node */ (*node)->left = NULL; (*node)->right = NULL; (*node)->word = save_string(word); return; } /* Check to see where the word goes */ result = strcmp((*node)->word, word); /* The current node already contains the word, no entry necessary */ if (result == 0) return; /* The word must be entered in the left or right sub-tree */ if (result < 0) enter(&(*node)->right, word); else enter(&(*node)->left, word); }

void scan(char *name) { char word[100]; /* word we are working on */ int

void scan(char *name) { char word[100]; /* word we are working on */ int index; /* index into the word */ int ch; /* current character */ FILE *in_file; /* input file */ in_file = fopen(name, "r"); if (in_file == NULL) { fprintf(stderr, "Error: Unable to open %sn", name); exit(8); } while (1) { /* scan past the whitespace */ ch = fgetc(in_file); while (1) { if (!isalpha(ch)) ch = fgetc(in_file); break; if (isalpha(ch) || (ch == EOF)) word[index] = ch; break; } } /* put a null on the end */ if (ch == EOF) word[index] = ''; break; word[0] = ch; enter(&root, word); for (index = 1; index < sizeof(word); ++index) } { fclose(in_file); }

void print_tree(struct node *top) { if (top == NULL) return; /* short tree */

void print_tree(struct node *top) { if (top == NULL) return; /* short tree */ print_tree(top->left); printf("%sn", top->word); print_tree(top->right); } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Error: Wrong number of parametersn"); fprintf(stderr, " on the command linen"); fprintf(stderr, "Usage is: n"); fprintf(stderr, " words 'file'n"); exit(8); } scan(argv[1]); print_tree(root); return (0); }