0% found this document useful (0 votes)
11 views44 pages

2 List

The document provides an overview of data structures, including linear and non-linear types, and details on basic structures like arrays, linked lists, and abstract data types. It discusses the implementation of a scoreboard using classes for game entries and scores, as well as the operations for adding and removing entries. Additionally, it covers the concepts of stacks, queues, and double-ended queues, along with their applications and implementations in C++.

Uploaded by

brianglw0506
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views44 pages

2 List

The document provides an overview of data structures, including linear and non-linear types, and details on basic structures like arrays, linked lists, and abstract data types. It discusses the implementation of a scoreboard using classes for game entries and scores, as well as the operations for adding and removing entries. Additionally, it covers the concepts of stacks, queues, and double-ended queues, along with their applications and implementations in C++.

Uploaded by

brianglw0506
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

CPSC 5005

Data Structures
Yueting Chen
Data Structure
Data Structure

• What is data structure?


• Linear Data Structure
• Data is organized sequentially, one
element after another.
• Non-linear Data Structure
• Data is organized in a non-sequential
way. E.g., organized hierarchically.
Basic Data Structure

• Array/2D Array
• Linked List
• Abstract Data Type
• Vector
• List
• Stack
• Queue
Two-dimensional (2D) Arrays

• 2D Array: Array of Arrays


• If size is known before compilation
int matrix[5][7]; //space reserved in stack

• Otherwise, dynamic allocation is needed


int n = 5, m = 7;
int** M = new int*[n]; //array of row pointers
for(int i=0; i<n; i++)
M[i] = new int[m]; //allocate the ith row
2D Arrays

M
M is a pointer to an int
int*
pointer, therefore:
int** M int*
int*
int*
int*
int*
2D Arrays

• De-allocate the matrix after use.


• De-allocate rows first,
• Then deallocate the array of row pointers.

for (int i = 0; i < n; i++)


delete[] M[i]; // delete the i-th row
delete[] M; // delete the array of row pointers
Problem: Maintain a Scoreboard

• A scoreboard contains a list of (name,


score) pairs.
• The items are sorted by score.
• Question:
• What are the classes/structs needed in
the problem?
Scoreboard - Definitions

• Define a class for each (name, score) pair (GameEntry).


• Define a class for the entire scoreboard (Scores).

What are the operations needed by two classes?


GameEntry
class GameEntry { // a game score entry
public:
GameEntry(const string& n="", int s=0); // constructor
Class string getName() const; // get player name
Definition int getScore() const; // get score
private:
string name; // player's name
int score; // player's score
OR };

