145
List, (dynamic) linked list et’s first forget about ‘classes’, but only a dynamic list. We make lists with ‘classes’ afterwards.

List, (dynamic) linked list

  • Upload
    mindy

  • View
    210

  • Download
    3

Embed Size (px)

DESCRIPTION

Let’s first forget about ‘classes’, but only a dynamic list. We make lists with ‘classes’ afterwards. List, (dynamic) linked list. A simple list Example: using a dynamic array. concept of a list, e.g. a list of integers Print out info Empty test Search an element - PowerPoint PPT Presentation

Citation preview

Page 1: List, (dynamic) linked list

List, (dynamic) linked list

Let’s first forget about ‘classes’, but only a dynamic list.

We make lists with ‘classes’ afterwards.

Page 2: List, (dynamic) linked list

A simple list Example: using a dynamic array

concept of a list, e.g. a list of integers Print out info Empty test Search an element Insertion (at head, at end, any position) Deletion …

implemented by a static array (over-sized if necessary)

int list[1000]; int size; by a dynamic array

int list[size]; int size; by a linked list and more …

Page 3: List, (dynamic) linked list

int main() {

cout << "Enter list size: ";int n;cin >> n;int* A = new int[n];

initialize(A, n, 0);print(A, n);A = addEnd(A,n,5); print(A, n);A = addHead(A,n,5); print(A, n);A = deleteFirst(A,n); print(A, n);selectionSort(A, n);print(A, n);delete [] A;}

How to use a list?

int A[10000];

int n;

Nothing compulsory in programming, only style matters!

Page 4: List, (dynamic) linked list

Initialize

void initialize(int list[], int size, int value){

for(int i=0; i<size; i++)

list[i] = value;

}

Page 5: List, (dynamic) linked list

void print(int list[], int size) {

cout << "[ ";

for(int i=0; i<size; i++)

cout << list[i] << " ";

cout << "]" << endl;

}

Print out a list

Page 6: List, (dynamic) linked list

Delete the first element// for deleting the first element of the arrayint* deleteFirst(int list[], int& size){

int* newList;newList = new int[size-1]; // make new array

if(size){ // copy and delete old arrayfor(int i=0; i<size-1; i++)

newList[i] = list[i+1];delete [] list;

}size--;return newList;

}

Page 7: List, (dynamic) linked list

Instead of

A = deleteFirst(A,n)

we can also just

deleteFirst(A,n) if we define as a void type function:

void deleteFirst(int*& A, int& size) {

A = newList;

}

Remark:

We can also B = deleteFirst(A,n) if we keep the original intact

Page 8: List, (dynamic) linked list

Adding Elements// for adding a new element to end of arrayint* addEnd(int list[], int& size, int value){

int* newList;newList = new int [size+1]; // make new array

if(size){ // copy and delete old arrayfor(int i=0; i<size; i++)

newList[i] = list[i];delete [] list;

}newList[size] = value;size++;return newList;

}

Page 9: List, (dynamic) linked list

// for adding a new element at the beginning of the arrayint* addHead(int list[], int& size, int value){

int* newList;newList = new int [size+1]; // make new array

if(size){ // copy and delete old arrayfor(int i=0; i<size; i++)

newList[i+1] = list[i];delete [] list;

}newList[0] = value;size++;return newList;

}

Add at the beginning:

Page 10: List, (dynamic) linked list

Linked list: a dynamic list

Page 11: List, (dynamic) linked list

Motivation list using static array

int myArray[1000]; int n;

We have to decide (to oversize) in advance the size of the array (list)

list using dynamic arrayint* myArray; int n;cin >> n;myArray = new int[n];

We allocate an array (list) of any specified size while theprogram is running

linked-list (dynamic size)size = ??The list is dynamic. It can grow and shrink to any size.

Page 12: List, (dynamic) linked list

Array naturally represents a (ordered) list,

the link is implicit, consecutive and contiguous!

Now the link is explicit, any places!

20 45 75 85

Data

Link

20

45

75

85Data Link

20 45 75 85

Data Link

0 1 2 array

linked list

Page 13: List, (dynamic) linked list

Linked Lists: Basic Idea

A linked list is an ordered collection of data Each element of the linked list has

Some data A link to the next element

The link is used to chain the data

Example: A linked list of integers:

20 45 75 85

Data Link

Page 14: List, (dynamic) linked list

The list can grow and shrink

Linked Lists: Basic Ideas

20 45 75 85

20 45

addEnd(75), addEnd(85)

deleteEnd(85), deleteHead(20), deleteHead(45)

75

Page 15: List, (dynamic) linked list

Original linked list of integers:

Insertion (in the middle):

Deletion (in the middle)

Linked Lists: Operations

20 45 75 85

20 45 75 85

20 45 75 85

60

old value

deleted item

Page 16: List, (dynamic) linked list

struct Node{ int data;Node* next;

};

We can also:

typedef Node* NodePtr;

Definition of linked list type:

Page 17: List, (dynamic) linked list

Linked List Structure Node : Data + Link

Definitionstruct Node {

int data; //contains useful information

Node* next; //points to next element or NULL

};

Create a NodeNode* p;

p = new Node; //points to newly allocated memory

Delete a Nodedelete p;

Page 18: List, (dynamic) linked list

Access fields in a node(*p).data; //access the data field

(*p).next; //access the pointer field

Or it can be accessed this way

p->data //access the data field

p->next //access the pointer field

Page 19: List, (dynamic) linked list

Representing and accessing linked lists

We define a pointer

Node* head;

that points to the first node of the linked list. When the linked list is empty then head is NULL.

20 45 75 85Head

Page 20: List, (dynamic) linked list

Passing a Linked List to a Function

When passing a linked list to a function it should suffice to pass the value of head. Using the value of head the function can access the entire list.

Problem: If a function changes the beginning of a list by inserting or deleting a node, then head will no longer point to the beginning of the list.

