0% found this document useful (0 votes)
21 views

CS DataStructure-Lecture 4-List (Array and Linked)

Data strructure

Uploaded by

AsmaaGhoniem
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views

CS DataStructure-Lecture 4-List (Array and Linked)

Data strructure

Uploaded by

AsmaaGhoniem
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 28

Data Structure

Dr. Ahmed Hesham Mostafa


Lecture 4 –Linked List
TextBooks
• s k chang, “data structures and algorithms”
• Kruse and Leung, “Data Structures & Program Design in C”
Online Martials
• CS214: Data Structures by Prof. Dr Waleed A. Yousef
• https://www.youtube.com/playlist?list=PLoK2Lr1miEm-
5zCzKE8siQezj9rvQlnca
• Data Structures Learning Course by Dr Mohammed El-Said
• https://www.youtube.com/playlist?list=PLfay0LLBd0wiNeOR_SGoYfC
3w-NxFwd0D
• Lectures Source code (updated frequently)
• https://github.com/ahmedheshamostafa/DataStructure
Motivation: Why Lists?

• In a general list:
– new values are added in position determined by the user.
– Element is removed from a position determined by the user.

• Important notice:
– if we keep adding and removing from the first position (the
head of the list) the general list will behave as a stack.

– If we keep adding from one end and removing from another


end the list will behave as a queue.

• Application:
– In queues, sometimes we need a priority for some elements.
We may need to put an emergency call prior to others.
© Waleed A. Yousef 2008 4
Motivation: Why Lists?

• This is a list (just a logical view, no implementation yet) with


number of entries equals to size
• We can add a new element in position 0  p  size.
• However, we delete from 0  p  size-1.
• Now, let us be rigorous and define lists.

© Waleed A. Yousef 2008 5


Definition: A general list of elements of type T is a finite
sequence of elements of T together with the following operations:

1. Create the list, leaving it empty.


2. Determine whether the list is empty or not
3. Determine whether the list is full or not
4. Find the size of the list.
5. Insert a new entry in the position 0  p  size.
6. Delete an entry from the position 0  p  size-1
7. Traverse the list, visiting each entry
8. Clear the list to make it empty

© Waleed A. Yousef 2008 6


0 size-1 MAXLIST-1

void InsertList(int p, ListEntry e, List *pl);


Precondition:
1- The list pl has been created.
2- not full
3- 0 p size.
Postcondition:
1- e has been inserted at position p
2- all elements at old positions p, p+1, …, size-1 are incremented by 1.
3- size increases by 1.

void DeleteList(int p, ListEntry *pe, List *pl);


Precondition: The list pl has been created, not empty, and 0  p  size-1.
Postcondition: e has been retrieved from position p, and all elements at old positions
p+1, …, size-1 are decremented by 1. size decreases by 1.

© Waleed A. Yousef 2008 7


0 size-1 MAXLIST-1

void RetrieveList(int p, ListEntry *pe, List *pl);


same precondition as DeleteList. And the list is unchanged

void ReplaceList(int p, ListEntry e, List *pl);


same precondition. And the element is replaced

Other functions have similar pre- and post-conditions to the Queue


and Stack.

Now let us start the Contiguous (array-based) Implementation

© Waleed A. Yousef 2008 8


/*List.h*/
MAXLIST-1
#include "Global.h"

typedef struct list{


ListEntry entry[MAXLIST];
int size; size -1
}List;

void CreateList (List *);


int ListEmpty (List *);
int ListFull (List *);
int ListSize (List *);
void DestroyList (List *);
void InsertList (int, ListEntry, List *); 0
void DeleteList (int, ListEntry *, List *);
size entry
void TraverseList(List *, void (*Visit)(ListEntry));
void RetrieveList(int , ListEntry *, List *);
void ReplaceList (int, ListEntry, List *);

© Waleed A. Yousef 2008 9


void CreateList(List *pl){
MAXLIST-1
pl->size=0;
} // Θ(1)

int ListEmpty(List *pl){


return !pl->size;
size -1
} // Θ(1)

int ListFull(List *pl){


return pl->size==MAXLIST;
} // Θ(1)

int ListSize(List *pl){


0
return pl->size;
} // Θ(1) size entry

void DestroyList(List *pl){


pl->size=0;
} // Θ(1)
© Waleed A. Yousef 2008 10
/*0 <= p <= size*/
void InsertList(int p, ListEntry e, List *pl){
int i;
/*The loop shifts up all the elements in the
range [p, size-1] to free the pth location*/
for(i=pl->size-1; i>=p; i--)
pl->entry[i+1]=pl->entry[i];
pl->entry[p]=e;
pl->size++;
} // Θ(n) MAXLIST-1

