Chapter 4 Lists Fundamentals of Data Structures in C

1 / 77

# Chapter 4 Lists Fundamentals of Data Structures in C - PowerPoint PPT Presentation

Chapter 4 Lists Fundamentals of Data Structures in C. Instructors: C. Y. Tang and J. S. Roger Jang. All the material are integrated from the textbook "Fundamentals of Data Structures in C" and some supplement from the slides of Prof. Hsin-Hsi Chen (NTU). 4.1 Pointers.

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## Chapter 4 Lists Fundamentals of Data Structures in C

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### Chapter 4 Lists Fundamentals of Data Structures in C

Instructors:

C. Y. Tang and J. S. Roger Jang

All the material are integrated from the textbook "Fundamentals of Data Structures in C" and some supplement from the slides of Prof. Hsin-Hsi Chen (NTU).

4.1 Pointers
• Consider the following alphabetized list of three letter English words ending in at: (bat, cat, sat, vat)
• We would like to add the word mat to this list.
• If we store this list in an array, then we must move sat and vat one position to the right before we insert mat.
• Similarly, if we want to remove the word cat from the list, we must move sat and vat one position to the left to maintain our sequential representation.
• In general case, arbitrary insertion and deletion from arrays can be very time-consuming.
• In a sequential representation the order of elements is the same as in the ordered list, while in a linked representation these two sequences need not be the same.
• To access elements of the list in the correct order with each element, we store the address, or location, of the next element in that list.
• Thus, associated with each list element is a node which contains both a data component and a pointer to the next item in the list. The pointers are often called links.

10

i

pi

- Pointers in C
• * the dereferencing (or indirection)

operator

• Example:

int i, *pi;

pi = &i;

• &i returns the address of i and assigns it

as the value of pi.

• To assign a value to i we can say:

i = 10;

• or

*pi = 10;

4.1.1 Pointers can be dangerous
• Set all pointers to NULL when they are not actually pointing to an object.
• Use explicit type cast when converting between pointer types.
• Example:

pointer

int i, *pi;

pi = &i; i=10 or *pi=10

pi= malloc(size of(int));

/* assign to pi a pointer to int */

pf=(float *) pi;

/* casts an int pointer to a float pointer */

• Define explicit return types for functions.
• Pointers may have the same size as type int. The function return type defaults to int which can later be interpreted as a pointer .
4.1.2 Using dynamically allocated storage
• We may not know how much space we will need, nor do we wish to allocate some vary large area that may never be required.
• C provides a mechanism, called a heap, for allocating storage at run-time.
• We can call a function, malloc, to request the amount of memory.
• Later we can call another function, free, to return the area of memory to the system.
Program 4.1 : Allocation and deallocation of pointers

int i, *pi;

float f, *pf;

pi = (int *) malloc(sizeof(int));

pf = (float *) malloc (sizeof(float));

*pi =1024;

*pf =3.14;

printf(”an integer = %d, a float = %f\n”, *pi, *pf);

free(pi);

free(pf);

request memory

return memory

bat 

cat 

sat 

vat NULL

• Linked lists are drawn as an order sequence of nodes with links represented as arrows.
• The name of the pointer to the first node in the list is the name of the list.
• -The nodes do not resident in sequential locations.
• -The locations of the nodes may change on different runs.

mat 

• It is easier to make arbitrary insertions and deletions using a linked list rather than a sequential list.
• To insert the word mat between cat can sat, we must:
• Get a node that is currently unused; let its address be paddr.
• Set the data field of this node to mat.
• Set the link field of the node containing cat to point to paddr.

bat 

cat 

sat 

vat NULL

cat 

sat 

mat 

• To delete mat from the list.
• Find the element that immediately precedes mat, which is cat, and set its link field to point to mat’s link field.

bat 

vat NULL

4.3 Dynamically linked stacks and queues
• When several stacks and queues coexisted, there was no efficient way to represent them sequentially.
• Direction of links for both stack and the queue facilitate easy insertion and deletion of nodes.

top

front

  

  

NULL

NULL

rear

- Represent n stacks
• Declarations

