1 Objectives of these slides: to describe linked lists in C 6 – Lists

Preview:

Citation preview

1

Objectives of these slides:

to describe linked lists in C

6 – Lists6 – Lists

22

Overview

1. List Data Structures and Operations

2. List Implementations

3. Dynamically Created Lists

4. Converting a String to a List

5. List Functions

33

1. List Data Structures and Operations

Some possible operations:

• create/destroy a list

• test to see if a list is empty

• return the tail of the list

• insert/delete elements

• print a list

• calculate the length of a list

44

2. List implementations

Version 1:

#define N 1000 /* the size of the list */

typedef char LIST[N];

LIST lt; /* same as char lt[N] */

55

Version 2

struct listnode { char data; struct listnode *nextptr;};

typedef struct listnode LISTNODE;

LISTNODE elem;

elem

data nextptr

66

Use

LISTNODE a, b, c;

a.data = 'a';b.data = 'c';c.data = 'e';

a.nextptr = b.nextptr = c.nextptr = NULL;

continued

a b c

77

a.nextptr = &b;b.nextptr = &c;

printf("%c", a.nextptr->data);/* 'c' printed */

printf("%c", a.nextptr->nextptr->data);/* 'e' printed */

a b c

NULL‘a’ ‘c’ ‘e’

88

3. Dynamically Created Lists

/* list implementation as before */typedef LISTNODE *LNP;

LNP head = NULL;head = malloc(sizeof(LISTNODE));head->data = 'n';head->nextptr = NULL;

Function prototype in stdlib.h: void *malloc(size_t size);

head ‘n’ NULL

99

Add a second element

head->nextptr = malloc(sizeof(LISTNODE));

head->nextptr->data = 'e';

head->nextptr->nextptr = NULL;

head ‘n’ ‘e’ NULL

1010

Add a third element

head->nextptr->nextptr = malloc(sizeof(LISTNODE));

head->nextptr->nextptr->data = 'w';

head->nextptr->nextptr->nextptr = NULL;

head ‘n’ ‘e’ ‘w’ NULL

1111

4. Converting a String to a List

#include <stdio.h>#include <stdlib.h>/* list type implementation */

LNP string_to_list(char []);

int main(){ LNP h = NULL; h = string_to_list("AB"); return 0;}

/* implementation of string_to_list() */

1212

LNP string_to_list(char s[]){ LNP head = NULL, tail; int i; if (s[0] != '\0') { head = malloc(sizeof(LISTNODE)); head->data = s[0]; tail = head; for (i=1; s[i] != '\0'; i++){ tail->nextptr =

malloc(sizeof(LISTNODE)); tail = tail->nextptr; tail->data = s[i]; } tail->nextptr = NULL; /* list end */ } return head;}

1313

string_to_list("AB")

head = malloc(sizeof(LISTNODE));

head->data = s[0];

tail = head;

head

‘A’tail

‘?’

1414

tail->nextptr = malloc(sizeof(LISTNODE));

head

‘A’tail

‘?’‘?’

1515

tail = tail->nextptr;

tail->data = s[i]; /* i = 1 here */

head

‘A’

tail

‘?’‘B’

1616

s[2] = '\0‘;/* so end of list is assigned NULL */

head

‘A’

tail

NULL‘B’

1717

5. List Functions

5.1. Empty Lists

5.2. Return the First Element of a List

5.3. Produce the Tail of a List

5.4. Put an Element on the Front of a List

5.5. Insertion

continued

1818

5.6. Deletion

5.7. List Membership

5.8. Print a List

5.9. List Length

5.10. Concatenate Two Lists

1919

5.1. Empty Lists

Make an empty list:

LNP h1;h1 = NULL;

Test for emptiness:

int isempty(LNP sptr){ return (sptr == NULL);}

2020

5.2. Return the First Element of a List