Special Cases are all the combination of the following:


p = 0 or p = size size -1
size = 0
All the cases will work p
p -1
0
Inserting one element requires too many shifting!!
size entry
© Waleed A. Yousef 2008 11
/*0<= p <= size-1 and List not empty*/
void DeleteList(int p, ListEntry *pe, List *pl){
int i;
*pe=pl->entry[p];
/*The loop shifts down all the elements in the
range [p+1, size-1] to free the pth location*/
for(i=p+1; i<=pl->size-1; i++)
pl->entry[i-1]=pl->entry[i];
pl->size--;
} // Θ(n) MAXLIST-1

Special Cases are all the combination of the following: size -1


p = 0 or p = size - 1
size = 1 p +1
All the cases will work p

0
Deleting one element requires too many shifting!!
size entry
© Waleed A. Yousef 2008 12
/* 0<= p <= size-1*/
void RetrieveList(int p, ListEntry *pe, List *pl){
*pe=pl->entry[p];
} // Θ(1)
/* 0<= p <= size-1*/
void ReplaceList(int p, ListEntry e, List *pl){
pl->entry[p]=e;
} // Θ(1)

void TraverseList(List* pl, void (*Visit)(ListEntry)){


int i;
for(i=0; i<pl->size; i++) MAXLIST-1
(*Visit)(pl->entry[i]);
} // Θ(n) size -1

p +1
p

0
size entry
© Waleed A. Yousef 2008 13
/*List.h*/
#include "Global.h"

typedef struct listnode{


ListEntry entry;
struct listnode *next;
}ListNode;

typedef struct list{


ListNode *head;
int size;
}List;

p=0 p=1 p=size-1

size head

© Waleed A. Yousef 2008 14


void CreateList(List *pl){
pl->head=NULL;
pl->size=0;
} // Θ(1)

int ListEmpty(List *pl){


return (pl->size==0);
//or return !pl->head
} // Θ(1)

int ListFull(List *pl){


return 0;
} // Θ(1)

int ListSize(List *pl){


return pl->size;
} // Θ(1)

0 1 p … size-1

© Waleed A. Yousef 2008


size head 15
void DestroyList(List *pl){
ListNode *q;
while(pl->head){
q=pl->head->next;
free(pl->head);
pl->head=q;
}
pl->size=0;
}//we took it before many times: // Θ(n)

void TraverseList(List* pl, void(*Visit)(ListEntry)){


ListNode *p=pl->head;
while(p){
(*Visit)(p->entry);
p=p->next;
}
} // Θ(n)

0 1 p … size-1
© Waleed A. Yousef 2008 size head 16
void InsertList(int pos, ListEntry e, List *pl){
size
ListNode *p, *q;
int i; head
p=(ListNode *)malloc(sizeof(ListNode));
p->entry=e;
0
p->next=NULL;

if (pos==0){//will work also for head equals NULL


p->next=pl->head; pos-1
pl->head=p;
} q
else{
for(q=pl->head, i=0; i<pos-1; i++) pos
q=q->next;
p
p->next=q->next;


q->next=p; 1
}
pl->size++;
} // Θ(n) but without shifting elements. size-1

© Waleed A. Yousef 2008 17


We should make sure that the memory is not full when we call malloc
(as we did previously). We have to design the function to return int
not void and we modify the contiguous implementation accordingly to
return 1 always.

© Waleed A. Yousef 2008 18


int InsertList(int pos, ListEntry e, List *pl){
size
ListNode *p, *q;
int i; head
if (p=(ListNode *)malloc(sizeof(ListNode))){
p->entry=e;
0
p->next=NULL;

if (pos==0){//works also for head = NULL


p->next=pl->head; pos-1
pl->head=p;
} q
else{
for(q=pl->head, i=0; i<pos-1; i++) pos
q=q->next;
p
p->next=q->next;
q->next=p;


}
pl->size++;
return 1;
} size-1
else return 0;
}
© Waleed A. Yousef 2008 19
void DeleteList(int pos, ListEntry *pe, List *pl){ size
int i; head
ListNode *q, *tmp;

if (pos==0){ 0
*pe=pl->head->entry;
tmp=pl->head->next;
free(pl->head); 1
pl->head=tmp;
}// it works also for one node tmp
else{ pos-1
for(q=pl->head, i=0; i<pos-1; i++)
q=q->next; q

pos
*pe=q->next->entry;
tmp=q->next->next;
free(q->next);
pos+1
q->next=tmp;
}// check for pos=size-1 (tmp will be NULL)
tmp
pl->size--;
} //O(n) but without shifting elements. size-1