Solution: When passing head always pass it by reference (not good!)

or using a function to return a new pointer value

It is roughly the same as for an array!!!

Page 21: List, (dynamic) linked list

Implementation of an (Unsorted) Linked List

Page 22: List, (dynamic) linked list

Start the first node from scratch

Node* newPtr;

newPtr = new Node;newPtr->data = 20;newPtr->next = NULL; head = newPtr;

Head

newPtr

20

Headhead = NULL;

Page 23: List, (dynamic) linked list

Inserting a Node at the Beginning

newPtr = new Node;

newPtr->data = 13;

newPtr->next = Head;

head = newPtr;

Head

newPtr

13

20

Page 24: List, (dynamic) linked list

Keep going …

Head

newPtr

50 40 13 20

Page 25: List, (dynamic) linked list

void addHead(Node*& head, int newdata){

Node* newPtr = new Node;

newPtr->data = newdata;newPtr->next = Head;head = newPtr;

}

Adding an element to the head:

Call by reference, scaring!!!

NodePtr&

Page 26: List, (dynamic) linked list

Node* addHead(Node* head, int newdata){

Node* newPtr = new Node;

newPtr->data = newdata;newPtr->next = Head;

return newPtr;}

Also written (more functionally) as:

Compare it with ‘addHead’ with a dynamic array implementation

Page 27: List, (dynamic) linked list

(to delete)

Deleting the Head Node

Node* p;

p = head;

head = head->next;

delete p;

head

p

50 40 13 20

Page 28: List, (dynamic) linked list

void deleteHead(Node*& head){

if(head != NULL){

NodePtr p = head;

head = head->next;

delete p;

}

}

Node* deleteHead(Node* head){

if(head != NULL){

NodePtr p = head;

head = head->next;

delete p;

}

return head;

}

As a function:

Page 29: List, (dynamic) linked list

Displaying a Linked List

p = head;

p = p->next;

20 45head

p

20 45head

p

Page 30: List, (dynamic) linked list

void displayList(Node* head){

NodePtr p;

p = head;

while(p != NULL){

cout << p->data << endl;

p = p->next;

} }

A linked list is displayed by walking through its nodes one by one,

and displaying their data fields (similar to an array!).

void displayArray(int data[], int size) { int n=0; while ( n<size ) {

cout << data[i] << endl; n++;

}

}

For an array:

Page 31: List, (dynamic) linked list

//return the pointer of the node that has data=item//return NULL if item does not exist

Node* searchNode(Node* head, int item){NodePtr p = head;

NodePtr result = NULL;bool found=false;while((p != NULL) && (!found)){

if(p->data == item) {found = true;result = p;}

p = p->next;}return result;

}

Searching for a node (look at array searching first!)

Page 32: List, (dynamic) linked list

void main() { const int size=8; int data[size] = { 10, 7, 9, 1, 17, 30, 5, 6 };

int value; cout << "Enter search element: ";

cin >> value; int n=0; int position=-1; bool found=false; while ( (n<size) && (!found) ) {

if(data[n] == value) { found=true; position=n;}

n++;}if(position==-1) cout << "Not found!!\n";else cout << "Found at: " << position << endl;

}

Remember array searching algorithm:

It is essentially the same!

Page 33: List, (dynamic) linked list

Variations of linked lists

Unsorted linked lists

Sorted linked lists

Circular linked lists Doubly linked lists …

Page 34: List, (dynamic) linked list

Further considerations for the unsorted lists:

Physical copy of list for operators like ‘deleteHead’ and ‘addHead’

‘deleteHead’ should be understood as a decomposition into a sub-list …

Page 35: List, (dynamic) linked list

Node* deleteHead(Node* head){

// physically copy head into a new one, newhead

// so to keep the original list intact!

Node* newhead=NULL;

Node* temp=head;

while(temp!=NULL) {

newhead=addEnd(newhead,temp->data);

temp=temp->next;

}

if(newhead != NULL){

Node* p = newhead;

newhead = newhead->next;

delete p;

}

return newhead;

}

B = deleteHead(A);

Page 36: List, (dynamic) linked list

Original linked list of integers:

Add to the end (insert at the end):

More operation: adding to the end

50 40 13 20

50 40 13 20 60

Last element

The key is how to locate the last element or node of the list!

Page 37: List, (dynamic) linked list

void addEnd(NodePtr& head, int newdata){NodePtr newPtr = new Node;newPtr->data = newdata;newPtr->next = NULL;

NodePtr last = head;if(last != NULL){ // general non-empty list case

while(last->next != NULL) last=last->next;

last->next = newPtr;}else // deal with the case of empty list

head = newPtr;}

Add to the end:

Link new object to last->nextLink a new object to empty list

Page 38: List, (dynamic) linked list

NodePtr addEnd(NodePtr head, int newdata){NodePtr newPtr = new Node;newPtr->data = newdata;newPtr->next = NULL;

NodePtr last = head;if(last != NULL){ // general non-empty list case

while(last->next != NULL) last=last->next;

last->next = newPtr;}else // deal with the case of empty list

head = newPtr;

return head;}

Add to the end as a function:

Page 39: List, (dynamic) linked list

Implementation of a

Sorted Linked List

Page 40: List, (dynamic) linked list

Inserting a Node

Head

cur

20

33

45 75

prev

...

newPtr

1. (a) Create a new node using: NodePtr newPtr = new node;

(b) Fill in the data field correctly.

2. Find “prev” and “cur” such that

the new node should be inserted between *prev and *cur.

3. Connect the new node to the list by using:

(a) newPtr->next = cur;

(b) prev->next = newPtr;

Page 41: List, (dynamic) linked list

Finding prev and cur

Suppose that we want to insert or delete a node with data value newValue. Then the following code successfully finds prev and cur such that

prev->data < newValue <= cur->data

Page 42: List, (dynamic) linked list

prev = NULL;

cur = head;

