Week 3
Week 3
html
C Programming
Basic
Linked List
For Data Structure and
Algorithms
Lecturers :
Cao Tuan Dung
Le Duc Trung
Dept of Software Engineering
Hanoi University of Technology
Today's topics
• Self referential structure in C
• Data structure “single linked LIST”
– Implementation of single linked LIST
– Algorithm for inserting, deleting,
traversing, …
• Data structure “double linked LIST”
– Implementation of double linked LIST
– Algorithm for inserting, deleting,
traversing, …
2
Self-Referential Structures
• One or more of its components is a
pointer to itself.
struct list {
char data;
struct list *link;
};
list item1, item2, item3; a b c
item1.data=‘a’;
item2.data=‘b’;
item3.data=‘c’;
item1.link=item2.link=item3.link=NULL;
3
Implemetation of List in C
• “LIST” means data structure that keeps the
information of the location of next element
generally.
• The elements of “Single linked LIST” have only
next location.
• In C, the pointer is used for the location of the
next element.
• Array: We can access any data immediately.
• Linked List: We can change the number of data in
it.
5
Hint
• you can organize elements and data
structure using following record structure
node_addr. Define by your self a structure
for storing information about an address.
6
Declaration of address list
typedef struct address_t {
char name[20];
char tel[11];
char email[25];
} address;
struct list_el {
address addr;
struct list_el *next;
};
typedef struct list_el node_addr;
7
Important 3 factors of a
LIST
• Root: It keeps the head of the list.
• NULL: The value of pointer. It means
the tail of the list.
• Cur: Pointer variable that keeps the
element just now.
cur
8
Initialisation
node_addr *root, *cur;
9
Make new node
node_addr* makeNewNode(){
node_addr* new = (node_addr*)
malloc(sizeof(node_addr));
strcpy((new->addr).name, « Tran Van Thanh »);
….
new->next =NULL;
return new;
}
..
root = makeNewNode();
cur = root;
10
Attention
• You can modify the makeNewNode function to
receive the data field as parameter:
11
Input Data for Node
address readNode(){
address tmp;
…..
return tmp;
}
12
Display node’s information
• Write the function displaying the
data inside a give node pointed by p.
13
Solution
void displayNode(node_addr* p){
if (p==NULL){printf(“Loi con tro NULL\n”);
return; }
address tmp = p->addr;
printf(“%-20s\t%-15s\t%-30s %p\n”, tmp.name,
tmp.tel, tmp.email, p->next);
}
void main(){
/* root = makeNewNode(); */
address tmp = readNode();
root = makeNewNode(tmp);
displayNode(root);
}
14
Exercise
• Create a singly linked list to store a list of
phone address.
• Write a function to insert to a list a new
element just after the current element and
use it to add node to the list
• Write a function for traversing the list to
print out all information stored.
• Write a function for the removal of a node
in the list.
15
Insert node at head of the
list
void insertAtHead(address addr){
node_addr* new = makeNewNode(addr);
new->next = root;
root = new;
cur = root;
}
16
Link list: insertion after the
current position
• Pseudo code
create new_item
new->next = cur->next;
cur->next = new;
cur= cur->next;
cur
…
root
new_item 17
insertion just after the
current position
/* input of a address struct variable addr */
…
new = makeNewNode(addr);
if ( root == NULL ) {
/* if there is no element */
root = new;
cur = root;
} else {
new->next=cur->next; …
cur->next = new;
/* prev=cur; */
cur = cur->next;
}
18
Insertion before current
position
• Another case: before the current position
prev cur
root
Insert new
item:
19
insertBeforeCurrent
void insertBeforeCurrent(address e) {
node_addr * new = makeNewNode(e);
if ( root == NULL ) {
/* if there is no element */
root = new;
cur = root;
prev = NULL;
} else {
new->next=cur;
/* if cur pointed to first element */
if (cur==root) {
/* nut moi them vao tro thanh dau danh sach */
root = new;
}
else prev->next = new;
cur = new;
}
}
20
If you do not frenquently
update pointer prev
/* determine prev if cur does
not point to first element */
tmp = root;
while (tmp->next!=cur && cur !
=NULL)
tmp=tmp->next;
prev = tmp;
21
Traversing a list
void traversingList(){
node_addr * p;
for ( p = root; p!= NULL; p = p->next )
displayNode(p);
}
cur
root NULL
22
Traversing a list
• Changing the value of pointer variable cur in
sequence.
• These variables are called “iterator.”
• The traversing is finished if the value is NULL
cur
root NULL
23
new test scenario
• Using a loop to input data to Linked
List then display the whole list.
void main(){
n=5;
while (n){
address tmp = readNode();
insertAtHead(tmp);
n--;
}
traversingList();
}
24
Deletion
• When we remove the first element
root = del->next; free(del);
• When we remove the first element,
change the value of “root” into the value
of “next” which is pointed by “del.”
del
root NULL
25
Delete first element
void deleteFirstElement() {
/* do it your self */
26
Delete first element of the
list
void deleteFirstElement(){
node_addr* del = root;
root = del->next;
free(del);
cur = root; /* prev = NULL; */
}
27
Deletion from the middle
• We want to remove the node pointed by cur
• Determine prev which point to the node just before the
node to delete
prev->next = cur->next;
free(cur);
cur = prev->next;
prev cur
root
28
Deletion from the middle
• Design and implement of
deleteCurrentElement function
/* Do it your self
*/
29
Solution: Delete element
pointed by cur
void deleteCurrentElement(){
if (cur==NULL) return;
if (cur==root) deleteFirstElement();
else {
prev->next = cur->next;
free(cur);
cur = prev->next;
}
30
Other useful function for
deleting node
• Delete the first node corresponding
to an address.
• void deleteElement(address adr);
31
Freeing a list
to_free = root ;
while (to_free != NULL) to_free root
{
root = root->next;
free(to_free);
to_free = root;
}
32
Freeing all nodes of a list
33
Freeing all nodes of a list
to_free = root ;
to_free root
while (to_free != NULL)
{
root = root->next;
free(to_free);
to_free = root;
}
34
Freeing all nodes of a list
35
Freeing all nodes of a list
36
Freeing all nodes of a list
37
Freeing all nodes of a list
38
Freeing all nodes of a list
39
Freeing all nodes of a list
40
Freeing all nodes of a list
41
Freeing all nodes of a list
42
Freeing all nodes of a list
43
Freeing all nodes of a list
44
Freeing all nodes of a list
45
Freeing all nodes of a list
46
Freeing all nodes of a list
47
Freeing all nodes of a list
NULL
48
Freeing all nodes of a list
NULL
49
Reverse a list
• Write a function that reverse a list.
1 2 3
3 2 1
50
Solution
node_addr* list_reverse (node_addr* root)
{
node_addr *cur, *prev;
cur = prev = NULL;
while (root != NULL) {
cur = root;
root = root->next;
cur->next = prev;
prev = cur;
}
return prev;
}
51
Exercise
• Write a program that reads data
from file phone.dat (created in
previous assignment) and load
them to a single linked list.
• You must use functions in your
linked list library
• Display the contacts stored in list.
• Ask user to input more contacts
and insert them to list in two ways:
– Before or after current position of cur
pointer.
52
Generic declaration of a
Linked List
typedef ... elementtype;
typedef struct node node;
typedef struct node{
elementtype element;
node* next;
};
node* root;
node* cur;
53
Memory allocation for an
element
• We need to allocate a memory bloc for
each node (element) via a pointer.
node * new;
new = (node*) malloc(sizeof(node));
new->element = …
new->next = null;
• Attention:
– new->addr means (*new).addr.
– “pointer variable for record structure” ->
“member name”
54
makeNewNode() - generic
node* makeNewNode(elementtype addr){
node* new = (node*)
malloc(sizeof(node));
new->element=addr;
new->next =NULL;
return new;
}
55
insertion just after the
current position (generic)
void insertAfterCurrent(elementtype e) {
56
insertBeforeCurrent
void insertBeforeCurrent(elementtype e) {
new->next=cur;
/* if cur pointed to first element */
if (cur==root) {
root = new; /* nut moi them vao tro thanh dau danh sach
*/
}
else prev->next = new;
cur = new;
}
}
57
Read/Write specific data
elementtype readData(){
elementtype res;
printf("name:");gets(res.name);
printf("tel:");gets(res.tel);
printf("email:");gets(res.email);
return res;
}
void printData(elementtype res){
printf("%15s\t%10s\t
%20s\n",res.name, res.tel,
res.email);
}
58
Traversing a List (generic)
void traverseList() {
node* p;
for (p = root; p !=
NULL; p = p->next ) {
printData(p-
>element);
}
59
Generic version
node* list_reverse (node* root)
{
node *cur, *prev;
cur = prev = NULL;
while (root != NULL) {
cur = root;
root = root->next;
cur->next = prev;
prev = cur;
}
return prev;
}
60
Delete an element with
given data
• Write API of linkedlist library
61
Exercise
• Implement function insert, delete with a
parameter n (integer) indicating the
position of node to be affected.
– The head position means 0th.
– 1st means that we want to add the element into
the next place of the first element.
– 2nd means the next place of the second element.
Kết quả insert trả về contrỏ trỏ tới nút vừa thêm
trong danh sách. Kết quả delete trả về root của
danh sách sau khi xóa 62
generic version
Node * insertAtPosition(elementType ad, int n){
int i=0;
node* p = root;
node* new, prev =p;
if (n==0 || root==NULL) {
new = makeNewNode(ad); new->next=root;
root=new; cur= new; return new;
}
while ((i<n) && (p->next!= NULL)) { prev=p; p=p-
>next; i++;}
if (i<n) prev = p;
new = makeNewNode(ad); new->next = prev->next;
prev->next = new; cur = new;
return new;
} 63
delete generic version
Node * deleteAtPosition(int n){
int i=0;
node* p = root;
node* del, prev =p;
if (n==0 || root==NULL) {
del = root; root=del->next; cur= root;
free(del); cur=root; return root;
}
while ((i<n) && (p->next!= NULL)) { prev=p; p=p-
>next; i++;}
if (i<n) return root; // do nothing
prev->next = p->next;
free(p);
cur=root; return root;
} 64
Exercise II
• Add to program in exercise I two
functionalities: insert and delete element
at given position.
– You must use two functions in your library
• Implement a searching function by
– Phone number
– Name
• Test inverseList function.
65
Exercise III
• a) Write and test splitList function
– Divide list in to 2 sub-lists.
– Syntax split n1 n2: n1: start position (indexed
from 0) – n2 number of element of sublist 1.
The rest is the sublist 2
• b) Write a function that print the content
of a list to a text file. Parameters are root
pointer and file path. Use this function to
view the sublists.
• c) Test data: Phone.dat
66
ICT55 - homework
• Make a improved version of NokiaDB Phone
management program using linked list. Here is
the functionalities in the menu:
– 1. Import from Text: read data from text file and
build the list
– 2. Import from Dat: read data from .dat file and
build the list
– 3. Display List: Display all elements, each element
in a line.
– 4. Search phone by Model
– 5. Search phone of which the price is under the
value inputted.
– 6. Export to Dat: store information in linked list to
NokiaDB.dat
– 7. Quit
67
Bài Tập VN K55C
• Hoàn thiện Bài tập Danh Bạ trên lớp
• Bổ sung hàm xóa toàn bộ danh sách
• Bổ sung hàm chèn 1 phần tử vào trước
phần tử Cur
• Bổ sung hàm Tìm một phần tử có trong
danh sách không (tìm theo số điện thoại)
• Khi thoat – Lưu toàn bộ nội dung danh
sách vào
• file text: contact.txt (1 dòng – 1 element)
• file dat: contact.dat
68
Tổng kết các chức năng của
Bài tập
• 1. Import from NokiaDB.dat (insertafter)
• 2. Display (traverse)
• 3. Add new phone (insertbefore/after)
• 4. Insert at Position
• 5. Delete at Position
• 6. Delete current
• 7. Delete first
• 8. Search and Update
• 9. Divide and Extract
• 10. Reverse List
• 11. Save to File
• 12. Quit(Free)
69
Exercise 3-3
• Develop a simple student management program
using linked list composed of node like this:
70
Exercise 3-3
so that:
- The list is sorted in descending order of
student's grades.
- Program provide the functionality of:
- Insert new student (when you insert a new
student into this list, first find the right
position)
- searching a student by ID: return to a pointer
- delete a student with a given ID
- ;
71
Adding a student - begining
Next
root
root
72
Adding a student – mid/end
Previous Next
root
Insert new
item:
73
Student *add_student(Student *root, Student *to_add)
{
Student *curr_std, *prev_std = NULL;
if (root == NULL)
return to_add;
handle empty list
if (to_add->grade > root->grade)
{
to_add->next = root; handle beginning
return to_add;
}
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
}
the rest
74
Adding a student –
beginning
if (root == NULL)
return to_add;
root 95 80 70 …
to_add 100
75
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
curr_std
root 95 80 70 60
to_add 75 76
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 77
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 78
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 79
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 80
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 81
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 82
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 83
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 84
Adding a student – mid /
end
curr_std = root;
while (curr_std != NULL && to_add->grade < curr_std->grade)
{
prev_std = curr_std;
curr_std = curr_std->next;
}
prev_std->next = to_add;
to_add->next = curr_std;
return root;
prev_std curr_std
root 95 80 70 60
to_add 75 85
Exercise
• Implement find_student, which receives
a list and an ID number and returns a
pointer to a student whose ID matches or
NULL if no such student is found.
87
Removing a student
• We would like to be able to remove a
student by her/his ID.
• The function that performs this is
remove_student
88
Removing a student -
reminder
Previous Current
root
89
Removing a student –
beginning
if (root == NULL) ID
return root;
14525
cur = root;
if (strcmp(cur->id, id) == 0)
{ cur last
root = root->next;
free(cur);
return root;
}
if (cur != NULL)
{
prev->next = cur->next;
free(cur);
}
return root;
cur
if (cur != NULL)
{
prev->next = cur->next;
free(cur);
}
return root;
prev cur
if (cur != NULL)
{
prev->next = cur->next;
free(cur);
}
return root;
prev cur
if (cur != NULL)
{
prev->next = cur->next;
free(cur);
}
return root;
prev cur
if (cur != NULL)
{
prev->next = cur->next;
free(cur);
}
return root;
prev cur
96
solution
Student *find_student(Student* root, char* id)
{
Student* curr = root;
return curr;
}
97
Bài tập
• Reuse file grade.dat (output previous
assignment) as the input of STUDENT
MANAGEMENT program. It has an menu-based
interface.
• Apart from the functionalities already
implemented on class such as Add new, delete,
search and update grade, do the following tasks:
– Print the student list in ascending order of grades.
– Compute the average grade of the class
– Classify grades in to 3 categories:
• Average: The difference with the average grade is not
greater than 0.5
• Good: greater than 0.5
• Bad: smaller than average depass 0.5
– Store the classification to a file.
98
Bài tập – List - NokiaDB
• Viết chương trình NokiaManager cho phép
– Import NokiaDB.dat (BT tuần trước) vào danh sách liên kết
đơn – Hiển thị
– Bổ sung hai chức năng: tìm kiếm đơn giản theo model và cập
nhật (update) thông tin cho một điện thoại.
– Hiển thị tất cả các điện thoại trong danh sách mà Model bắt
đầu bởi một chữ cái nhập từ người dùng:
• VD: n, e
• In ra danh sách các điện thoại model cùng bắt đầu bởi một chữ cái
sắp xếp theo giá tiền.
– Xóa tất cả các điện thoại trong danh sách theo chữ cái bắt đầu
của model
– Xóa n (nhập từ bàn phím) nút kể từ nút có model cụ thể.
– In ra danh sách sắp xếp theo giá tiền
– In ra danh sách các điện thoại có giá nhỏ hơn một giá trị nhập
99
Question
• We are now designing “address list” for mobile phones.
• You must declare a record structure that can keep a name,
a phone number, and a e-mail address at least. And you
must make the program which can deals with any number
of the data.
• Hint: you can organize elements and data structure using
following record structure AddressList
struct AddressList {
struct AddressList *prev;
struct AddressList *next;
struct Address addr;
};
100
Double link list
• An element has 2 pointer fields, we can
follow front and back.
tail
/
5 12 5
head
/
101
Declaration
typedef ... elementtype;
typedef struct node node;
typedef struct node{
elementtype element;
node* prev;
node* next;
};
typedef node* doublelist;
doublelist head, tail, cur;
102
Initialisation and check for
emptiness
void MakeNull_List (doublelist *root,
doublist *tail, doublist *cur){
(*root)= NULL;
(*tail)= NULL; (*cur)= NULL;
}
int isEmpty (doublist root){
return (root==NULL);
}
103
makeNewNode() - generic
node* makeNewNode(elementtype addr){
node* new = (node*)
malloc(sizeof(node));
new->element=addr;
new->next =NULL;
new->prev =NULL;
return new;
}
104
insertion just after the
current position (generic)
void insertAfterCurrent(elementtype e, doublelist
*root, doublelist *tail, doublelist *cur) {
node* new = makeNewNode(e);
if ( *root == NULL ) {
/* if there is no element */
*root = new; *tail=new;
*cur = *root;
} else {
new->next=(*cur)->next;
if ((*cur)->next!=NULL)(*cur)->next->prev=new;
new->prev=*cur;
(*cur)->next = new;
*cur = new;
if (new->next==NULL) *tail = new;
}
} 105
insertBeforeCurrent
void insertBeforeCurrent(elementtype e) {
new->next=cur;
/* if cur pointed to first element */
if (cur==root) {
root = new; /* nut moi them vao tro thanh dau danh sach
*/
}
else prev->next = new;
cur = new;
}
}
106
Delete a node pointed by p
void Delete_List (doublelist p, doublelist *root){
if (*root == NULL) printf(”Empty list”);
else {
if (p==*root) (*root)=(*root)->Next;
//Delete first element
else p->prev->next=p->next;
if (p->next!=NULL) p->next->prev=p->prev;
free(p);
}
}
/
root
8 5 12 5
p 107
Delete a node pointed by p
void Delete_List (doublelist p, doublelist *root){
if (*root == NULL) printf(”Empty list”);
else {
if (p==*root) (*root)=(*root)->Next;
//Delete first element
else p->prev->next=p->next;
if (p->next!=NULL) p->next->prev=p->prev;
free(p);
}
}
/
root
8 5 12 5
p 108
Delete a node pointed by p
void Delete_List (Position p, DoubleList *DL){
if (*DL == NULL) printf(”Empty list”);
else {
if (p==*DL) (*DL)=(*DL)->Next;
//Delete first element
else p->Previous->Next=p->Next;
if (p->Next!=NULL) p->Next->Previous=p->Previous;
free(p);
}
}
/
DL
8 5 5
p 109
Insertion
void Insert_List (ElementType X,Position p, DoubleList *DL){
if (*DL == NULL){ // List is empty
(*DL)=(Node*)malloc(sizeof(Node));
(*DL)->Element = X;
(*DL)->Previous =NULL;
(*DL)->Next =NULL;
}
else{
Position temp;
temp=(Node*)malloc(sizeof(Node));
temp->Element=X;
temp->Next=p;
temp->Previous=p->Previous;
if (p->Previous!=NULL)
p->Previous->Next=temp;
p->Previous=temp;
}
}
110
Create a library
• Create lib.h • Compile
– Type declaration • gcc – o ex
– Function prototype pro.c lib.c
• Create lib.c
– #include “lib.h” Another way:
– Function Implementation gcc –c lib.c
gcc –c pro.c
• Main Program: pro.c
gcc –o lib.o pro.o
– #include “lib.h”
ex
111
Bài tập về nhà
• Xây dựng thư viện danh sách liên kết
đôi.
112
Chú ý:
• Cài đặt thư viện doublylinkedlist.h
• Cài đặt bài tập NokiaDB với các tính năng
bổ sung (chia tách, tìm kiếm theo chữ cái
đầu model)
• Từ dữ liệu grade.dat xây dựng chương trình
dùng danh sách móc nối đơn sắp xếp (theo
chiều giảm dần của điểm). Chương trình cho
phép
– Đọc file grade.dat nạp vào DS
– Bổ sung một sinh viên mới
– Xóa một sinh viên.
– In danh sách
113
Double linked list
• Using the library doubly linked list
and the data you have created in the
PhoneBook Exercise. Write a function
that:
– Count the max number of identical
phone number elements in a list.
– Split these elements from the list.
Display the memory address of these
element before and after the split
action. (Bài tập)
114
Nộp bài tập
• gửi mail attach source code vào
[email protected]
115
BTVN 2 – Double linked list
• Xây dựng chương trình giao diện menu với các chức
năng sau sử dụng thư viên dll.h (doublelinkedlist).
Chương trình có chức năng quản lý thông tin sinh
viên, điểm – dữ liệu load từ grade.dat và nhập từ
người dùng
116
Appendix
117
Bài tập 3 (Chương List)
• Bổ sung vào Menu chương trình
(Nokia DB List) chức năng đảo ngược
danh sách
• Kiểm tra bằng chức năng Duyệt.
118