© Waleed A. Yousef 2008 20


size

head

void RetrieveList(int pos, ListEntry *pe, List *pl){


int i; 0
ListNode *q;
for(q=pl->head, i=0; i<pos; i++)
q=q->next; 1
*pe=q->entry;
}
pos-1

void ReplaceList(int pos, ListEntry e, List *pl){


int i; pos
ListNode *q;
for(q=pl->head, i=0; i<pos; i++)
q=q->next;
pos+1
q->entry=e;
}

size-1

© Waleed A. Yousef 2008 21


Comparison between the array-based and the linked
implementation: “Which is always better?” is a wrong question!

Array-based Linked
CreateList Θ(1) Θ(1)
InsertList Θ(n) Θ(n)
DeleteList Θ(n) Θ(n)
RetrieveList Θ(1) Θ(n)
ReplaceList Θ(1) Θ(n)

InsertList is very time consuming for Array-based because of


copying elements, especially if the elements are large records.

RetrieveList and ReplaceList are always better for contiguous


implementation.

© Waleed A. Yousef 2008 22


Design Enhancement: Learn how you modify your design to enhance
the performance

Many applications processes the entries in order, i.e., moving from one entry to the
next.

Many other applications refer to the same entry many times.

Then, our current linked implementation is very inefficient, since it moves from the
head to the element every time!
Then, we need to remember the last position currentpos and start navigating
from it, and we use current to start walking from currentpos

k 0 1 k size-1
currentpos current size head
© Waleed A. Yousef 2008 23
Design Enhancement: Learn how you modify your design to
enhance the performance

Of course, this will not help if the new element is preceding


the last element visited.

Only the type definition, InsertList, DeleteList,


ReplaceList, and RetrieveList will change.

typedef struct list{


ListNode *head, *current;
int size, currentpos;
}List;

k 0 1 k size-1
currentpos current size head
© Waleed A. Yousef 2008 24
void InsertList(int pos, ListEntry e, List *pl){
ListNode *p; 0
p=(ListNode *)malloc(sizeof(ListNode));
p->entry=e;
p->next=NULL;
if (pos==0){ currentpos
p->next=pl->head;
pl->head=p;
pl->currentpos=0; //new pos-1
pl->current=pl->head; //new pl->current
}
else{//pl->current is used in place of q previously.
if (pos<=pl->currentpos){ pos
pl->currentpos=0;//as i=0
pl->current=pl->head;//as q=pl->head
} //new.


for(; pl->currentpos!=pos-1; pl->currentpos++)
pl->current=pl->current->next; p
p->next=pl->current->next;
pl->current->next=p; size-1
}
pl->size++;
© Waleed A. Yousef 2008 25
void DeleteList(int pos, ListEntry *pe, List *pl){
ListNode *tmp; 0
if (pos==0){
*pe=pl->head->entry;
pl->current=pl->head->next;
free(pl->head); currentpos
pl->head=pl->current; //new
pl->currentpos=0; //new
} pos-1
else{ pl->current
if (pos<=pl->currentpos){
pl->currentpos=0;
pl->current=pl->head; pos
tmp
}
for(; pl->currentpos!=pos-1; pl->currentpos++)
pl->current=pl->current->next;


*pe=pl->current->next->entry;
tmp=pl->current->next->next;
free(pl->current->next);
pl->current->next=tmp; size-1
}
pl->size--;
© Waleed A. Yousef 2008 26
You have to modify ReplaceList and RetrieveList in
the same manner. (Do it as a homework). Check also for other
functions, e.g., CreateList (for initialization)

Compare the previous functions to the functions of the book,


where it has a function SetPosition that is called from
within InsertList and DeleteList.

Having this function may simplify the code for the case of
having current and currentpos.

© Waleed A. Yousef 2008 27


Design Enhancement: Learn how you modify your design to
enhance the performance

Accessing the list at a position preceding currentpos will


be slow, since we cannot move back. A possible remedy is
using doubly linked list.

We need just a pointer, current, not necessarily point to


the first node. currentpos will always indicates the order
of the current node.

Read the code from the book and solve the review problems

k 0 1 k size-1
currentpos current size
© Waleed A. Yousef 2008 28

You might also like