#define MAX_STACKS 10 /* max number of stacks */

typedef struct {

int key;

/* other fields */

} element;

typedef struct stack *stack_pointer;

typedef struct stack {

element item;

};

stack_pointer top[MAX_STACKS];

• Initial condition:

top[i] = NULL, 0 ≦ i < MAX_STACKS

• Boundary conditions:

top[i] = NULL iff the ith stack is empty and

IS_FULL(temp) iff the memory is full

Program 4.6 : Push in a linked stack
• void add(stack_pointer *top, element item){ /* add an element to the top of the stack */ stack_pointer temp = (stack_pointer) malloc (sizeof (stack)); if (IS_FULL(temp)) { fprintf(stderr, “ The memory is full\n”); exit(1); } temp->item = item; temp->link = *top; *top= temp;

}

Program 4.7 : Pop from a linked stack
• element delete(stack_pointer *top) {/* delete an element from the stack */ stack_pointer temp = *top; element item; if (IS_EMPTY(temp)) { fprintf(stderr, “The stack is empty\n”); exit(1); } item = temp->item; *top = temp->link; free(temp); return item;}
-Represent n queues
• Declarations

#define MAX_QUEUES 10 /* maximum number of queues */

typedef struct queue *queue_pointer;

typedef struct queue { element item; queue_pointer link; };

queue_pointer front[MAX_QUEUE], rear[MAX_QUEUES];

• Initial conditions:

front[i] = NULL, 0 ≦ i < MAX_QUEUES

• Boundary conditions:

front[i] = NULL iff the ith queue is empty and

IS_FULL(temp) iff the memory is full

• void addq(queue_pointer *front, queue_pointer *rear, element item){ /* add an element to the rear of the queue */ queue_pointer temp = (queue_pointer) malloc(sizeof (queue)); if (IS_FULL(temp)) { fprintf(stderr, “ The memory is full\n”); exit(1); } temp->item = item; temp->link = NULL;
• if (*front) (*rear) -> link = temp;
• else *front = temp;
• *rear = temp; }
Program 4.9 : Delete from the front of a linked queue
• element deleteq(queue_pointer *front) {/* delete an element from the queue */ queue_pointer temp = *front; element item; if (IS_EMPTY(*front)) { fprintf(stderr, “The queue is empty\n”); exit(1); } item = temp->item; *front = temp->link; free(temp); return item;}
4.4 Polynomials
• 4.4.1- Representing Polynomials As Singly Linked Lists
• We want to represent the polynomial:
Where the ai are nonzero coefficients and the eiare nonnegative integer exponents such that

em-1＞ em-2＞ … ＞e1＞ e0≧ 0.

• We represent each term as a node containing coefficient and exponent fields, as well as a pointer to the next term.

• Declarations

typedef struct poly_node *poly_pointer;

typedef struct poly_node {

int coef;

int expon;

};

poly_pointer a, b, c;

-Polynomial representation

a

null

1 0

3 14

2 8

b

null

8 14

-3 10

10 6

• To add two polynomials, we examine their terms starting at the nodes pointed to by a and b.
• If the exponents of the two terms are equal, we add the two coefficients and create a new term for the result.
• If the exponent of the current term in a is less than the exponent of the current term in b, then we create a duplicate term of b, attach this term to the result, called d, and advance the pointer to the next term in b.
• Take a similar action on a if a->expon > b->expon.
(a) a->expon == b->expon

2 8

1 0

3 14

a

-3 10

10 6

8 14

b

11 14

d

a->expon == b->expon

(b) a->expon < b->expon

2 8

1 0

3 14

a

-3 10

10 6

8 14

b

-3 10

11 14

d

a->expon < b->expon

(c) a->expon > b->expon

2 8

1 0

3 14

a

-3 10

10 6

8 14

b

-3 10

11 14

2 8

a->expon > b->expon

Program 4.10 : Add two polynomials
• poly_pointer padd(poly_pointer a, poly_pointer b)