struct GameEntry { // stores a game entry


Struct GameEntry(const std::string& n = "", int s = 0) : name(n), score(s) {}
std::string name; // player's name
Definition int score; // player's score
};
Scores
class Scores { // stores game high scores
• Main methods public:
Scores(int maxEnt = 10); // constructor
• Constructor ~Scores(); // destructor
void add(const GameEntry& e); // add a game entry
• Destructor GameEntry remove(int i); // remove the ith entry
• Add elements private:
int maxEntries; // maximum number of entries
• Remove elements int numEntries; // actual number of entries
GameEntry* entries; // array of game entries
};
Question:
• What to do if?
• Remove is invoked with parameter i > 10?
Side Note: Define Exception
#include <iostream>
#include <exception>
• You can also define #include <string>
using namespace std;
exception to indicate illegal
inputs class IndexOutOfBounds : public exception {
private:
string message;
• (Not Required for this course) public:
// constructor with index and size info
IndexOutOfBounds(int index, int size) {
class Scores { message = "Index " + to_string(index) +
public: " is out of bounds for array of size " +
GameEntry remove(int i) to_string(size);
throw(IndexOutOfBounds); }
}; // override what()
const char* what() const noexcept override {
return message.c_str();
}
https://cplusplus.com/doc/tutorial/exceptions/ };
Constructor and Destructor
class Scores {
• How to implement constructor & destructor? public:
Scores(int maxEnt = 10);
~Scores();
};
Scores::Scores(int maxEnt) { // constructor
maxEntries = maxEnt; // save the max size
entries = new GameEntry[maxEntries]; // allocate array storage
numEntries = 0; // initially no elements
}

Scores::~Scores() { // destructor
delete[] entries;
}
Add

• How to implement add elements in Scores?


• add(e):
• Insert game entry e into the collection of high scores. If this causes the number of
entries to exceed maxEntries, the smallest is removed.

Steps:
1. Test if the new element can be added to the
array.
1. If the array is full and the smallest > e.score,
ignore.
2. Find where to insert the new element.
3. Make space for the new element.
4. Insert the new element to the target position.
Add
void Scores::add(const GameEntry& e) { // add a game entry

int newScore = e.getScore(); // score to add


if (numEntries == maxEntries) { // the array is full
if (newScore <= entries[maxEntries-1].getScore()) Step 1: Test if the new element can be added
return; // not high enough − ignore to the array & update the # of elements
}
else numEntries++; // if not full, one more entry

int i = numEntries-2; // start with the next to last


while ( i >= 0 && newScore > entries[i].getScore() ) { Step 2 & 3: find the target position and make
entries[i+1] = entries[i]; // shift right if smaller
i--;
space for the new element
}

entries[i+1] = e; // put e in the empty spot Step 4: Insert the new element to the target position.
}
Remove

• remove(i)
• Remove and return the game entry e at index i in the entries array.
• For a valid index i, the entries array is updated to remove the object at index i and
all objects previously stored at indices higher than i are "shifted left" to fill in for the
removed object.
Steps:
1. Test if the index i is valid.
1. If not, throw an Exception or return a default
value.
2. Find where to insert the new element.
3. Make space for the new element.
4. Insert the new element to the target position.
Remove

GameEntry Scores::remove(int i) throw(IndexOutOfBounds) {


if ((i < 0) | | (i >= numEntries)) // invalid index
throw IndexOutOfBounds("Invalid index");
GameEntry e = entries[i]; // save the removed object

for (int j = i+1; j < numEntries; j++)


entries[j-1] = entries[j]; // shift entries left

numEntries--; // one fewer entry

return e; // return the removed object


}
Summary

• We have designed and implemented a scoreboard


• The scoreboard can be seen as a data structure
• The data structure:
• Stores player records (name, score) utilizing a dynamic array.
• Supports adding and updating players
• Allows retrieving and comparing scores.
• More functions can be extended.
General Collections

• Can we make it more general?


• In the previous example, we require the scoreboard to be sorted.
• In many scenarios, we only require a collection of elements.
• The collection should provide some general operations
• E.g., add(), remove(), first(), last(), size(), etc.
Abstract Data Type (ADT)

• An abstract data type (ADT) is a set of objects together with a set


of operations.

ADT Public Functions


Data Structure Application Program
(Interface) (Client)
Implementation
add, remove, etc.

• ADT: focus on what operations can be applied to the objects.


• Does not mention how these operations are implemented.
Abstract Data Type (ADT)

• Container (collection)
• One of the basic ADTs.
• A data type that is capable of holding a collection of items.
• Required Operations
• size(): return the # elements in the container.
• clear(): removes all elements from the container.
• empty(): returns true if the container contains no
elements, and false otherwise.
Vector ADT

• A vector is an ADT that supports the following


operations, assume 0 ≤ 𝑖 ≤ 𝑠𝑖𝑧𝑒() − 1
• at(i): returns the element at index i.
• set(i, e): replace the element at index i with e.
• insert(i, e): insert a new element e to have index i.
• erase(i): remove the element at index i.

How can you implement a vector ADT?


Vector ADT

• Can you implement vector with a simple array?


• Key operations: class Vector {
private:
int* data; // pointer to array
• constructor int capacity; // total allocated size
• insert(i, e) int length; // current number of elements

• erase(i) public:
Vector(int cap = 10); // constructor
• size() ~Vector(); // destructor

void insert(int i, int e); // insert element at index i


void erase(int i); // remove element at index i
int size() const; // return number of elements
};
Vector ADT

• Question:
• What to do if the vector is full when inserting a new element?
void insert(int i, int e);

Resize & insert


- resize the array first, void resize(int newCap); How to resize?
- then insert the new element.
Two options:
- newCap = oldCap + 1 We prefer always double the size.
- newCap = oldCap *2 (reduce # of resize function calls)
Resize

• Resize
void Vector::resize(int newCap) {
int* newData = new int[newCap];
void Vector::insert(int i, int e) { for (int i = 0; i < length; i++) {
if (length == capacity) resize(capacity * 2); newData[i] = data[i];
}
for (int j = length; j > i; j--) {
data[j] = data[j - 1]; delete[] data;
} data = newData;
data[i] = e; capacity = newCap;
length++; }
}

Similarly, you can shrink the size after # of elements fall below a certain threshold.
Summary on Vector ADT

• Vector ADT
• Some basic operations:
• Insert, erase, size, …
• In our implementation
• Use array to store elements.
• Resize to copy all elements to a larger array when needed.
• In fact, we do have a standard vector implementation in STL (standard template
library)
• https://cplusplus.com/reference/vector/a/
An Alternative Approach

• Is using array the only way to store a list of elements?

https://www.happycoders.eu/algorithms/array-vs-linked-list/
Linked List

• Linked List
• A collection of nodes that together form a linear ordering.
• Node: stores one element and pointers (links) to the next node in the list.

• Define a base class/struct

struct Node{ struct Node{


string data; int data; Aka. Singly Linked List
Node* next; Node* next;
• Each node stores a single pointer.
} }
Linked List - Operations
Insert to the front

void SinglyLinkedList::addFront(const
string& e) { // add to front of list
Node* v = new Node; // create new node
v->elem = e; // store data
v->next = head; // head now follows v
head = v; // v is now the head
}
Linked List - Operations
Remove from the front

void SinglyLinkedList::removeFront() { //
remove front item
Node* old = head; // save current head
head = old->next; // skip over old
head
delete old; // delete the old head
}
Question

• What about inserting/deleting at a specific location?


• You will always need to start from the front!
• Any better ways to do this?
• Doubly Linked List
• Two pointers for each node:
• next and prev
Linked List

• Pros • Cons
• Access any item as long as • Overhead of links
external link to first item • No longer have direct access to
maintained each element of the list
• Insert/delete new item without • Access of nth item now less
shifting efficient
• Can expand/contract as necessary • Must go through first element, and
then second, and then third, etc
The Idea of Iterator

• Two ways of navigating in a linear data structure


• Array • Linked List
• Navigate using indices, e.g., arr[i] • Navigate using relative positions, e.g., next, previous.

• Iterator
• The object that is used to navigate through the container by advancing to the next
position in the container.
• Acts like a pointer.
List ADT

• A list is a linear, ordered collection of elements using the concept of an


iterator.
• Required Operations
• begin(): return an iterator referring to the first element.
• end(): return an iterator referring to an imaginary element just after the last
element
• insert(p, e): insert a new element e before position p.
• erase(p): remove the element at position p.

Note: p is an iterator that refers to a specific position in the list.


Stack ADT

• A stack is a container of objects that are inserted


and removed according to the last-in first-out
(LIFO) principle.
• Required Operations
• push(e): insert element e at the top of the stack
• pop(): remove the top element from the stack; an
error occurs if the stack is empty.
• peek(): return a reference to the top element on the
stack, without removing it; an error occurs if the stack is
empty.
Stack Applications

• Applications of stack?
• Stack of plates/cups…
• Undo / Redo Operations
• Broswer history
• Call logs in phones
•…
Stack Implementation
• How to implement stack?
• Static: Use a fixed size array.
• Dynamic: grow in size as needed, use a vector/list, etc.
• For a static stack of integers:
• How would you outline the class?
• What are the pros and cons?
• For a dynamic stack of integers:
• What is the main difference between static and dynamic?
• Can you use linked list to implement it? How?
• Pros and Cons?
Queue ADT

• A queue is a container of elements that are inserted


and removed according to the first-in first-out (FIFO)
principle.
• Required Operations
• enqueue(e): insert element e at the rear of the queue.
• dequeue(): remove element at the front of the queue;
an error occurs if the queue is empty.
• front(): return, but do not remove, a reference to the
front element in the queue; an error occurs if the queue is
empty.
Queue Applications

• Applications of Queue?
• Waiting lines in stores
• Printer jobs
• Booking systems
• Messages
•…
Queue Implementation
• How to implement queue?
• Static: Use a fixed size array.
• Dynamic: grow in size as needed, use a vector/list, etc.
• For a static queue of integers:
• How would you outline the class?
• What are the pros and cons?
• For a dynamic queue of integers:
• What is the main difference between static and dynamic?
• Can you use linked list to implement it? How?
• Pros and Cons?
Double-Ended Queue (Deque)
• Double-Ended Queues
• Supports insertion and deletion at both the front
and rear of the queue.
• Required Operations
• insertFront(e): insert element e at the front of
the queue.
• insertBack(e): insert element e at the end of the
queue. Look Familiar?
• eraseFront(): remove element at the front of the
queue;
Deque can be implemented using a
• eraseBack(): remove element at the end of the doubly linked list OR array.
queue;
Deque can be used to implement
Queue AND Stack
STL library

• Standard Template Library


• Defines ADT using template classes & functions.
#include <stack>
using std::stack; // make stack accessible
stack<int> myStack; // a stack of integers

#include <queue>
using std::queue; // make queue accessible
queue<float> myQueue; // a queue of floats

#include <list>
using std::list; // make list accessible
list<float> myList; // an empty list of floats
Interface vs Implementation

• Stack and Queue are two different ADTs


• However, by default they both utilizing deque (double ended
queue) as underlying container (data structure) in C++ STL.
Resources

• Chapter 3.1-3.3
• Chapter 5
• Chapter 6.1-6.2
• Visualization tool
• https://pythontutor.com/visualize.html#mode=edit
• C++ references
• https://cplusplus.com/reference/

You might also like