Download presentation
Presentation is loading. Please wait.
1
as an abstract data structure and
Concept of lists, as an abstract data structure and Implementations of lists, with arrays and others
2
‘pointer’ is only an implementation issue
Indices (relative addresses), indexing variable, array elements (absolute) addresses, pointer, and elements
3
A simple ‘list’ example (not ‘linked list’!)
Concept of a list, e.g. a list of integers A list is a linear sequence of objects Print out info Empty test Search Insertion 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 …
4
Using a (static) array How to use a list? Static array!
const int DIM=1000; int main() { int A[DIM]; int n; cin >> n; … } int main() { int A[1000]; int n; cin >> n; initialize(A, n, 0); print(A, n); addEnd(A,n,5); // or A = addEnd(A,n,5); addHead(A,n,5); // or A = addHead(A,n,5); deleteFirst(A,n); // or A = deleteFirst(A,n); selectionSort(A, n); } Static array! How to use a list?
5
Initialize void initialize(int list[], int size, int value){
for(int i=0; i<size; i++) list[i] = value; }
6
Print out a list void print(int list[], int size) {
cout << "[ "; for(int i=0; i<size; i++) cout << list[i] << " "; cout << "]" << endl; }
7
Delete the first element
// for deleting the first element of the array void deleteFirst(int list[], int& size){ for(int i=0; i<size-1; i++) list[i] = list[i+1]; size--; } deleteFirst(A,n) int* deleteFirst(int list[], int& size){ for(int i=0; i<size-1; i++) list[i] = list[i+1]; size--; return list; } B = deleteFirst(A,n) If A is an array name, we cannot A = deleteFirst(A,n) as A is a ‘constant pointer’ But if A is a pointer, we can do A = deleteFirst(A,n). A = deleteFirst(A,n) is also OK for a dynamic array for it is merely a pointer. Pointer type!
8
int* deleteFirst(int* head, int& size){
return head++; } int* deleteFirst(int list[], int& size){ for(int i=0; i<size-1; i++) list[i] = list[i+1]; size--; return list; } int* deleteFirst(int* list, int& size){ for(int i=0; i<size-1; i++) *(list+i) = *(list+i+1); size--; return list; } int* deleteFirst(int* head, int& size){ for(int i=0; i<size-1; i++) *(head+i) = *(head+i+1); size--; return head; }
9
Adding Elements addEnd(A,n,v) If not full! B = addEnd(A,n,v)
// for adding a new element to end of array void addEnd(int list[], int& size, int value){ if (size < DIM) { list[size] = value; size++; } addEnd(A,n,v) If not full! int* addEnd(int list[], int& size, int value){ if ((size>0) && (size < DIM)) { list[size] = value; size++; } return list; B = addEnd(A,n,v)
10
Add at the beginning: addHead(A,n,v) B = addHead(A,n,v)
// for adding a new element at the beginning of the array void addHead(int list[], int& size, int value){ if(size < DIM){ for(int i=size-1; i>0; i--) list[i+1] = list[i]; list[0] = value; size++; } else cout << “out of array memory!!! << endl; addHead(A,n,v) int* addHead(int list[], int& size, int value){ if(size < DIM){ for(int i=size-1; i>0; i--) list[i+1] = list[i]; list[0] = value; size++; return list; } else … B = addHead(A,n,v)
11
Using a dynamic array int main() { cout << "Enter list size: ";
int n; cin >> n; int* A = new int[n]; … }
12
How to use a list? int A[1000]; int n; cin >> n; 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); A = addHead(A,n,5); A = deleteFirst(A,n); selectionSort(A, n); delete[] A; } int A[1000]; int n; cin >> n;
13
Initialize and Print-out: the same as before
void initialize(int list[], int size, int value){ for(int i=0; i<size; i++) list[i] = value; } void print(int list[], int size) { cout << "[ "; for(int i=0; i<size; i++) cout << list[i] << " "; cout << "]" << endl; }
14
Delete the first element
// for deleting the first element of the array int* deleteFirst(int list[], int& size){ int* newList; if (size>1) { newList = new int[size-1]; // make new array // copy and delete old array for(int i=0; i<size-1; i++) newList[i] = list[i+1]; delete[] list; size--; return newList; } else … If not empty!!!, cannot delete an empty list.
15
Remark: deleteFirst(A,n) if we define as a void type function:
Instead of A = deleteFirst(A,n) we can also just do deleteFirst(A,n) if we define as a void type function: void deleteFirst(int*& A, int& size) { … A = newList; } For a static array, A does not change, but the content of A changed. For a dynamic array, A changed!
16
Adding Elements // for adding a new element to end of array
int* addEnd(int list[], int& size, int value){ int* newList; newList = new int [size+1]; // make new array if(size){ // copy and delete old array for(int i=0; i<size; i++) newList[i] = list[i]; delete[] list; } newList[size] = value; size++; return newList; Not empty list
17
Add at the beginning: // for adding a new element at the beginning of the array int* addHead(int list[], int& size, int value){ int* newList; newList = new int [size+1]; // make new array if(size){ // copy and delete old array for(int i=0; i<size; i++) newList[i+1] = list[i]; delete[] list; } newList[0] = value; size++; return newList;
18
Search and delete … // for adding a new element to end of array
int* delete(int list[], int& size, int value){ Search the element in the array and get the position Shift all elements after it towards this position … }
19
Linked Lists
20
Motivation A “List” is a useful structure to hold a collection of data. Currently, we use arrays for lists Examples: List of ten students marks int studentMarks[10]; List of temperatures for the last two weeks double temperature[14];
21
Motivation list using static array list using dynamic array
int myArray[1000]; int n; We have to decide (to oversize) in advance the size of the array (list) list using dynamic array int* myArray; cin >> n; myArray = new int[n]; We allocate an array (list) of any specified size while the program is running linked-list (dynamic size) size = ?? The list is dynamic. It can grow and shrink to any size.
22
‘n’ is removed, so we don’t need to ‘care’ about it!
How to use a linked list? int main() { … initialize(A,0); print(A); A = addEnd(A,5); A = addHead(A,5); A = deleteFirst(A); selectionSort(A); } int main() { … initialize(A, n, 0); print(A, n); A = addEnd(A,n,5); A = addHead(A,n,5); A = deleteFirst(A,n); selectionSort(A, n); } ‘n’ is removed, so we don’t need to ‘care’ about it!
23
Now the link is explicit, any places!
Array naturally represents a (ordered) list, the link is implicit, consecutive and contiguous! Now the link is explicit, any places! Data 75 85 20 45 Link Link Data 45 85 20 75 20 45 75 85 Data Link
24
Linked List Structure Definition Definition Create a Node
struct Node { int data; Node* next; }; typedef Node* NodePtr; Create a Node NodePtr p; p = new Node; Delete a Node delete p; Definition struct Node { int data; Node* next; }; Create a Node Node* p; p = new Node; Delete a Node delete p;
25
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
26
Representing and accessing linked lists
20 45 75 85 Head We define a pointer NodePtr head; (also: Node* head) that points to the first node of the linked list. When the linked list is empty then head is NULL.
27
Passing a Linked List to a Function
It is roughly the same as for an array!!! l = deleteHead(l); node* deleteHead(node* list) {…}; 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 or using a function to return a new pointer value
28
Manipulation (implementation) of a Unsorted Linked List
29
Start the first node from scratch
head = NULL; Head NodePtr newPtr; newPtr = new Node; newPtr->data = 20; newPtr->next = NULL; head = newPtr; Head newPtr 20
30
Inserting a Node at the Beginning
newPtr = new Node; newPtr->data = 13; newPtr->next = Head; head = newPtr; 20 Head 13 newPtr
31
Keep going … Head newPtr 50 40 13 20
32
Adding an element to the head:
void addHead(NodePtr& head, int newdata){ NodePtr newPtr = new Node; newPtr->data = newdata; newPtr->next = Head; head = newPtr; }
33
It can also be written (more functionally) as:
NodePtr addHead(NodePtr head, int newdata){ NodePtr newPtr = new Node; newPtr->data = newdata; newPtr->next = Head; return newPtr; } Compare it with ‘addHead’ with a dynamic array implementation
34
Deleting the Head Node NodePtr p; p = head; head = head->next;
delete p; head (to delete) 50 40 13 20 p
35
Or as a function: void deleteHead(NodePtr& head){ if(head != NULL){
NodePtr p = head; head = head->next; delete p; } Or as a function: NodePtr deleteHead(NodePtr head){ if(head != NULL){ NodePtr p = head; head = head->next; delete p; } return head;
36
A (unsorted) list with linked data representation
struct Node { int data; Node* next; }; Data representation Operations void addHead(Node*& head, int newdata){ Node* newPtr = new Node; newPtr->data = newdata; newPtr->next = Head; head = newPtr; } void deleteHead(Node*& head){ if(head != NULL){ Node* p = head; head = head->next; delete p; } void …(…){ … }
37
Re-write … typedef List Node*; List addhead(List int data);
struct Node { int data; Node* next; }; void addHead(Node*& head, int newdata){ Node* newPtr = new Node; newPtr->data = newdata; newPtr->next = Head; head = newPtr; } typedef List Node*; List addhead(List int data); List deleteHead(List); void deleteHead(Node*& head){ if(head != NULL){ Node* p = head; head = head->next; delete p; } void …(…){ … }
38
Displaying a Linked List
p = head; print out (*p) p = p->next; print out (*p) head 20 45 p head 20 45 p
39
p++ p->next For an array: i p
A linked list is displayed by walking through its nodes one by one, and displaying their data fields (similar to an array!). void displayList(NodePtr head){ NodePtr p; p = head; while(p != NULL){ cout << p->data << endl; p = p->next; } p++ p->next For an array: void displayArray(int data[], int size) { int i; i=0; while ( i<size ) { cout << data[i] << endl; i++; } void displayArray(int data[], int size) { int* p; p=data; while ( (p-data)<size ) { cout << *p << endl; p++; } i p
40
Searching for a value in a linked list (look at array searching first
41
Remember searching algorithm in an array: It is essentially the same!
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; It is essentially the same!
42
If we use a pointer to an array, it will be even closer!
Searching for a value NodePtr searchNode(NodePtr head, int item){ NodePtr p = head; NodePtr position = NULL; bool found=false; while((p != NULL) && (!found)){ if(p->data == item) { found = true; position = p;} p = p->next; } return position; int searchArray(int data[], int size, int value){ int n=0; int position=-1; bool found=false; while ( (n<size) && (!found) ) { if(data[n] == value) { found=true; position=n;} n++; } return position; np If we use a pointer to an array, it will be even closer!
43
More operation: adding to the end
Original linked list of integers: Add to the end (insert at 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!
44
Link new object to last->next Link a new object to empty list
Add to the end: 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; Link new object to last->next Link a new object to empty list
45
Add to the end as a function:
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;
46
Manipulation (implementation) of a
Sorted Linked List
47
Inserting a value in a sorted list
How to do it in a sorted array? a static array and a dynamic array 1. Find the position 2. Free up the place by moving the others 3. Insert the new value
48
Inserting a Node 1. (a) Create a new node using: 20 33 45 75 ...
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; Head cur 20 33 45 75 prev ... newPtr
49
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
50
It’s a kind of search algo, Prev is necessary as we can’t go back!
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!
51
A useful programming ‘trick’: boolean ‘found’ can be avoided.
Finally, it is equivalent to: 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.
52
If the position happens to be the head
//insert item into linked list according to ascending order void 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 list newp->next = head; head = newp; } else { pre->next = newp; new->next = cur; If the position happens to be the head General case
53
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 (to delete) ... 20 45 75 85 prev cur
54
Delete an element in a sorted 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; else prev->next = cur->next; delete cur; Get the location If it’s in, negation of ‘not in’ We can delete only if the element is present! If (cur==NULL || cur->data!=item) Item is not in the list! If the element is at the head General case
55
Other variants of linked lists
56
Motivation: there are always many ‘special’ cases
the empty case the first element case the last element case the ‘middle’ element case … tedious implementation …
57
A note on ‘Dummy Head node’
A well-known implementation ‘trick’ or ‘method’: add one more node at the beginning, which does not store any data, to ease operations. always present, even when the linked list is empty Insertion and deletion algorithms initialize prev to reference the dummy head node, rather than NULL head empty list! head 40 13 20 Dummy head node list of (40,13,20)
58
Circular Linked Lists A Circular Linked List is a special type of Linked List It support the traversing from the end of the list to the beginning of the list by making the last node points back to the head of the list 10 20 40 55 70 Rear
59
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 70 20 55 40 Head Cur Cur->next Cur->prev
60
Doubly Linked List Definition
struct Node{ int data; Node* next; Node* prev; }; typedef Node* NodePtr;
61
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
62
Idea of ‘dummy’ object ‘dummy object’ is also called a ‘sentinel’, it allows the simplification of special cases, but confuses the emptyness NULL! Instead of pointing to NULL, point to the ‘dummy’!!! Skip over the dummy for the real list 70 20 55 40 Head 10 Dummy Head Node
63
Head->next = head; compared with head=NULL;
Empty list: Head Dummy Head Node Head->next = head; compared with head=NULL;
64
as an abstract data structure
Concept of lists, as an abstract data structure Implementations of lists, with arrays and others The same ‘list’ operators, different efficiencies
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.