Data Structures Lec PDF
Data Structures Lec PDF
Data Structures Lec PDF
Array
Stack
Queue
Linked List
Tree
Graph
•
Data Structure Philosophy
Each data structure has costs and benefits.
Rarely is one data structure better than another in all situations.
A data structure requires:
space for each data item it stores,
time to perform each basic operation,
programming effort.
Traversing
Accessing each data element exactly once so that
certain items in the data may be processed
Searching
Finding the location of the data element (key) in the
structure
Insertion
Adding a new data element to the structure
Data Structure Operations (cont.)
Deletion
Removing a data element from the structure
Sorting
Arrange the data elements in a logical order
(ascending/descending)
Merging
Combining data elements from two or more data
structures into one
Algorithm
An algorithm is a well-defined list of steps for solving computational
problem
Complexity of Algorithm
It must be correct
It must be finite (in terms of time and size)
It must terminate
It must be unambiguous
Which step is next?
It must be space and time efficient
A data structure is a data type that can hold multiple values at the
same time. (Synonyms: complex data type, composite data type)
The array is one kind of data structure.
Abstract Data Type (ADT) - A data object and a set of operations for
manipulating it
List ADT with operations insert and delete
Stack ADT with operations push and pop
Arrays
Array: a set of pairs (index and value)
data structure
For each index, there is a value associated with
that index.
representation (possible)
implemented by using consecutive memory.
Arrays in C++
int list[5];
Solution:
The given values are: B = 1020, LB = 1300, W = 2, I = 1700
Address of A [ I ] = B + W * ( I – LB )
= 1020 + 2 * (1700 – 1300)
= 1020 + 2 * 400
= 1020 + 800
= 1820 [Ans]
Address of an element of any array say “A[ I ][ J ]” is calculated in two forms as given: (1)
Row Major System (2) Column Major System
Row Major System:
The address of a location in Row Major System is calculated using the following formula:
Address of A [ I ][ J ] = B + W * [ N * ( I – Lr ) + ( J – Lc ) ]
Column Major System:
The address of a location in Column Major System is calculated using the following formula:
Address of A [ I ][ J ] Column Major Wise = B + W * [( I – Lr ) + M * ( J – Lc )]
Where,
B = Base address
I = Row subscript of element whose address is to be found
J = Column subscript of element whose address is to be found
W = Storage Size of one element stored in the array (in byte)
Lr = Lower limit of row/start row index of matrix, if not given assume 0 (zero)
Lc = Lower limit of column/start column index of matrix, if not given assume 0 (zero)
M = Number of row of the given matrix
N = Number of column of the given matrix
•
Data Structures
Lecture 2: C++ Overview
… … 100
a
… 1024 …
Variable a’s value, i.e., 100, is
int a = 100; stored at memory location 1024
Pointer Types
Pointer •
C++ has pointer types for each type of object –
• Pointers to int objects
• Pointers to char objects
• Pointers to user-defined objects
(e.g., RationalNumber)
– Even pointers to pointers
• Pointers to pointers to int objects
Pointer Variable
• Declaration of Pointer variables
type* pointer_name;
//or
type *pointer_name;
… … 100 … … …
a
int a = 100;
//get the value,
cout << a;
//prints 100
//get the memory address
cout << &a;
//prints 1024
Pointer Variables
Memory address: 1020 1024 1032
… 88 100 … 1024 …
a p
int a = 100; Result is:
int *p = &a; 100 1024
cout << a << " " << &a <<endl; 1024 1032
cout << p << " " << &p <<endl;
… 88 100 … 1024 …
a p
int a = 100;
int *p = &a; Result is:
cout << a << endl; 100
cout << &a << endl; 1024
cout << p << " " << *p << endl; 1024 100
cout << &p << endl; 1032
Reference Variables
A reference is an additional name to
an existing memory location
Pointer: Reference:
x 9 x
9
ref
ref
int x = 9;
int x=9;
int &ref = x;
int *ref;
ref = &x;
Reference Variables
• A reference variable serves as an alternative name for an
object
int m = 10;
int &j = m; // j is a reference variable
cout << “value of m = “ << m << endl;
//print 10
j = 18;
cout << “value of m = “ << m << endl;
// print 18
#include <iostream>
void main (){
int a[5];
cout << "Address of a[0]: " << &a[0] << endl
<< "Name as pointer: " << a << endl;
}
Result:
Address of a[0]: 0x0065FDE4
Name as pointer: 0x0065FDE4
Array Names as Pointers
To access an array, any pointer to the first element can
be used instead of the name of the array.
We could replace *p by *a
p #include <iostream>
a
void main(){
a[0] 2 int a[5] = {2,4,6,8,22}; 22
int *p = a;
a[1] 4
cout << a[0] << " "
a[2] 6 << *p;
a[3] 8 }
a[4] 22
a
Pointer Arithmetic
Given a pointer p, p+n refers to the element that is
offset from p by n positions.
a 2 p - 1
a + 1 4 p
a + 2 6 p + 1
a + 3 8 p + 2
a + 4 22 p + 3
Array of Pointers & Pointers to Array
a
p
b
Example
int* p = new int;
p
Object (variable) destruction: Delete
Syntax
delete p;
storage pointed to by p is returned to free store and p is now undefined
Example
int* p = new int;
*p = 10;
delete p;
p 10
Data Structures
Lecture 3: Stack and its Applications
Operation on Stacks
• Push
The operation to place a new item at the top of the stack
• Pop
The operation to remove the next item from the top of the stack
• IsEmpty
Determines whether the stack is empty
• IsFull
Determines whether the stack is empty
Stack ADT Specification
Structure: Elements are added to and removed from the top of the stack.
Definitions (provided by user)
MAX_ITEMS: Maximum number of items that might be on the stack.
ItemType: Datatype of the items on the stack.
Operations (provided by the ADT):
MakeEmpty
Function: Sets stack to an empty state.
Precondition: None
Postcondition: Stack is empty.
Implementation of Stack
#include<iostream.h>
#include<stdlib.h>
typedef int ItemType;
const int MAX_ITEMS=10;
class StackType
{
public:
StackType();
void push(ItemType newitem);
ItemType pop();
bool IsEmpty();
bool IsFull();
private:
int top;
ItemType items[MAX_ITEMS];
};
StackType::StackType()
{ top=-1; }
bool StackType::IsEmpty()
{ return(top==-1);}
bool StackType::IsFull(void)
{ return(top==MAX_ITEMS);}
void StackType::push(ItemType newitem)
{
if(IsFull())
{ cout<<"empty"; exit(0);}
top++;
items[top]=newitem;
}
ItemType StackType::pop()
{
if(IsEmpty())
{ cout<<"empty"; exit(0);}
ItemType x=items[top];
top--;
return x;
}
void main()
{ ItemType symbol;
StackType stack;
for(int i=0;i<5;i++)
{ cin>>symbol;
stack.push(symbol);
}
for( i=0;i<5;i++)
cout<<stack.pop();}
Applications of Stack
• Stacks are useful for any application requiring
LIFO storage. There are many, many of these:
Operations •
MakeEmpty –
Boolean IsEmpty –
Boolean IsFull –
Enqueue (ItemType newItem) –
Dequeue (ItemType& item) –
Enqueue (ItemType newItem)
• Function: Adds newItem to the rear of the queue.
• Preconditions: Queue has been initialized and is not full.
• Postconditions: newItem is at rear of queue.
if(front == -1)
front=front+1;
rear=rear+1;
items[r]=item;
} }
Queue Implementation (cont.)
ItemType QueueType::Dequeue()
{
int item;
if( IsEmpty())
{
cout<<"Error......the is empty";
exit(0); }
item=items[front];
front=front+1;
if(front== MAX_ITEMS)
{ front =-1; rear =-1; }
return item;}
Queue Implementation (cont.)
void main()
{
QueueType queue;
ItemType x;
for( int i=0;i< MAX_ITEMS;i++)
{
cin>>x;
queue.Enqueue(x);
}
for( i=0;i< MAX_ITEMS;i++)
cout<<" "<<queue.Dequeue(); }
Circular Queue
Circular Queue Implementation
class Cqueue
{
int a[MAX],
front,
rear;
public:
cqueue()
{ front=rear=-1; }
void insert(int );
int deletion();
void display();
};
Queue Implementation (cont.)
void cqueue :: insert(int val)
{ if((front==0 && rear==MAX-1) || (rear+1==front))
cout<<" Circular Queue is Full";
else
{ if(rear==MAX-1)
rear=0; (rear + 1) % MAX== front);
else
rear++;
a[rear]=val; }
if(front==-1) (rear = (rear + 1) % MAX
front=0; }
Queue Implementation (cont.)
int cqueue :: deletion()
{ int k;
if(front==-1)
cout<<"Circular Queue is Empty";
else {
k=a[front];
if(front==rear)
front=rear=-1;
else {
if(front==MAX-1)
front=0;
else
front++; }
}
return k; }
front = (front + 1) % MAX;
Queue Implementation (cont.)
void cqueue :: display()
{ int i;
if(front==-1)
cout<<"Circular Queue is Empty";
else
{ if(rear < front)
{ for(i=front; i<=MAX-1;i++)
cout<<a[i]<<" ";
for(i=0;i<=rear;i++)
cout<<a[i]<<" ";
}
Data Structures
Lecture 5: Linked Lists
head
2 6 8 7 1 size=5
current
Linked List
Note some features of the list:
Need a head to point to the first node of the
list. Otherwise we won’t know where the start of
the list is.
The current here is a pointer, not an index.
The next field in the last node points to nothing.
We will place the memory address NULL which
is guaranteed to be inaccessible.
A Simple Linked List Class
tail
Linked List Operations
void List::InsertAnyPos(ItemType elem, int pos)
{
int i=0;
Start
Link ptr;
ptr=start;
2 6 8 7 1 size=5 6
Link addedNode=new Node;
assert(addedNode); current 2 1
addedNode->elem=elem; 3
while(i<pos) 9
{
ptr=ptr->next; addedNode
i++;
}
addedNode->next=ptr->next;
ptr->next=addedNode;
}
Linked List Operations
ItemType* itemPtr;
...
itemPtr = new ItemType;
*itemPtr = newItem;
Chaining the stack elements together
(cont.)
class StackType {
public:
StackType();
~StackType();
void MakeEmpty();
bool IsEmpty()
bool IsFull() ;
void Push(ItemType);
ItemType void Pop(void);
private:
NodeType* topPtr;
};
Function Push
void StackType::Push(ItemType newitem)
{
NodeType* location;
location = new NodeType;
if(location==NULL)
cout<<“exit”;
else
{ location->info = newItem;
location->next = topPtr;
topPtr = location;
}}
Function Pop
ItemType StackType::Pop(void)
{
If (IsEmpty())
cout<<" The Stack is Empty";
else
{
NodeType* tempPtr;
ItemType item = topPtr->info;
tempPtr = topPtr;
topPtr = topPtr->next;
delete tempPtr;
return item
}}
Other Stack functions
StackType>::StackType()
{
topPtr = NULL;
}
void StackType::MakeEmpty()
{
NodeType* tempPtr;
while(topPtr != NULL) {
tempPtr = topPtr;
topPtr = topPtr->next;
delete tempPtr;
}
}
Other Stack functions (cont.)
bool StackType::IsEmpty()
{
return(topPtr == NULL);
}
bool StackType::IsFull()
{
NodeType* location;
location = new NodeType;
if(location == NULL)
return true;
else {
delete location;
return false;
} }
StackType::~StackType()
{
MakeEmpty();
}
Implementing queues using
arrays
Simple implementation •
The size of the queue must be determined •
when a stack object is declared
Space is wasted if we use less elements •
We cannot "enqueue" more elements than •
the array can hold
Implementing queues using linked
lists
Allocate memory for each new element •
dynamically
Link the queue elements together •
Use two pointers, front and rear, to mark •
the front and rear of the queue
Queue class specification
// forward declaration of NodeType (like function prototype)
struct NodeType;
class QueType {
public:
QueType();
~QueueType();
void MakeEmpty();
bool IsEmpty() ;
bool IsFull() ;
void Enque(ItemType);
ItemType Deque(void);
private:
NodeType* front;
NodeType* rear;
};
Function Enqueue
void QueueType::Enqueue(ItemType newItem)
{
NodeType* newNode;
newNode = new NodeType;
newNode->info = newItem;
newNode->next = NULL;
if(rear == NULL)
front = newNode;
else
rear->next = newNode;
rear = newNode;
}
Function Dequeue
ItemTyp QueueType::Dequeue(void)
{
ItemType item;
NodeType* tempPtr;
if(IsEmpty())
cout<<"Queue is Empty";
else
{
tempPtr = front;
item = front->info;
front = front->next;
if(front == NULL)
rear = NULL;
delete tempPtr;
return item; }}
Other Queue functions
void QueueType::MakeEmpty()
{
NodeType* tempPtr;
while(front != NULL) {
tempPtr = front;
front = front->next;
delete tempPtr;
}
rear=NULL;
}
Other Queue functions (cont.)
bool QueueType::IsEmpty()
{
return(front == NULL); }
bool QueueType::IsFull()
{
NodeType *ptr;
ptr = new NodeType;
if(ptr == NULL)
return true;
else {
delete ptr;
return false;
}}
QueueType::~QueueType()
{ MakeEmpty(); }
LEC 7: Circular Linked Lists &
Double Liked Lists
#include <iostream>
typedef int ItemType;
struct Node
{
ItemType info;
NodeType * next; };
class CQueType
{
public:
CQueType() { Front=NULL; Rear=NULL;}
void enQueue(ItemType value);
ItemType deQueue();
void displayQueue();
private:
Node* front;
Node* rear;
};
Circular Linked List Operations
rear = temp;
rear->next = front;
}
Circular Linked List Operations
// Function to delete element from Circular Queue
ItemType CQueType ::deQueue()
{
if (front == NULL)
{
printf ("Queue is empty");
exit(0);
}
// If this is the last node to be deleted
ItemType value; // Value to be dequeued
if (front == rear)
{
value = front->info;
delete(front);
front = NULL;
rear = NULL;
}
Circular Linked List Operations
return value ;
}
Circular Linked List Operations
cq.enQueue(9);
cq.enQueue(20);
cq.displayQueue();
return 0;}
Doubly Linked Lists
Node data
info: the user's data
next, back: the address of the next
and previous node in the list
private:
struct NodeType {
ListElementType info;
NodeType* next;
NodeType * back;
};
NodeType* listData ;
};
Inserting into a Doubly Linked List
NodeType * newNode;
NodeType * location;
bool found; else
listData = newNode;
newNode = new NodeType; location->back = newNode;
newNode->info = item; }
if (listData != NULL) {
if (location->info > item) { (3)
newNode->back = location->back; (1) (4)
newNode->next = location; (2)
if (location != listData) // special case
(location->back)->next = newNode; (3)
Inserting into a Doubly Linked List
Data
firstChild NextSibling
A
B C D
E F G H I
J K L
Binary Tree
• A binary tree is a tree with the following Applications:
properties: arithmetic expressions
– Each internal node has at most two
children (degree of two) decision processes
– The children of a node are an ordered pair searching
H I
Array Representation
Array Representation
+
2 - 3 b
a 1
Arithmetic Expression Tree
2
O( N )
Graph terminology (cont.)
• What is the number of edges in a complete
undirected graph with N vertices?
N * (N-1) / 2
2
O( N )
Graph terminology (cont.)
• Weighted graph: a graph in which each edge
carries a value
Graph implementation
• Array-based implementation (Adjacency Tables)
The adjacency table has a natural interpretation:
adjacency[v][w] is true if and only if vertex v is
adjacent to vertex w. If the graph is directed, we
interpret adjacency [v][w] as indicating whether or not
the edge from v to w is in the graph. If the graph is
undirected, then the adjacency table must be
symmetric; that is, adjacency [v][w] = adjacency[w][v]
for all v and w. The representation of a graph by
adjacency sets and by an adjacency table is illustrated
in Figure below.
Adjacency Table -based
implementation
struct Node
{
ItemType info;
node * link; }
class Digraph {
int count; // number of vertices, at most
max_size
Node * G[max_size];
};
Linked List Implementation
Linked List Implementation
Adjacency matrix vs. adjacency list
representation
• Adjacency matrix
– Good for dense graphs --|E|~O(|V|2)
– Memory requirements: O(|V| + |E| ) = O(|V|2 )
– Connectivity between two vertices can be tested
quickly
• Adjacency list
– Good for sparse graphs -- |E|~O(|V|)
– Memory requirements: O(|V| + |E|)=O(|V|)
– Vertices adjacent to another vertex can be found
quickly
Searching and Sorting
Lec.10