found=false;

while( (cur!=NULL) && (!found) ) {

if (newValue > cur->data) {

prev=cur;

cur=cur->next;

}

else found = true;

}

Prev is necessary as we can’t go back!

It’s a kind of search algo,

Page 43: List, (dynamic) linked list

prev = NULL;

cur = head;

while( (cur!=NULL) && (newValue>cur->data) ) {

prev=cur;

cur=cur->next;

}

Logical AND (&&) is short-circuited, sequential, i.e. if the first part is false, the second part will not be executed.

Finally, it is equivalent to:

Page 44: List, (dynamic) linked list

//insert item into linked list according to ascending orderNode* insertNode(Node* head, int item){

NodePtr newp, cur, pre; newp = new Node;newp->data = item;

pre = NULL;cur = head;while( (cur != NULL) && (item>cur->data)){

pre = cur;cur = cur->next;

}

if(pre == NULL){ //insert to head of linked listnewp->next = head;head = newp;

} else {pre->next = newp;new->next = cur;

}

return head;}

If the position happens to be the head

General case

Page 45: List, (dynamic) linked list

// not recommended void type functionvoid insertNode(NodePtr& head, int item){

NodePtr newp, cur, pre; newp = new Node;newp->data = item;

pre = NULL;cur = head;while( (cur != NULL) && (item>cur->data)){

pre = cur;cur = cur->next;

}

if(pre == NULL){ //insert to head of linked listnewp->next = head;head = newp;

} else {pre->next = newp;new->next = cur;

}}

Page 46: List, (dynamic) linked list

(to delete)

Deleting a Node To delete a node from the list

1. Locate the node to be deleted(a) cur points to the node.

(b) prev points to its predecessor

2. Disconnect node from list using: prev->next = cur->next;

3. Return deleted node to system: delete cur;

Head

cur

20 45 75 85

prev

...

Page 47: List, (dynamic) linked list

Node* deleteNode(Node* head, int item){NodePtr prev=NULL, cur = head;while( (cur!=NULL) && (item > cur->data)){

prev = cur;cur = cur->next;

}

if ( cur!==NULL && cur->data==item) {

if(cur==head)head = head->next;

elseprev->next = cur->next;

delete cur; }

return head;}

Delete an element in a sorted linked list:

If the element is at the head

General case

We can delete only if the element is present!

If (cur==NULL || cur->data!=item) Item is not in the list!

Get the location

Page 48: List, (dynamic) linked list

void deleteNode(NodePtr& head, int item){NodePtr prev=NULL, cur = head;while( (cur!=NULL) && (item > cur->data)){

prev = cur;cur = cur->next;

}

if ( cur!==NULL && cur->data==item) {

if(cur==Head)Head = Head->next;

elseprev->next = cur->next;

delete cur; }}

// in a void function, not recommended

If the element is at the head

General case

We can delete only if the element is present!

If (cur==NULL || cur->data!=item) Item is not in the list!

Get the location

Page 49: List, (dynamic) linked list

Example of a (dynamic) class: linked list class

Page 50: List, (dynamic) linked list

bool listEmpty(NodePtr head) {

}int getHead(NodePtr head) {

}NodePtr getRest(NodePtr head) {

}NodePtr addHead(NodePtr head, int newdata) {

}void delHead(NodePtr& Head){

}

linked lists: definition

struct Node{ int data;Node* next;

};

typedef Node* NodePtr;

NodePtr head;

Page 51: List, (dynamic) linked list

void main(){

NodePtr Head1=NULL, Head2 = NULL, Head;

addHead(Head1, 50);

addHead(Head1, 40);

addHead(Head1, 30);

addHead(Head1, 20);

cout << "List 1: " << endl;

DisplayList(Head1);

cout << "Length of Head1 list: " << length(Head1) << endl;

cout << "Recursive length of Head1 list: " << lengthRec(Head1) << endl;

if(isPalindrome(Head1))

cout << "Head1 list is palindrome" << endl;

else

cout << "Head1 list is not palindrome" << endl;

addHead(Head2, 25);

addHead(Head2, 35);

addHead(Head2, 45);

addHead(Head2, 35);

addHead(Head2, 25);

cout << "List 2: " << endl;

DisplayList(Head2);

cout << "Length of Head2 list: " << length(Head2) << endl;

cout << "Recursive length of Head2 list: " << lengthRec(Head2) << endl;

if(isPalindrome(Head2))

cout << "Head2 list is palindrome" << endl;

else

cout << "Head2 list is not palindrome" << endl;

Head = mergeLists(Head1, Head2);

cout << "Merged List: " << endl;

DisplayList(Head);

cout << "Length of Merged list: " << length(Head) << endl;

cout << "Recursive length of Merged list: " << lengthRec(Head) << endl;

if(isPalindromeRec(Head))

cout << "Merged list is palindrome" << endl;

else

cout << "Merged list is not palindrome" << endl;

cout << "check the list again:" << endl;

DisplayList(Head);

}

Usage:

Page 52: List, (dynamic) linked list

Make an Abstract Data Type

One more example of ADT: integer linked list using class

A class with dynamic objects: Copy constructor Destructor

Page 53: List, (dynamic) linked list

struct Node{ public:

int data;Node* next;

};typedef Node* Nodeptr;

class list {public:

list(); // constructorlist(const list& list1); // copy constructor~list(); // destructor

bool empty() const; // boolean functionint headElement() const; // access functions

void addHead(int newdata); // add to the headvoid deleteHead(); // delete the head

int length() const; // utility functionvoid print() const; // output

private:Nodeptr head;

};‘old’ operations

‘new’ member functions

Page 54: List, (dynamic) linked list