char first(LNP cptr){ if (isempty(cptr)) return '\0‘; else return cptr->data;}

2121

Use

LNP head;char c;

head = string_to_list("new");c = first(head);

/* c is 'n'; head is not altered */

2222

5.3. Produce the tail of a list

void tail(LNP *cptr){ LNP temp; if (isempty(*cptr)) printf("The list is empty.\n\n"); else { temp = *cptr; *cptr = (*cptr)->nextptr; free(temp); }}

cptr is the address of a pointer, so that the pointer can be modified using "call by reference".

2323

Use

LNP head;

head = string_to_list("new"); :tail(&head);

/* head is now the list version of “ew” */

2424

5.4. Put an Element on the List Front

LNP cons(char c, LNP cptr){ LNP temp; temp = malloc(sizeof(LISTNODE)); temp->data = c; temp->nextptr = cptr; return temp;}

2525

Use

LNP h1, h2;

h1 = string_to_list("ew");

h2 = cons('n', h1);

Before the cons() call:

h1‘e’ ‘w’ NULL

2626

After:

h2‘n’ ‘e’ ‘w’ NULL

h1

2727

5.5. Insertion

Before:

head‘n’ ‘w’

previousptr currentptr

NULL

newptr

‘o’ NULL

2828

head‘n’ ‘o’ ‘w’ NULL

After:

2929

Code

void insert(LNP *sptr, char value){ LNP newptr, previousptr, currentptr;

newptr = malloc(sizeof(LISTNODE)); if (newptr) { newptr->data = value; newptr->nextptr = NULL;

previousptr = NULL; currentptr = *sptr;

continued

3030

while ((currentptr != NULL) && (value > currentptr->data)) {

previousptr = currentptr; currentptr = currentptr->nextptr; } if (previousptr == NULL) { newptr->nextptr = *sptr; *sptr = newptr; } else { previousptr->nextptr = newptr; newptr->nextptr = currentptr; } } else printf("No memory available.\n");}

3131

Note

The use of a pointer address (sptr) as an argument to insert() is to allow the head pointer to the list to be altered if the character is inserted as the first node.

3232

Use

LNP h1;

h1 = string_to_list("nw");

insert(&hl, 'o');

Dangers:LNP h1, h2;

h1 = string_to_list("nw");

h2 = h1;

insert(&hl, 'o');

3333

5.6. Deletion

LNP head;

head = string_to_list("new");

c = delete(&head, 'e');

head‘n’

previousptr currentptr

‘e’ ‘w’ NULL

3434

head‘n’

previousptr currentptr

‘e’ ‘w’ NULL

tempptr

3535

Code

char delete(LNP *sptr, char value){ LNP previousptr, currentptr, tempptr;

if (value == (*sptr)->data) { tempptr = *sptr; *sptr = (*sptr)->nextptr; free(tempptr); return value; } else { previousptr = *sptr; currentptr = (*sptr)->nextptr;

continued

3636

while ((currentptr != NULL) && (currentptr->data != value)) {

previousptr = currentptr; currentptr = currentptr->nextptr; }

if (currentptr) { tempptr = currentptr; previousptr->nextptr = currentptr->nextptr; free(tempptr); return value; } } return '\0';}

3737

Some Comments

The use of a pointer address (sptr) as an argument to

delete() is to allow the head pointer to the list to be alt

ered if the first character in the list is being deleted.

3838

delete() can stop when:

1. It has found the character.

2. It has reached the end of the list (the character isn't there).

3. It has reached a character lexically bigger than the one being sought. Not used in this code.

3939

Dangers

LNP h1, h2;char c;h1 = string_to_list("all");h2 = h1;c = delete(&h1, 'l');

h2 wouldbepointingatnothing if the f irstnodeofh1 wasdeleted

h1‘a’ ‘l’ NULL

h2

4040

5.7. List Membership

int member(char c, LNP cptr){ if (isempty(cptr)) return 0; else { if (c == first(cptr)) return 1; else return member(c, cptr->nextptr); }}

4141

5.8. Print a List (iteratively)

void printList(LNP cptr){ if (!cptr) printf("List is empty.\n\n"); else { printf("The list is:\n"); while (cptr) { printf("%c --> ", cptr->data); cptr = cptr->nextptr; } printf("NULL\n\n"); }}

4242

Use

LNP head;

head = string_to_list("old");

printList(head);

The list is:o --> l --> d --> NULL

4343

Print a List (recursively)

void printList(LNP cptr){ if (isempty(cptr)) printf("NULL"); else { printf("%c --> ", first(cptr)); printList(cptr->nextptr); }}

4444

5.9. List Length

int length(LNP cptr){ if (isempty(cptr)) return 0; else return (1 + length(cptr->nextptr));}

4545

5.10. Concatenate Two Lists

void concat(LNP a, LNP b){ if (a->nextptr == NULL) a->nextptr = b; else concat(a->nextptr, b);}

4646

Use

LNP h1, h2;

h1 = string_to_list("new");h2 = string_to_list("ton");

concat(h1, h2); /* h1 altered */print_list(h1);

The list is:n --> e --> w --> t --> o --> n --> NULL

4747

Dangers

LNP h1, h2;

h1 = string_to_list("ab");h2 = string_to_list("cd");

concat(h1, h2); /* h1 is list "abcd" */

h2->data = 'o';

h1‘a’ ‘o’ ‘d’ NULL‘b’

h2

4848

5.11 Doubly Linked Lists

A node in a doubly-linked list contain two references that point to the next node and the previous node.

ex. struct listnode { char data; struct listnode *next; struct listnode *prev;

};

front points to the first node in the list

back points at the last node in the list

4949

A doubly-linked list can be scanned in both directions: a forward scan starts at 'front' and ends

when the link is to the same object as 'back' a backward scan starts at 'back' and ends

when the link is to the same object as 'front'

5050

Like a singly-linked list, a doubly linked list is a sequential structure.

To move forward or backward, use the node links 'next' and 'prev'.

Unlike a singly linked list, the insert and delete operations only need a single reference to the node.

5151

Insert a list into double linked list

Insertion into a doubly linked list requires four reference assignments.

prevNode = curr.prev;newNode.prev = prevNode; // 1prevNode.next = newNode; // 2curr.prev = newNode; // 3newNode.next = curr; // 4

5252

Delete a list from double linked list

To delete a node curr, link the predecessor (curr.prev) of 'curr' to the successor of 'curr' (curr.next).

prevNode = curr.prev;succNode = curr.next;succNode.prev = prevNode; // 1prevNode.next = succNode; // 2curr.prev = null;curr.next = null;

Recommended