{

poly_pointer front, rear, temp;

int sum;

rear =(poly_pointer)malloc(sizeof(poly_node));

if (IS_FULL(rear)) {

fprintf(stderr, “The memory is full\n”);

exit(1);

}

front = rear;

while (a && b) {

switch (COMPARE(a->expon, b->expon)) {

case -1: /* a->expon < b->expon */

attach(b->coef, b->expon, &rear);

break;

case 0: /* a->expon == b->expon */

sum = a->coef + b->coef;

if (sum) attach(sum,a->expon,&rear);

break;

case 1: /* a->expon > b->expon */

attach(a->coef, a->expon, &rear);

}

}

for (; a; a = a->link) attach(a->coef, a->expon, &rear);

for (; b; b=b->link)attach(b->coef, b->expon, &rear);

temp = front; front = front->link; free(temp);

return front;

}

Delete extra initial node.

- Analysis
• 0  additions  min(m, n)
• where m (n) denotes the number of terms in A (B).
• (2) exponent comparisons
• extreme case
• em-1 > fm-1 > em-2 > fm-2 > … > e0 > f0
• m+n-1 comparisons
• (3) creation of new nodes
• extreme case
• m + n new nodes
• summary O(m+n)
4.4.3 Erasing polynomials
• Program 4.12 : Erasing a polynomial

void erase(poly_pointer *ptr)

{

/* erase the polynomial pointed to by ptr */

poly_pointer temp;

while (*ptr) {

temp = *ptr;

free(temp);

}

}

ptr

3

14

2

8

1

0

4.4.4 Representing Polynomials As Circularly linked lists
• If the link field of the last node points to the first node in the list, all the nodes of a polynomial can be freed more efficiently.

ptr =3X 14+2X 8+1

• Nodes that are no longer in use are freed so that we can reuse these nodes later.
• Maintaining a list (as a chain) of nodes that have been “freed”.
Program 1.13 : get_node function
• poly_pointer get_node(void)

{

poly_pointer node;

if (avail) {

node = avail;

}

else {

node = (poly_pointer)malloc(sizeof(poly_node));

if (IS_FULL(node)) {

printf(stderr, “The memory is full\n”);

exit(1);

}

}

return node;

}

Program 4.14 : ret_node function
• void ret_node(poly_pointer ptr)

avail = ptr;

}

Program 4.15 : Erasing a circular list

void erase(poly_pointer *ptr)

{ /* erase the circular list ptr */

poly_pointer temp;

if (*ptr) {

avail = temp;

*ptr = NULL;

}

}

  

NULL

  

avail

ptr

temp

avail

To avoid the special case of zero polynomial, each polynomial contains one additional head node.
• The expon and coef fields of this node are irrelevant.

(a) Zero polynomial

-1

a

Zero polynomial

(b)

a

-1

2 8

1 0

3 14

Program 4.16 : Adding circularly represented polynomials
• poly_pointer cpadd(poly_pointer a, poly_pointer b)

{

poly_pointer starta, d, lastd;

int sum, done = FALSE;

starta = a;

d = get_node();

d->expon = -1; lastd = d;

do {

switch (COMPARE(a->expon, b->expon)) {

case -1: attach(b->coef, b->expon, &lastd);

break;

Set expon field of head node to -1.

case 0: if (starta == a) done = TRUE;

else {

sum = a->coef + b->coef;

if (sum) attach(sum,a->expon,&lastd);

}

break;

case 1: attach(a->coef,a->expon,&lastd);

}

} while (!done);

return d;

}

typedef struct list_node *list_pointer;

typedef struct list_node {

char data;

};

Use two extra pointers: middle and trail.

• Program 4.17: Inverting a singly linked list

{ /* invert the chain pointed to by lead */

list_pointer middle, trail;

middle = NULL;

trail = middle;

}

return middle;

}

a

x1

x1

x2

x2

x3

x3

a

4.5.2 Operations for circularly linked lists
• Need to change the link field of the last node when insert a new node at the front of the list.
• It is more convenient if the name of the circular list points to the last node.
Program 4.18 : Concatenating singly linked lists
• list_pointer concatenate(list_pointer

ptr1, list_pointer ptr2)

{

list_pointer temp;

if (IS_EMPTY(ptr1)) return ptr2;

else {

if (!IS_EMPTY(ptr2)) {

}

return ptr1;

}

}