void main(){list L; // constructor called automatically here for LL.print(); { }L.addHead(30);L.print(); { 30 }L.addHead(13);L.print(); { 13 30 } L.addHead(40);L.print(); { 40 13 30 }L.addHead(50);L.print(); { 50 40 13 30 }list N(L);N.print(); { 50 40 13 30 }

list R;R.print(); { }if(R.empty())

cout << "List R empty" << endl;L.deleteHead();L.print(); { 40 13 30 }L.deleteHead();L.print(); { 13 30 }if(L.empty())

cout << "List L empty" << endl;else{

cout << "List L contains " << L.length() << " nodes" << endl;cout << "Head element of list L is: " << L.headElement() << endl;

}} // destructor called automatically here for L

How to use it

Page 55: List, (dynamic) linked list

list::list(){head = NULL;

}

bool list::empty() const{if(head==NULL)

return true;else

return false;}

int list::headElement() const {if(head != NULL)

return head->data;else{

cout << "error: trying to find head of empty list" << endl;

exit(1);}

}

Some simple member functions:

Implementation

Page 56: List, (dynamic) linked list

list::list(const list& list1) {

head = NULL;

Nodeptr cur = list1.head;

while(cur != NULL) {

// addEnd(cur->data);

addHead(cur->data); // inverse list order

cur = cur->next;

}

}

(explicitly defined) copy constructor:

Page 57: List, (dynamic) linked list

Destructor: deallocation function

list::~list(){

Nodeptr cur;

while(head!=NULL){

cur = head;

head = head->next;

delete cur;

}

}

Page 58: List, (dynamic) linked list

void list::addHead(int newdata){

Nodeptr newPtr = new Node;

newPtr->data = newdata;

newPtr->next = head;

head = newPtr;

}

Adding an element to the head:

Page 59: List, (dynamic) linked list

void list::deleteHead(){

if(head != NULL){

Nodeptr cur = head;

head = head->next;

delete cur;

}

}

Deleting the head:

Page 60: List, (dynamic) linked list

void list::print() const{cout << "{";Nodeptr cur = head;while(cur != NULL){

cout << cur->data << " ";

cur = cur->next;}

cout << "}" << endl;}

Print the list:

Page 61: List, (dynamic) linked list

int list::length() const{

int n=0;Nodeptr cur = head;while(cur != NULL){

n++;cur = cur->next;

}return n;

}

Computing the number of elements of a given list:

Page 62: List, (dynamic) linked list

struct Node{ public:

int data;Node* next;

};typedef Node* Nodeptr;

class list {public:

list(); // constructorlist(const list& list1); // copy constructorconst list& operator=(const list& list1); // assigment, l = l1;~list(); // destructor

bool empty() const; // boolean functionint head() const; // access functionslist remaining() const; // the list with the head removed void insert(int d); // insertionvoid delete(int d); // deletion

int length() const; // utility functionvoid print() const; //

private:Nodeptr head;

};

Interface functions

An almost ideal list class

Page 63: List, (dynamic) linked list

list::list(const listClass& list1) {

head = NULL;

Nodeptr cur = list1.head;

while(cur != NULL) {

// addEnd(cur->data);

addHead(cur->data); // inverse list order

cur = cur->next;

}

}

copy constructor:

Const list& operator=(const list& list1) {

if (this != &list1) {

head = NULL;

Nodeptr cur = list1.head;

while(cur != NULL) {

// addEnd(cur->data);

addHead(cur->data); // inverse list order

cur = cur->next;

}

return *this;

}

Operator assignment, ‘deep copy’

Delete[] head;

Big three: copy constructor, operator=, destructor

Page 64: List, (dynamic) linked list

list l1, l2;

l1.addEnd(5);

list l3(l1);

l3 = l2;

node* head1, head2;

head1 = NULL; head2 = NULL

addEnd(head1,5);

node* head3 = NULL;

copylist(head1, head3);

head3 = head2;

Usage difference

Page 65: List, (dynamic) linked list

Doubly Linked List

Page 66: List, (dynamic) linked list

Motivation

Doubly linked lists are useful for playing video and sound files with “rewind” and instant “replay”

They are also useful for other linked data where “require” a “fast forward” of the data as needed

Page 67: List, (dynamic) linked list

list using an array: Knowledge of list size Access is easy (get the ith element) Insertion/Deletion is harder

list using ‘singly’ linked lists: Insertion/Deletion is easy Access is harder

But, can not ‘go back’!

Page 68: List, (dynamic) linked list

Doubly Linked Lists

In a Doubly Linked-List each item points to both its predecessor and successor prev points to the predecessor next points to the successor

10 7020 5540

HeadCur Cur->nextCur->prev

Page 69: List, (dynamic) linked list

struct Node{

int data;

Node* next;

Node* prev;

};

typedef Node* NodePtr;

Doubly Linked List Definition

Page 70: List, (dynamic) linked list

Doubly Linked List Operations insertNode(NodePtr& Head, int item)//add new node to ordered doubly linked //list

deleteNode(NodePtr& Head, int item) //remove a node from doubly linked list

SearchNode(NodePtr Head, int item)

Print(nodePtr Head, int item)

Page 71: List, (dynamic) linked list

Deleting a Node

Delete a node Cur (not at front or rear)

(Cur->prev)->next = Cur->next; (Cur->next)->prev = Cur->prev;

delete Cur;

10 7020 5540

HeadCur

Page 72: List, (dynamic) linked list

void deleteNode(NodePtr& head, int item) {

NodePtr cur;

cur = searchNode(head, item);

if (head==NULL) { …

}

else if (cur->prev == NULL) { …

}

else if (cur->next==NULL) { …

}

else {

(cur->prev)->next = cur->next;

(cur->next)->prev = cur->prev;

delete cur;

}

}

Empty case

At-the-beginning case

At-the-end case

General case

A systematic way is to start from all these cases, then try to simply the codes, …

Page 73: List, (dynamic) linked list

Inserting a Node

Insert a node New before Cur (not at front or rear)

10 7020 55

40Head

New

Cur

New->next = Cur;

New->prev = Cur->prev;

Cur->prev = New;

(New->prev)->next = New;

Page 74: List, (dynamic) linked list

void insertNode(NodePtr& head, int item) {

NodePtr cur;

cur = searchNode(head, item);

if (head==NULL) { …

}

else if (cur->prev == NULL) { …

}

else if (cur->next==NULL) { …

}

else {

blablabla …}

}

Many special cases to consider.

Page 75: List, (dynamic) linked list

Many different linked lists … singly linked lists

Without ‘dummy’ With dummy circular

doubly linked lists Without ‘dummy’ With dummy

Using ‘dummy’ is a matter of personal preference!

+ simplify codes (not that much - Less logically sounds

Page 76: List, (dynamic) linked list

20Head 10 20 40 7055

Rear

10 20 40 7055

7020 5540

Head

10

7020 5540

Head

10Dummy

singly linked list

(singly) circular linked list

(regular) doubly linked list

doubly circular linked list with dummy

Page 77: List, (dynamic) linked list

Doubly Linked Lists with Dummy Head Node

To simplify insertion and deletion by avoiding special cases of deletion and insertion at front and rear, a dummy head node is added at the head of the list

The last node also points to the dummy head node as its successor

Page 78: List, (dynamic) linked list

Idea of ‘dummy’ object

Instead of pointing to NULL, point to the ‘dummy’!!! Skip over the dummy for the real list

7020 5540

Head

10Dummy Head Node

‘dummy object’ is also called a ‘sentinel’, it allows the simplification of special cases, but confuses the emptyness NULL!

Page 79: List, (dynamic) linked list

Head

Dummy Head Node

Empty list:

Head->next = head; compared with head=NULL;

Page 80: List, (dynamic) linked list

void createHead(NodePtr& head){

head = new Node;

head->next = head;

head->prev = head;

}

NodePtr head;

createHead(head);

NodePtr cur=head;

cur=cur->next;

cur=head; // dummy head

NodePtr head=NULL;

NodePtr cur=head;

cur=head;

cur=NULL; // or head=NULL;

operations Doubly linked with dummy Singly linked

creation

Empty test

Start from

reference

Page 81: List, (dynamic) linked list

void print(NodePtr head){

NodePtr cur=head->next;

while(cur != head){

cout << cur->data << " ";

cur = cur->next;

}

}

Print the whole list:

Page 82: List, (dynamic) linked list

NodePtr searchNode(NodePtr head, int item){

NodePtr cur = head->next;

while ((cur != head) && (item != cur->data)) cur=cur->next;

if (cur == head) cur = NULL; // we didn’t find

return cur;

}

Searching a node

(returning NULL if not found the element):

End of the list, empty

Page 83: List, (dynamic) linked list

Deleting a Node

Delete a node Cur at front

7020 5540

Head

10Dummy Head Node

Cur

(Cur->prev)->next = Cur->next;

(Cur->next)->prev = Cur->prev;

delete Cur;

Page 84: List, (dynamic) linked list

Delete a node Cur in the middle

(Cur->prev)->next = Cur->next;

(Cur->next)->prev = Cur->prev;

delete Cur; // same as delete front!

70

Head

10Dummy Head Node

20 5540

Cur

Page 85: List, (dynamic) linked list

Delete a node Cur at rear

(Cur->prev)->next = Cur->next;

(Cur->next)->prev = Cur->prev;

delete Cur; // same as delete front and middle!

7020 5540

Head

10Dummy Head Node

Cur

Page 86: List, (dynamic) linked list

void deleteNode(NodePtr head, int item){

NodePtr cur;

cur = searchNode(head, item);

if(cur != NULL){

cur->prev->next = cur->next;

cur->next->prev = cur->prev;

delete cur;

}

}

If we found the element, it does not mean any emptyness!

Page 87: List, (dynamic) linked list

Inserting a Node Insert a Node New after dummy node and

before Cur

Head

Dummy Head Node

Cur

20

New->next = Cur;

New->prev = Cur->prev;

Cur->prev = New;

(New->prev)->next = New;

10

New

Page 88: List, (dynamic) linked list

Insert a Node New at Rear (with Cur pointing to dummy head)

New->next = Cur;

New->prev = Cur->prev;

Cur->prev = New;

(New->prev)->next = New;

7020 5540

Head

10Dummy Head Node

Cur New

Page 89: List, (dynamic) linked list

Insert a Node New in the middle and before Cur

New->next = Cur;

New->prev = Cur->prev;

Cur->prev = New;

(New->prev)->next = New;

55

Head

10Dummy Head Node

20

Cur

40

New

Page 90: List, (dynamic) linked list

Insert a Node New to Empty List (with Cur pointing to dummy head node)

Head

Dummy Head Node

New

20

New->next = Cur;

New->prev = Cur->prev;

Cur->prev = New;

(New->prev)->next = New;

Cur

Page 91: List, (dynamic) linked list

void insertNode(NodePtr head, int item){ NodePtr newp, cur; newp = new Node;

newp->data = item; cur = head->next; while ((cur != head)&&(!(item<=cur->data)))

cur = cur->next;

newp->next = cur; newp->prev = cur->prev; cur->prev = newp;

(newp->prev)->next = newp;}

It is similar to, but different from SearchNode!

(it returns NULL if no element)

creation

location

insertion

Page 92: List, (dynamic) linked list

void main(){ NodePtr Head, temp; createHead(Head); insertNode(Head, 3); insertNode(Head, 5); insertNode(Head, 2); print(Head); insertNode(Head, 7); insertNode(Head, 1); insertNode(Head, 8); print(Head); deleteNode(Head, 7); deleteNode(Head, 0); print(Head); temp = searchNode(Head, 5); if(temp !=NULL) cout<<" Data is contained in the list"<<endl; else cout<<" Data is NOT contained in the list"<<endl; }

Result is

2 3 5

1 2 3 5 7 8

1 2 3 5 8

Data is contained in the list

Page 93: List, (dynamic) linked list

Stacks and Queues

Page 94: List, (dynamic) linked list

struct Node{ double data;Node* next;

};

class List {public:

List(); // constructorList(const List& list); // copy constructor~List(); // destructorList& operator=(const List& list); // assignment operator

bool empty() const; // boolean functionvoid addHead(double x); // add to the headdouble deleteHead(); // delete the head and get the head element// List& rest(); // get the rest of the list with the head removed// double headElement() const; // get the head element

void addEnd(double x); // add to the enddouble deleteEnd(); // delete the end and get the end element// double endElement(); // get the element at the end

bool searchNode(double x); // search for a given xvoid insertNode(double x); // insert x in a sorted listvoid deleteNode(double x); // delete x in a sorted list

void print() const; // outputint length() const; // count the number of elements

private:Node* head;

};

More complete list ADT

Page 95: List, (dynamic) linked list

Stack Overview

Stack ADT Basic operations of stack

Pushing, popping etc.

Implementations of stacks using array linked list

Page 96: List, (dynamic) linked list

Stack

A stack is a list in which insertion and deletion take place at the same end This end is called top The other end is called bottom

Stacks are known as LIFO (Last In, First Out) lists. The last element inserted will be the first to be retrieved

Page 97: List, (dynamic) linked list

Push and Pop

Primary operations: Push and Pop Push

Add an element to the top of the stack

Pop Remove the element at the top of the stack

top

empty stack

Atop

push an element

top

push another

A

Btop

pop

A

Page 98: List, (dynamic) linked list

Implementation of Stacks

Any list implementation could be used to implement a stack Arrays (static: the size of stack is given initially) Linked lists (dynamic: never become full)

We will explore implementations based on array and linked list

Page 99: List, (dynamic) linked list

class Stack {public:

Stack(); // constructorStack(const Stack& stack); // copy constructor~Stack(); // destructor

bool empty() const; void push(const double x); double pop(); // change the stack

double top() const; // keep the stack unchanged

// bool full(); // optional// void print() const;

private:…

};

Stack ADT

Compare with List, see that it’s ‘operations’ that define the type!

inspection, access

Page 100: List, (dynamic) linked list

Using Stack

int main(void) {Stack stack;stack.push(5.0);stack.push(6.5);stack.push(-3.0);stack.push(-8.0);stack.print();cout << "Top: " << stack.top() << endl;

stack.pop();cout << "Top: " << stack.top() << endl;while (!stack.empty()) stack.pop();stack.print();return 0;

}

result

Page 101: List, (dynamic) linked list

struct Node{ public:

double data;Node* next;

};

class Stack {public:

Stack(); // constructorStack(const Stack& stack); // copy constructor~Stack(); // destructor

bool empty() const; void push(const double x); double pop(); // change the stack

bool full(); // unnecessary for linked listsdouble top() const; // keep the stack unchanged

void print() const;

private:Node* top;

};

Stack using linked lists

Page 102: List, (dynamic) linked list

void List::addHead(int newdata){

Nodeptr newPtr = new Node;

newPtr->data = newdata;

newPtr->next = head;

head = newPtr;

}

void Stack::push(double x){

Node* newPtr = new Node;

newPtr->data = x;

newPtr->next = top;

top = newPtr;

}

From ‘addHead’ to ‘push’

Push (addHead), Pop (deleteHead)

Page 103: List, (dynamic) linked list

Implementation based on ‘existing’ linked lists

Optional to learn Good to see that we may ‘re-use’ linked lists

Page 104: List, (dynamic) linked list

Now let’s implement a stack based on a linked list To make the best out of the code of List, we implement Stack

by inheriting the List To let Stack access private member head, we make Stack

as a friend of List

class List {public:

List() { head = NULL; } // constructor~List(); // destructor

bool empty() { return head == NULL; }Node* insertNode(int index, double x);int deleteNode(double x);

int searchNode(double x);void printList(void);

private:Node* head;friend class Stack;

};

Page 105: List, (dynamic) linked list

class Stack : public List {public:

Stack() {}~Stack() {}double top() {

if (head == NULL) {cout << "Error: the stack is empty." << endl;return -1;

}else

return head->data;}void push(const double x) { InsertNode(0, x); }double pop() {

if (head == NULL) {cout << "Error: the stack is empty." << endl;return -1;

}else {

double val = head->data;DeleteNode(val);return val;

}}

void printStack() { printList(); }};

Note: the stack implementation based on a linked list will never be full.

from List

Page 106: List, (dynamic) linked list

Stack using arrays

class Stack {public:

Stack(int size = 10); // constructor~Stack() { delete [] values; } // destructor

bool empty() { return top == -1; }void push(const double x);double pop();

bool full() { return top == maxTop; }double top();void print();

private:int maxTop; // max stack size = size - 1int top; // current top of stackdouble* values; // element array

};

Page 107: List, (dynamic) linked list

Attributes of Stack maxTop: the max size of stack top: the index of the top element of stack values: point to an array which stores elements of stack

Operations of Stack empty: return true if stack is empty, return false otherwise full: return true if stack is full, return false otherwise top: return the element at the top of stack push: add an element to the top of stack pop: delete the element at the top of stack print: print all the data in the stack

Page 108: List, (dynamic) linked list

Allocate a stack array of size. By default, size = 10.

Initially top is set to -1. It means the stack is empty. When the stack is full, top will have its maximum value, i.e.

size – 1.

Stack::Stack(int size /*= 10*/) {values = new double[size];top = -1;

maxTop = size - 1;}

Although the constructor dynamically allocates the stack array, the stack is still static. The size is fixed after the initialization.

Stack constructor

Page 109: List, (dynamic) linked list

void push(const double x); Push an element onto the stack Note top always represents the index of the top

element. After pushing an element, increment top.

void Stack::push(const double x) {if (full()) // if stack is full, print error

cout << "Error: the stack is full." << endl;else

values[++top] = x;}

Page 110: List, (dynamic) linked list

double pop() Pop and return the element at the top of the stack Don’t forgot to decrement top

double Stack::pop() {if (empty()) { //if stack is empty, print error

cout << "Error: the stack is empty." << endl;return -1;

}else {

return values[top--];}

}

Page 111: List, (dynamic) linked list

double top() Return the top element of the stack Unlike pop, this function does not remove the top

element

double Stack::top() {if (empty()) {

cout << "Error: the stack is empty." << endl;return -1;

}else

return values[top];}

Page 112: List, (dynamic) linked list

void print() Print all the elements

void Stack::print() {cout << "top -->";for (int i = top; i >= 0; i--)

cout << "\t|\t" << values[i] << "\t|" << endl;cout << "\t|---------------|" << endl;

}

Page 113: List, (dynamic) linked list

Stack Application: Balancing Symbols

To check that every right brace, bracket, and parentheses must correspond to its left counterpart e.g. [( )] is legal, but [( ] ) is illegal

How? Need to memorize Use a counter, several counters, each for a type of

parenthesis …

Page 114: List, (dynamic) linked list

Balancing Symbols using a stack

Algorithm(1)   Make an empty stack.(2)   Read characters until end of file

i.    If the character is an opening symbol, push it onto the stackii.   If it is a closing symbol, then if the stack is empty, report an erroriii.  Otherwise, pop the stack. If the symbol popped is not the corresponding opening symbol, then report an error

(3)   At end of file, if the stack is not empty, report an error

Page 115: List, (dynamic) linked list

Stack Application: postfix, infix expressions and

calculator Postfix expressions

a b c * + d e * f + g * + Operands are in a stack

Convert infix to postfix a+b*c+(d*e+f)*g a b c * + d e * f + g * + Operators are in a stack

Calculator Adding more operators …

Page 116: List, (dynamic) linked list

Stack Application: function calls and recursion

Take the example of factorial! And run it.

#include <iostream>using namespace std;

int fac(int n){int product;if(n <= 1) product = 1;else product = n * fac(n-1);return product;

}

void main(){int number;cout << "Enter a positive integer : " << endl;;cin >> number;cout << fac(number) << endl;

}

Page 117: List, (dynamic) linked list

Stack Application: function calls and recursion

Take the example of factorial! And run it.

#include <iostream>using namespace std;

int fac(int n){int product;if(n <= 1) product = 1;else product = n * fac(n-1);return product;

}

void main(){int number;cout << "Enter a positive integer : " << endl;;cin >> number;cout << fac(number) << endl;

}

Page 118: List, (dynamic) linked list

Assume the number typed is 3. fac(3): has the final returned value 6

3<=1 ? No.

product3 = 3*fac(2) product3=3*2=6, return 6,

fac(2):2<=1 ? No.

product2 = 2*fac(1) product2=2*1=2, return 2,

fac(1):1<=1 ? Yes.return 1

Tracing the program …

Page 119: List, (dynamic) linked list

fac(3) prod3=3*fac(2)

prod2=2*fac(1)fac(2)

fac(1) prod1=1

Call is to ‘push’ and return is to ‘pop’!

top

Page 120: List, (dynamic) linked list

Array versus linked list implementations

push, pop, top are all constant-time operations in both array and linked list implementation Caveat: insertNode and deleteNode have to

be done at the beginning of the list! For array implementation, the operations are

performed in very fast constant time

Page 121: List, (dynamic) linked list

Queue Overview

Queue ADT Basic operations of queue

Enqueuing, dequeuing etc.

Implementation of queue Linked list Array

Page 122: List, (dynamic) linked list

Queue

A queue is also a list. However, insertion is done at one end, while deletion is performed at the other end.

It is “First In, First Out (FIFO)” order. Like customers standing in a check-out line in a

store, the first customer in is the first customer served.

Page 123: List, (dynamic) linked list

Enqueue and Dequeue

Primary queue operations: Enqueue and Dequeue Like check-out lines in a store, a queue has a front

and a rear. Enqueue – insert an element at the rear of the

queue Dequeue – remove an element from the front of

the queue

Insert (Enqueue)

Remove(Dequeue) rearfront

Page 124: List, (dynamic) linked list

Implementation of Queue

Just as stacks can be implemented as arrays or linked lists, so with queues.

Dynamic queues have the same advantages over static queues as dynamic stacks have over static stacks

(“static” should be interpreted as “non-dynamic” here!)

Page 125: List, (dynamic) linked list

class Queue {public:

Queue();Queue(Queue& queue);~Queue();

bool empty();void enqueue(double x);double dequeue();

void print(void);// bool full(); // optional

private:…

};

Queue ADT

‘physical’ constructor/destructor

‘logical’ constructor/destructor

Page 126: List, (dynamic) linked list

Using Queueint main(void) {

Queue queue;cout << "Enqueue 5 items." << endl;for (int x = 0; x < 5; x++)

queue.enqueue(x);cout << "Now attempting to enqueue again..." << endl;queue.enqueue(5);queue.print();double value;value=queue.dequeue();cout << "Retrieved element = " << value << endl;queue.print();queue.enqueue(7);queue.print();return 0;

}

Page 127: List, (dynamic) linked list

Struct Node {double data;Node* next;

}

class Queue {public:

Queue();Queue(Queue& queue);~Queue();

bool empty();void enqueue(double x);double dequeue();

// bool full(); // optionalvoid print(void);

private:Node* front; // pointer to front nodeNode* rear; // pointer to last nodeint counter; // number of elements

};

Queue using linked lists

Page 128: List, (dynamic) linked list

class Queue {public:

Queue() { // constructorfront = rear = NULL;counter = 0;

}~Queue() { // destructor

double value;while (!empty()) dequeue(value);

}bool empty() {

if (counter) return false;else return true;

}void enqueue(double x);double dequeue();

// bool full() {return false;};void print(void);

private:Node* front; // pointer to front nodeNode* rear; // pointer to last nodeint counter; // number of elements, not compulsary

};

Implementation of some online member functions …

Page 129: List, (dynamic) linked list

Enqueue (addEnd)void Queue::enqueue(double x) {

Node* newNode = new Node;newNode->data = x;newNode->next = NULL;

if (empty()) {front = newNode;

}else {

rear->next = newNode;}

rear = newNode;counter++;

}

8

rear

rear

newNode

5

58

Page 130: List, (dynamic) linked list

Dequeue (deleteHead)double Queue::dequeue() {

double x;if (empty()) {

cout << "Error: the queue is empty." << endl;exit(1); // return false;

}else {

x = front->data;Node* nextNode = front->next;delete front;front = nextNode;counter--;

}return x;

}

front

583

8 5

front

Page 131: List, (dynamic) linked list

Printing all the elements

void Queue::print() {cout << "front -->";Node* currNode = front;for (int i = 0; i < counter; i++) {

if (i == 0) cout << "\t";else cout << "\t\t"; cout << currNode->data;if (i != counter - 1)

cout << endl;else

cout << "\t<-- rear" << endl;currNode = currNode->next;

}}

Page 132: List, (dynamic) linked list

Queue using Arrays There are several different algorithms to

implement Enqueue and Dequeue Naïve way

When enqueuing, the front index is always fixed and the rear index moves forward in the array.

front

rear

Enqueue(3)

3

front

rear

Enqueue(6)

3 6

front

rear

Enqueue(9)

3 6 9

Page 133: List, (dynamic) linked list

Naïve way (cont’d) When dequeuing, the front index is fixed, and the

element at the front the queue is removed. Move all the elements after it by one position. (Inefficient!!!)

Dequeue()

front

rear

6 9

Dequeue() Dequeue()

front

rear

9

rear = -1

front

Page 134: List, (dynamic) linked list

A better way When enqueued, the rear index moves forward. When dequeued, the front index also moves forward

by one element

XXXXOOOOO (rear) OXXXXOOOO (after 1 dequeue, and 1 enqueue)OOXXXXXOO (after another dequeue, and 2 enqueues)OOOOXXXXX (after 2 more dequeues, and 2 enqueues)

(front)

The problem here is that the rear index cannot move beyond the last element in the array.

Page 135: List, (dynamic) linked list

Using Circular Arrays

Using a circular array When an element moves past the end of a circular

array, it wraps around to the beginning, e.g. OOOOO7963 4OOOO7963 (after Enqueue(4))

How to detect an empty or full queue, using a circular array algorithm? Use a counter of the number of elements in the queue.

Page 136: List, (dynamic) linked list

class Queue {public:

Queue(int size = 10); // constructorQueue(const Queue& queue);

~Queue() { delete [] values; } // destructor

bool empty(void);void enqueue(double x); // or bool enqueue();double dequeue();

bool full();void print(void);

private:int front; // front indexint rear; // rear indexint counter; // number of elementsint maxSize; // size of array queuedouble* values; // element array

};

full() is not essential, can be embedded

Page 137: List, (dynamic) linked list

Attributes of Queue front/rear: front/rear index counter: number of elements in the queue maxSize: capacity of the queue values: point to an array which stores elements of the queue

Operations of Queue empty: return true if queue is empty, return false otherwise full: return true if queue is full, return false otherwise enqueue: add an element to the rear of queue dequeue: delete the element at the front of queue print: print all the data

Page 138: List, (dynamic) linked list

Queue constructor

Queue(int size = 10) Allocate a queue array of size. By default, size = 10. front is set to 0, pointing to the first element of the

array rear is set to -1. The queue is empty initially.

Queue::Queue(int size /* = 10 */) {values = new double[size];maxSize = size;front = 0;rear = -1;counter = 0;

}

Page 139: List, (dynamic) linked list

Empty & Full Since we keep track of the number of elements

that are actually in the queue: counter, it is easy to check if the queue is empty or full.

bool Queue::empty() {if (counter==0) return true;else return false;

}bool Queue::full() {

if (counter < maxSize) return false;else return true;

}

Page 140: List, (dynamic) linked list

Enqueue

void Queue::enqueue(double x) {if (full()) {

cout << "Error: the queue is full." << endl;exit(1); // return false;

}else {

// calculate the new rear position (circular)rear = (rear + 1) % maxSize; // insert new itemvalues[rear] = x;// update countercounter++;// return true;

}}

Or ‘bool’ if you want

Page 141: List, (dynamic) linked list

Dequeue

double Queue::dequeue() {double x;if (empty()) {

cout << "Error: the queue is empty." << endl;exit(1); // return false;

}else {

// retrieve the front itemx = values[front];// move front front = (front + 1) % maxSize;// update countercounter--;// return true;

}return x;

}

Page 142: List, (dynamic) linked list

Printing the elements

void Queue::print() {cout << "front -->";for (int i = 0; i < counter; i++) {

if (i == 0) cout << "\t";else cout << "\t\t"; cout << values[(front + i) % maxSize];if (i != counter - 1)

cout << endl;else

cout << "\t<-- rear" << endl;}

}

Page 143: List, (dynamic) linked list

Using Queueint main(void) {

Queue queue;cout << "Enqueue 5 items." << endl;for (int x = 0; x < 5; x++)

queue.enqueue(x);cout << "Now attempting to enqueue again..." << endl;queue.enqueue(5);queue.print();double value;value=queue.dequeue();cout << "Retrieved element = " << value << endl;queue.print();queue.enqueue(7);queue.print();return 0;

}

Page 144: List, (dynamic) linked list

Results

Queue implemented using linked list will be never full!

based on array based on linked list

Page 145: List, (dynamic) linked list

Queue applications

When jobs are sent to a printer, in order of arrival, a queue.

Customers at ticket counters …