2. Problem with Arrays
• Sometimes
◻Amount of data cannot be predicted beforehand
◻Number of data items keeps changing during program execution
• Example: N Number of employees in an organization(Increase/Decrease)
• One solution: find the maximum possible value of N and allocate an array of N
elements
◻Wasteful of memory space, as N may be much smaller in some executions
◻Example: maximum value of N may be 10,000, but a particular run may need to
search only among 100 elements
◻Using array of size 10,000 always wastes memory in most cases
3. Better Solution
• Dynamic memory allocation
◻Know how much memory is needed after the program is run
• Example: ask the user to enter from keyboard
◻Dynamically allocate only the amount of memory needed
• C provides functions to dynamically allocate memory
◻malloc, calloc, realloc
4. Dynamic Data Sets
• Sets can
– grow
– shrink
– change their size over time
• Such sets are called Dynamic Sets
5. Operations on Dynamic Sets
Dynamic operations grouped into two categories:
– Queries: return information about the sets
– Modifying operations: change structure of the sets
6. Typical Queries on Dynamic Sets
• SEARCH(S, k)
Input: A set S and a key value k
Output: Returns
– a pointer x to an element in S such that x.key = k
OR
– NIL if no such element belongs to S
• MINIMUM(S):
Input: A totally ordered set S
Output:
– Returns a pointer to the element of S with the smallest key
7. • MAXIMUM(S)
Input: A totally ordered set S
Output:
– Returns a pointer to the element of S with the largest key
• SUCCESSOR(S, x)
Input: An element x whose key is from a totally ordered set S
Output: Returns
– a pointer to the next larger element in S
– NIL if x is the maximum element in S
Typical Queries on Dynamic Sets
8. • PREDECESSOR(S, x)
Input: An element x whose key is from a totally ordered set S
Output: Returns
– a pointer to the next smaller element in S
– NIL if x is the minimum element in S
• SUCCESSOR(S, x) and PREDECESSOR(S, x) are extended to sets with
non-distinct keys
Typical Queries on Dynamic Sets
9. Modifying operations on Dynamic Sets
• INSERT(S, x)
Input: A set S and a pointer to x
(Assume that an attribute of x is already initialized)
Output:
– Augments S with the element pointed by x
• DELETE(S, x)
Input: A set S and a pointer to x (not a key value)
Output: Removes x from S
10. Dynamic Sets
• Each element is represented by an object
– A pointer to the object is used for examining and manipulating the
objects’ attributes
• Dynamic sets assume, one of the objects attribute is an identifying key
11. Dynamic Sets
• The object may contain satellite data, which are carried around in other
object attributes
• Object attributes - manipulated by set operations
– Attributes may contain data or pointers to other objects in the set
• Some dynamic sets – keys from a totally ordered set
12. Dynamic Memory Allocation Functions
• malloc()
◻Allocates requested number of bytes and returns a pointer to the first byte of the
allocated space
• calloc()
◻Allocates space for an array of elements, initializes them to zero and then returns a a
base pointer of the memory.
• free()
◻Frees previously allocated space.
• realloc()
◻Modifies the size of previously allocated space
13. Allocating a Block of Memory
• A block of memory can be allocated using the function malloc()
◻Reserves a block of memory of specified size and returns a pointer of
type void
◻The return pointer can be type-casted to any pointer type
• General format:
datatype *ptr = (cast type *) malloc (size*size of(datatype));
Eg: int *ptr=(int*)malloc(5*size of(int));
14. 14
Example
p = (int *) malloc(100 * sizeof(int));
◻ A memory space equivalent to 100 times the size of an int bytes
is reserved
◻The address of the first byte of the allocated memory is assigned
to the pointer p of type int
p
400 bytes of space
15. Cont…
• cptr = (char *) malloc (20);
Allocates 20 bytes of space for the pointer cptr of type char
• sptr = (struct stud *) malloc(10*sizeof(struct stud));
Allocates space for a structure array of 10 elements. sptr points to a
structure element of type struct stud
Always use sizeof operator to find number of bytes for a data type, as it can vary
from machine to machine
16. Cont…
• malloc() always allocates a block of contiguous bytes
◻The allocation can fail if sufficient contiguous memory
space is not available
◻If it fails, malloc() returns NULL
if ((p = (int *) malloc(100 * sizeof(int))) == NULL)
{
printf (“n Memory cannot be allocated”);
exit();
}
17. Releasing the Allocated Space:
free()
• An allocated block can be returned to the system for future use by using the
free function
• General syntax:
free (ptr);
where ptr is a pointer to a memory block which has been previously created
using malloc()
• Note that no size needs to be mentioned for the allocated block, the system
remembers it for each pointer returned
18. calloc()
calloc()
• datatype *ptr=(cast type *)calloc(size, sizeof(each datatype));
Eg: int *ptr=(int *)calloc(5,sizeof(int));
• Here each bit is initialized with zero
19. realloc() is to resize the memory allocated
using malloc() or calloc()
realloc()
*ptr=(int *)realloc(ptr,10*size of(int));
….
….
free(ptr); //Clear the ptr after all its use
20. Data Structures: A data structure is a way of organizing and storing data in a
computer so that it can be accessed and used efficiently.
Types Data Structure:
• 1. Linear Data Structure: Stacks, Queues,
Linked List(SLL,DLL,CLL,CDLL)
• 2. Non-Linear Data Structure: Trees, Graphs
21. Linked List
• Linked list is a data structure in which objects are arranged in a linear
order
– Linear order is determined by a pointer in each object
• Provides a simple, flexible representation for dynamic sets and it
supports all the operations (query & modifications)
• Different types of linked list:
– Singly Linked List (SLL)
– Doubly Linked List (DLL)
– Circular Linked List(CLL)
– Circular Doubly Linked List (CDLL)
22. Cont…
• A linked list is simply a chain of structures which contain a pointer to the next
element and it is dynamic in nature
• Items may be added to it or deleted from it.
• A list item has a pointer to the next element, or NIL if the current element is the
tail (end of the list).
• Pointer to the next element points to a structure of the same type as itself.
• This structure that contains elements and pointers to the next structure is called
a Node.
• The first node is always used as a reference to traverse the list and is called
HEAD. The last node(Tail) which points to NIL at the pointer.
23. Declaring a Linked list
Declaring a Linked list :
struct SLL{
int data;
struct SLL *next;
};
• The above definition is used to create every node in the list.
• The data field stores the element and the next is a pointer to store the address of the next node.
• In place of a data type, struct LinkedList is written before next. That's because its a self-referencing
pointer. It means a pointer that points to whatever it is a part of.
• Here, next is a part of a node and it holds a poiter to the next node.
24. SINGLY LINKED LIST (SLL)
10
Key Field
Next Field
Each element of SLL : An object
Attributes: Key and a Next pointer. Head.data=40,
Head.next= pointer to the next Node
20
30
40
Head
Tail
25. Cont…
• For every linked list there is a head node and there is a tail node
• Head.key hold the data value
• Head.next hold the address
• In a dynamic dataset like linked list the term ‘query’ is used to get a
response about list and the term ‘modification’ means insert or delete
some element into list.
26. Cont…
• An attribute Head points to the first element of the list.
• If Head = NIL, the list is empty
• Given an element x in the list, x.next points to its successor in the
linked list
• If x.next = NIL, the element x has no successor and is therefore the
last element, or tail, of the list.
27. Creation of Singly Linked List
struct SLL *Head=NIL;
typedef struct SLL node;
create_SLL(Head, k)
1. x=create_node(k)
2. if(Head==NIL)
3. Head=x
4. Tail=x
else
5. Tail.next=x
6. Tail=x
Creating a node and return its pointer if
memory created otherwise return NIL
create_node(k)
1. Allocate dynamic memory to temp
//node temp=(node)malloc(size of(node))
2. if(temp==NIL)
3. print “Memory not available”;
4. exit
else
5. temp.key=k
6. temp.next=NIL
7. return temp
28. Print Linked List
• Print_SLL prints the SLL by copying the Head into x. x travelling
from Head to till NIL by printing the data present at each node.
Print_SLL(Head)
1. x=Head
2. while x ≠NIL
3. print x.key
4. x=x.next
29. SLL Cont…
• The operations performed on a Singly linked list are :
• Create SLL
• Print SLL
• Length of SLL
• Insert a node (Begin, Middle, End)
• Delete a node(Begin, Middle, End)
• Search an element k in SLL
• predecessor
• successor
• minimum
• maximum
30. Print length of a Singly linked list
Length_SSL(Head)
1. count=0
2. x=Head
3. while(x≠NIL)
4. x=x.next
5. count=count+1
6. print count
31. Search Operation
• The procedure search(Head, k) finds the first element with key k in
list by a simple linear search, returning a pointer of the node having this
key ‘k’.
• If no object with key ‘k’ appears in the list, then the procedure returns
NIL.
• Time complexity of linear search and time complexity of search in a
linked list are same.
33. Insertion of a node in a linked list
• Insertion at the beginning of the list.
• Insertion at the end of the list
• Inserting a new node except the above mentioned positions.
34. Inserting a node at begin: Inserting a node under the
assumption of SLL is already created.
Insert_Begin (Head, k)
1. newnode=create_node(k)
2. newnode.next=Head
3. Head=newnode
4. return Head
35. Inserting a node in SLL at middle
Insert_Middle(Head, k, position)
1. L=Length_SSL(Head)
2. newnode=create_node(k)
3. if pos≥2 and pos<L
4. x=Head
5. for j=2 to pos-1
6. x=x.next
7. newnode.next=x.next
8. x.next=newnode
else
9. print “Invalid position”
10. return 0
36. Inserting a node at end of SLL
Insert_End(Head, k)
1. newnode=create_node(k)
2. x=Head
3. while(x.next≠NIL)
4. x=x.next
5. x.next=newnode
6. tail=newnode
37. Delete a node from SLL at beginning
Delete_Begin(Head)
1. x=Head
2. Head=Head.next
3. print “x.data”
4. free(x) //free the memory pointed by x pointer
38. Delete a node from SLL at Middle
Delete_Middle(Head, pos) //(pos) is position of a node
1. L=Length_SLL(Head)
2. if pos≥2 and pos<L
3. x=Head
4. for j=2 to pos-1
5. x=x.next
6. temp=x.next
7 x.next=x.next.next
8. print “temp.data”
9. free(temp)
else
10. print “invalid position”
11. return 0
39. Delete a node from SLL at ending
Delete_End(Head)
1. x=Head
2. while(x.next.next ≠ NIL)
3. x=x.next
4. temp=x.next
5. x.next=NIL
6. print “temp.data”
7. free temp
40. Reverse a Singly linked list: Try to convert tail into
head and head into tail as shown in below figure.
41. CIRCULAR LINKED LIST (CLL): Tail’s pointer
points to the Head node instead of NIL.
10
• Each element of CLL : An object
• Attributes: Key and a Next pointer. Head.data=40,
Head.next= pointer to the next Node
• Reader can take all the functions of CLL as an exercise.
20
30
40
Head
Tail
42. Doubly linked List (DLL)
• A Doubly Linked List (DLL) is a special type of linked list in which each
node contains a pointer to the previous node as well as the next node of the
linked list.
• Doubly Linked List is combining the Singly Linked List and Reverse of Singly
Linked List in the previous slide
• Traverse from tail to head is not possible in SLL but possible in DLL because
of previous pointer. So, in DLL either way traversal is possible.
44. Creation of DLL
struct DLL { // structure of a node
struct DLL *next
int key
struct DLL *prev };
typedef struct DLL node;
node *Head=*Tail=NIL // Initialization of Head and Tail
create_DLL(Head, k, Tail)
1. Newnode=create_node(k)
2. if (Head==NIL)
3. Head=Newnode
4. Tail=Newnode
5 return Head
else
6. Tail.next=Newnode
7. Newnode.prev=Tail
8. Tail=Newnode
9. return tail
create_node(k)
1. Allocate dynamic memory to temp
//node temp=(node *)malloc(sizeof(node))
2. If (temp==NIL)
3. print “Memory not available”;
4. exit
else
5. temp.key=k
6. temp.prev=NIL
7. temp.next=NIL
8. return temp
Creating a node and return its pointer if
memory created otherwise return NIL
45. Printing DLL from Tail using prev pointer
print_DLL(Tail)
1. x=Tail
2. while x ≠ NIL
3. print “x.key”
4. x=x.prev
46. DLL Insertion at Middle
In case of DLL, we can travel either from Head to Tail or Tail to Head.
Assume that x is pointing before node where new node to be inserted using
position (pos) while travelling from Head. Newnode points the node to be
inserted. Then
1. Newnode.next=x.next
2. Newnode.prev=x
3. Newnode.next.prev=Newnode
4. x.next=Newnode
Reader should complete the pseudocode by taking the above piece of code.
47. DLL Deletion at Middle
In case of DLL, we can travel either from Head to Tail or Tail to Head.
Assume that x is pointing before node of delete node while travelling from
Tail.
1. temp=x.prev
2. x.prev=temp.prev
3. x.prev.next=x
4. print “temp.key”
5. free(temp)
Reader should complete the pseudocode by taking the above piece of code.
48. Circular Doubly Linked List
• Circular Doubly Linked List has properties of both doubly linked list and circular linked
list in which two consecutive elements are linked or connected by the previous and next
pointer and the last node points to the first node by the next pointer and also the first node
points to the last node by the previous pointer.
• For all operations of a Circular Doubly Linked List Head.prev and Tail.next should be
replaced always.
50. Create a CDLL: reuse the create_node function
discussed during DLL.
Create_CDLL(Head, Tail, k)
1. temp=create_node(k) //temp is newnode to be part of CDLL
2. if Head==NIL
3. Head=temp
4. Tail=temp
5. Tail.prev=temp
6. Tail.next=temp
else
7. temp.next=Tail.next
8. Tail.next=temp
9. temp.prev=Tail
10. Head.prev=temp
11. Tail=Temp
12. return Head, Tail // use call by reference to replicate both the pointers
51. Insert node to the beginning of CDLL: The below piece
of code is under the assumption of CDLL is already created.
Insert_Begin_CDLL(Head, k)
1. temp=create_node(k)
2. temp.next=Head
3. temp.prev=Head.prev
4. Head.prev=temp
5. temp.prev.next=temp
6. Head=temp
7. return Head
52. Cont…
• We can use both Head and Tail to insert a node in circular doubly
linked list.
• In CDLL 4 pointers get affected to insert a node at beginning, but in
DLL only 2 pointers get affected
53. Insert a node to the end of a CDLL
Insert_End_CDLL(Tail, k)
1. temp=create_node(k)
2. temp.next=Tail.next
3. temp.prev=Tail
4. temp.next.prev=temp
5. Tail.next=temp
6. Tail=temp
7. return Tail
54. Cont…
• In case of inserting a node at the middle of a CDLL, Head.prev or
Tail.next is not get affected. So,
Insert_Middle_CDLL=Insert_Middle_DLL
55. Delete a node at the beginning of a CDLL
Delete_Begin_CDLL(Head)
1. temp=Head
2. Head=Head.next
3. Head.prev=temp.prev
4. temp.prev.next=Head
5. print “temp.key”
6. free(temp)
56. Delete a node at the End of a CDLL by
passing Tail node as the parameter
Delete_End_CDLL(Tail)
1. temp=Tail
2. Tail=Tail.prev
3. Tail.next=temp.next
4. Tail.next.prev=Tail //alternate stmt is Temp.next.prev=Tail
5. Print “temp.key”
6. free(temp)