O(m) where m is # of elements in the first list

X2

X1

void insert_front (list_pointer *ptr, list_pointer node)

{

if (IS_EMPTY(*ptr)) {

*ptr= node;

}

else {

}

}

X3

ptr

(2)

(1)

4.6 Equivalence relations
• A relation over a set, S, is said to be an equivalence relation over S iff it is symmertric, reflexive, and transitive over S.
• reflexive, x=x
• symmetric, if x=y, then y=x
• transitive, if x=y and y=z, then x=z
0=4, 3=1, 6=10, 8=9, 7=4, 6=8, 3=5, 2=11, 11=0
• three equivalent classes{0,2,4,7,11}; {1,3,5}; {6,8,9,10}
A Rough Algorithm to find Equivalence Classes
• Program 4.21 : First pass at equvalence algorithm
• void equivalenec()

{

initialize;

while (there are more pairs) {

process this pair;

}

initialize the output;

do {

output a new equivalence class;

} while (not done);

}

#include <stdio.h>

#include <alloc.h>

#define MAX_SIZE 24

#define IS_FULL(ptr) (!(ptr))

#define FALSE 0

#define TRUE 1

void equivalence()

{

initialize seq to NULL and out to TRUE

while (there are more pairs) {

put j on the seq[i] list;

put i on the seq[j] list;

}

for (i=0; i<n; i++)

if (out[i]) {

out[i]= FALSE;

output this equivalence class;

}

}

direct equivalence

Compute indirect equivalence

using transitivity

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]

seq

0  4

3  1

6  10

8  9

7  4

6  8

3  5

2  11

11  0

3

8

6

11

11

5

7

4

6

0

8

3

data

NULL

NULL

NULL

NULL

NULL

NULL

9

4

1

10

0

data

2

NULL

NULL

NULL

NULL

NULL

typedef struct node *node_pointer ;

typedef struct node {

int data;

};

Final Version for Finding Equivalence Classes
• void main(void)

{

short int out[MAX_SIZE];

node_pointer seq[MAX_SIZE];

node_pointer x, y, top;

int i, j, n;

printf(“Enter the size (<= %d) “, MAX_SIZE);

scanf(“%d”, &n);

for (i=0; i<n; i++) {

out[i]= TRUE; seq[i]= NULL;

}

printf(“Enter a pair of numbers (-1 -1 to quit): “);

scanf(“%d%d”, &i, &j);

Phase 1: input the equivalence pairs:

while (i>=0) {

x = (node_pointer) malloc(sizeof(node));

if (IS_FULL(x)) fprintf(stderr, “memory is full\n”);

exit(1);

}

x->data= j; x->link= seq[i]; seq[i]= x;

if (IS_FULL(x)) fprintf(stderr, “memory is full\n”);

exit(1);

}

x->data= i; x->link= seq[j]; seq[j]= x;

printf(“Enter a pair of numbers (-1 -1 to \ quit): “);

scanf(“%d%d”, &i, &j);

}

Insert x to the top of lists seq[i]

Insert x to the top of lists seq[j]

Phase 2: output the equivalence classes

for (i=0; i<n; i++) {

if (out[i]) {

printf(“\nNew class: %5d”, i);

out[i]= FALSE;

x = seq[i]; top = NULL;

for (;;) {

while (x) {

j = x->data;

if (out[j]) {

printf(“%5d”, j);

out[j] = FALSE;

top = x; x = y;

}

}

if (!top) break;

x = seq[top->data]; top = top->link;

}

}

}

push

pop

4.7 Sparse matrices
• Represent each column of a sparse matrix as a circularly linked list with a head node.
• A similar representation for each row of a sparse matrix.
• Each node has a tag field that is used to distinguish between head nodes and entry nodes.
• Each head node has three additional fields: down, right, and next.
• down field: links into a column list
• right field: links into a row list
• The head node for row i is also the head node for column i, and the total number of head nodes is max {number of rows, number of columns}.
• down field: links to the next nonzero term in the same column
• right field: links to the next nonzero term in the same row
• A num_rows × num_cols matrix with num_terms nonzero terms needs max{num_rows, num_cols} + num_terms + 1 nodes.
• Total storage will be less than num_rows × num_cols when num_terms is sufficiently small.

