Lecture 18 - Oct 17, 2023
Summary
In this lecture, we start discussing linked lists variants: stacks and queues, and where they are used.
Last lecture
Deep copy in copy constructors.
Today
Data structures: Stacks and queues.
Recap on arrays
To store and organize data of same type, we used arrays.
int arr[3] = {1,2,3};
An issue with arrays is that they are not flexible. If you need more space, you need to allocate new memory with more space and copy data to this space.
This is where liked lists are helpful.
Linked lists
A linked list is a collection of nodes that are linked together via pointers. They are easily extendable, shrinkable and flexible.
In C, each node and the linked list were a data structure. There were some functions/operations like insert
and delete
.
In C++, we can bundle operations and data into an object.
There are variants or linked lists: stacks, queues, doubly linked lists, etc.
Class definition of a Node
Class definition of a Node
in all linked list variants.
In Node.h
:
class Node {
private:
int data;
* next;
Node
private:
() { data = 0; next = NULL; }
Node(int d) { data = d; next = NULL; }
Node(int d, Node* n) { data = d; next = n; }
Node~Node() { delete next; }
int getData() { return data; }
* getNext() { return next; }
Nodevoid setData(int d) { data = d; }
void setNext(Node* n) { next = n; }
}
Stacks
Two operations: pop()
and push()
.
Putting a node or removing a node happens with LIFO (last-in first-out).
pop()
: Remove the node that was most recently inserted.
push()
: Insert a node at the head only as pop()
would remove a node from head.
Class definition of a Stack
class Stack {
private:
* head;
Node
public:
() { head = NULL; }
Stack~Stack() { delete head; }
void push(int d) {
// if stack is empty, next of new node is NULL
// if stack has nodes, next of new node is old head
* p = new Node(d, head);
Node
// make new node the head
= p;
head }
}
;
stack s
.push(3);
s.push(2);
s.push(1);
s.push(0); s
int pop() {
// if stack is empty
if (head == NULL) {
return -1;
}
* p = head;
Nodeint d = p->getData(); // data is private to Node
= p->getNext(); // head is private to Stack
head ->setNext(NULL); // very important!
pdelete p;
return d;
};
// for the 1st pop, the most recently pushed node is 0
// output is 0123
<< s.pop() << s.pop() << s.pop() << endl; cout
Always think of special cases:
- Does it work if the stack is empty?
- Does it work if the stack has only one node?
Queues
Two operations: enqueue()
and dequeue()
.
Putting a node or removing a node happens with FIFO (first-in first-out).
dequeue()
: Remove the node that was first put in the list.
enqueue()
: Put a node at the end of the list.
Class implementation of a Queue
class Queue {
private:
* head;
Node
// point to the end of the queue to facilitate dequeue of nodes
* tail;
Node
public:
() {
Queue= NULL;
head = NULL;
tail }
~Queue() {
// enough to free up all nodes in linked list
delete head;
}
void enqueue(int d) {
* p = new Node(d, NULL);
Node->setNext(p);
tail= p;
tail if (head == NULL) {
= p;
head }
}
int dequeue() {
if (head == NULL) {
return -1;
}
* p = head;
Node= p->getNext();
head int d = p->getData();
->setNext(NULL); // very important!
pdelete p;
return d;
}
};
;
Queue q.enqueue(1);
q.enqueue(2);
q.enqueue(3);
q
// output 123
<< q.dequeue() << q.dequeue() << q.dequeue() << endl; cout