Introduction to Linear Data Structures
A data structure is a particular way of organizing data in a computer so that it can be used effectively. The idea is to reduce the space and time complexities of different tasks. Below is an overview of some popular linear data structures.
The array is a data structure used to store homogeneous elements at contiguous locations. The size of an array must be provided before storing data.
Let size of array be n. Accessing Time: O(1) [This is possible because elements are stored at contiguous locations] Search Time: O(n) for Sequential Search: O(log n) for Binary Search [If Array is sorted] Insertion Time: O(n) [The worst case occurs when insertion happens at the Beginning of an array and requires shifting all of the elements] Deletion Time: O(n) [The worst case occurs when deletion happens at the Beginning of an array and requires shifting all of the elements]
Example: For example, let us say, we want to store marks of all students in a class, we can use an array to store them. This helps in reducing the use of a number of variables as we don’t need to create a separate variable for marks of every subject. All marks can be accessed by simply traversing the array.
A linked list is a linear data structure (like arrays) where each element is a separate object. A linked list is made up of two items that are data and a reference to the next node. A reference to the next node is given with the help of pointers and data is the value of a node. Each node contains data and links to the other nodes. It is an ordered collection of data elements called a node and the linear order is maintained by pointers. It has an upper hand over the array as the number of nodes i.e. the size of the linked list is not fixed and can grow and shrink as and when required, unlike arrays.
Types of Linked List :
1. Singly Linked List: In this type of linked list, every node stores address or reference of the next node in the list and the last node has the next address or reference as NULL. For example 1->2->3->4->NULL
2. Doubly Linked List: In this type of Linked list, there are two references associated with each node, One of the reference points to the next node and one to the previous node. The advantage of this data structure is that we can traverse in both directions and for deletion, we don’t need to have explicit access to the previous node. Eg. NULL<-1<->2<->3->NULL
3. Circular Linked List: Circular linked list is a linked list where all nodes are connected to form a circle. There is no NULL at the end. A circular linked list can be a singly circular linked list or a doubly circular linked list. The advantage of this data structure is that any node can be made as starting node. This is useful in the implementation of the circular queues in the linked list. Eg. 1->2->3->1 [The next pointer of the last node is pointing to the first]
4. Circular Doubly Linked List: The circular doubly linked list is a combination of the doubly linked list and the circular linked list. It means that this linked list is bidirectional and contains two pointers and the last pointer points to the first pointer.
Accessing time of an element : O(n) Search time of an element : O(n) Insertion of an Element : O(1) [If we are at the position where we have to insert an element] Deletion of an Element : O(1) [If we know address of node previous to the node to be deleted]
Example: Consider the previous example where we made an array of marks of students. Now if a new subject is added to the course, its marks are also to be added to the array of marks. But the size of the array was fixed and it is already full so it can not add any new element. If we make an array of a size lot more than the number of subjects it is possible that most of the array will remain empty. We reduce the space wastage Linked List is formed which adds a node only when a new element is introduced. Insertions and deletions also become easier with a linked list.
One big drawback of a linked list is, random access is not allowed. With arrays, we can access i’th element in O(1) time. In the linked list, it takes Θ(i) time.
A stack or LIFO (last in, first out) is an abstract data type that serves as a collection of elements, with two principal operations: push, which adds an element to the collection, and pop, which removes the last element that was added. In stack both the operations of push and pop take place at the same end that is top of the stack. It can be implemented by using both array and linked list.
Insertion : O(1) Deletion : O(1) Access Time : O(n) [Worst Case] Insertion and Deletion are allowed on one end.
Example: Stacks are used for maintaining function calls (the last called function must finish execution first), we can always remove recursion with the help of stacks. Stacks are also used in cases where we have to reverse a word, check for balanced parenthesis, and in editors where the word you typed the last is the first to be removed when you use undo operation. Similarly, to implement back functionality in web browsers.
Primary Stack Operations:
- void push(int data): When this operation is performed, an element is inserted into the stack.
- int pop(): When this operation is performed, an element is removed from the top of the stack and is returned.
Auxiliary Stack Operations:
- int top(): This operation will return the last inserted element that is at the top without removing it.
- int size(): This operation will return the size of the stack i.e. the total number of elements present in the stack.
- int isEmpty(): This operation indicates whether the stack is empty or not.
- int isFull(): This operation indicates whether the stack is full or not.
Types of Stacks:
- Register Stack: This type of stack is also a memory element present in the memory unit and can handle a small amount of data only. The height of the register stack is always limited as the size of the register stack is very small compared to the memory.
- Memory Stack: This type of stack can handle a large amount of memory data. The height of the memory stack is flexible as it occupies a large amount of memory data.
A queue or FIFO (first in, first out) is an abstract data type that serves as a collection of elements, with two principal operations: enqueue, the process of adding an element to the collection. (The element is added from the rear side) and dequeue the process of removing the first element that was added. (The element is removed from the front side). It can be implemented by using both array and linked list.
Insertion : O(1) Deletion : O(1) Access Time : O(n) [Worst Case]
Example: Queue as the name says is the data structure built according to the queues of a bus stop or train where the person who is standing in the front of the queue(standing for the longest time) is the first one to get the ticket. So any situation where resources are shared among multiple users and served on a first come first serve basis. Examples include CPU scheduling, Disk Scheduling. Another application of queue is when data is transferred asynchronously (data not necessarily received at the same rate as sent) between two processes. Examples include IO Buffers, pipes, file IO, etc.
Basic Operations on Queue:
- void enqueue(int data): Inserts an element at the end of the queue i.e. at the rear end.
- int dequeue(): This operation removes and returns an element that is at the front end of the queue.
Auxiliary Operations on Queue:
- int front(): This operation returns the element at the front end without removing it.
- int rear(): This operation returns the element at the rear end without removing it.
- int isEmpty(): This operation indicates whether the queue is empty or not.
- int size(): This operation returns the size of the queue i.e. the total number of elements it contains.
Types of Queues:
- Simple Queue: Simple queue also known as a linear queue is the most basic version of a queue. Here, insertion of an element i.e. the Enqueue operation takes place at the rear end and removal of an element i.e. the Dequeue operation takes place at the front end.
- Circular Queue: In a circular queue, the element of the queue act as a circular ring. The working of a circular queue is similar to the linear queue except for the fact that the last element is connected to the first element. Its advantage is that the memory is utilized in a better way. This is because if there is an empty space i.e. if no element is present at a certain position in the queue, then an element can be easily added at that position.
- Priority Queue: This queue is a special type of queue. Its specialty is that it arranges the elements in a queue based on some priority. The priority can be something where the element with the highest value has the priority so it creates a queue with decreasing order of values. The priority can also be such that the element with the lowest value gets the highest priority so in turn it creates a queue with increasing order of values.
- Dequeue: Dequeue is also known as Double Ended Queue. As the name suggests double ended, it means that an element can be inserted or removed from both the ends of the queue unlike the other queues in which it can be done only from one end. Because of this property it may not obey the First In First Out property.
This article is contributed by Abhiraj Smit. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.