down

row

col

right

value

down

right

next

entry

i

j

ai j

entry of aij

# of head nodes = max{# of rows, # of columns}

4

4

0

2

11

1

1

1

0

12

5

1

2

-4

3

3

-15

#define MAX_SIZE 50 /* size of largest matrix */typedef enum {head, entry} tagfield;typedef struct matrix_node *matrix_pointer;typedef struct entry_node { int row; int col; int value; };typedef struct matrix_node { matrix_pointer down; matrix_pointer right; tagfield tag;
union { matrix_pointer next; entry_node entry; } u; };matrix_pointer hdnode[MAX_SIZE];
Program 4.24 : Read in a sparse matrix

{

/* read in a matrix and set up its linked list. An global array hdnode is used */

int num_rows, num_cols, num_terms;

int row, col, value, current_row;

matrix_pointer temp, last, node;

printf(“Enter the number of rows, columns and number of nonzero terms: “);

scanf(“%d%d%d”, &num_rows, &num_cols,

&num_terms);

num_heads = (num_cols>num_rows)? num_cols : num_rows;

nodes */

node = new_node(); node->tag = entry;

node->u.entry.row = num_rows;

node->u.entry.col = num_cols;

else { /* initialize the head nodes */

term= new_node();

hdnode[i] = temp;

hdnode[i]->right = temp;

hdnode[i]->u.next = temp;

}

current_row= 0; last= hdnode[0];

for (i=0; i<num_terms; i++) {

printf(“Enter row, column and value:”);

scanf(“%d%d%d”, &row, &col, &value);

if (row>current_row) {

last->right= hdnode[current_row];

current_row= row; last=hdnode[row];

}

temp = new_node();

temp->tag=entry; temp->u.entry.row=row;

temp->u.entry.col = col;

temp->u.entry.value = value;

last->right = temp;/*link to row list */

last= temp;

/* link to column list */

hdnode[col]->u.next->down = temp;

hdnode[col]=>u.next = temp;

}

...

/*close last row */

last->right = hdnode[current_row];

/* close all column lists */

for (i=0; i<num_cols; i++)

hdnode[i]->u.next->down = hdnode[i];

hdnode[i]->u.next = hdnode[i+1];

node->right = hdnode[0];

}

return node;

}

Program 4.26 : Write out a sparse matrix
• void mwrite(matrix_pointer node)

{ /* print out the matrix in row major form */

int i;

printf(“\n num_rows = %d, num_cols= %d\n”,

node->u.entry.row,node->u.entry.col);

printf(“The matrix by row, column, and

value:\n\n”);

for (i=0; i<node->u.entry.row; i++) {

printf(“%5d%5d%5d\n”, temp->u.entry.row, temp->u.entry.col, temp->u.entry.value);

}

}

Program 4.27 : Erase a sparse matrix
• void merase(matrix_pointer *node)

{

matrix_pointer x, y, head = (*node)->right;

for (i=0; i<(*node)->u.entry.row; i++) {

x = y; y = y->right; free(x);

}

}

while (y!=*node) {

x = y; y = y->u.next; free(x);

}

free(*node); *node = NULL;

}

• Analysis of mwrite
• merase

O(max{#_rows, #_cols}+#_terms)

O(#_rows+#_terms)

O(#_rows+#_cols+#_terms)

• Can move easily only in the direction of the links in singly linked lists.
• Declarations:

typedef struct node *node_pointer;

typedef dtruct node {

element item;

}

ptr

ptr

Program 4.28 : Insertion into a doubly linked circular list
• void dinsert(node_pointer node, node_pointer newnode)

{

}

Insert

(1)

(3)

(2)

(4)

Program 4.29 : Deletion from a doubly linked circular list
• void ddelete(node_pointer node, node_pointer deleted)

{

if (node==deleted) printf(“Deletion of head node not permitted.\n”);

else {

free(deleted);

}

}

Delete