Abstract Datatypes and Data Structures: Stacks, Queues, ...

(抽象データ型とデータ構造、スタック、キューなど)

Data Structures and Algorithms

4th lecture, October 13, 2022

https://www.sw.it.aoyama.ac.jp/2022/DA/lecture4.html

Martin J. Dürst

AGU

© 2009-22 Martin J. Dürst 青山学院大学

 

Today's Schedule

 

Summary of Last Lecture: Big-O Notation

The asymptotic growth (order of growth) of a function and the time (and space) complexity of an algorithm can be expressed with the Big-O/Ω/Θ notation:

f(n)∈O(g(n)) ⇔ ∃c>0: ∃n0≥0: ∀nn0: f(n)≤c·g(n)

 

Summary of Last Lecture: Finding Order of Growth

The order of growth of a function can be found by:

When using Big-O notation, always try to simplify g() as much as possible.

 

Last Lecture's Homework

(no need to submit)

Review this lecture's material and the additional handout every day!

On the Web, find algorithms with time complexity
O(1), O(log n), O(n), O(n log n), O(n2), O(n3), O(2n), O(n!), and so on.

 

Frequent Orders

Example of other order: O(n2.373), fastest known algorithm for matrix multiplication (for data of size n2)

 

Polynomial versus Exponential Growth

Example:

1.1nn20

log(1.1)·n ≶ log(n)·20

n/log10(n) ≶ 20/log10(1.1) ≊483.2

n0 ≊ 1541

Conclusion: For any a, b > 1, an will always eventually grow faster than nb (O(nb)⊊O(an))

(nb is polynominal, an is exponential)

 

The Importance of Polynomial Time

[We will discuss this in more detail in lecture 14]

 

Finding the (Asymptotic) Time Complexity of an Algorithm

  1. Find/define the variables that determine the problem/input size (e.g. n)
  2. Find the basic operations (steps) in the algorithm that are most frequently executed
  3. Express the total number of basic operations (steps) using summation or a recurrence relation
  4. Determine the time complexity expressed with big-O notation

Simplifications possible for big-O notation can be applied early.
Example: Because constant factors are irrelevant in big-O notation, they can be eliminated when counting steps.

 

Finding Time Complexity: A Very Simple Example

Time complexity of linear search:

  1. Variable that determines size of input: Size of dictionary n
  2. Most frequently executed basic operations: Loop is executed once per data item, runs in constant time.
  3. Total number of steps: n × O(1)
  4. Time complexity: O(n)

 

How to Define Input Size Variables

 

How to Identify the Most Frequent Basic Operations

Caution: Some methods/functions may hide complexity (e.g. Ruby sort, C strlen, qsort,...)

 

Counting Basic Operations using Summation

 

Counting Basic Operations using Recurrence Relations

 

Ceiling/Floor Functions

 

Recurrence Relations

 

Comparing the Execution Time of Algorithms

(from previous lectures)

Possible questions:

Conclusion: Expressing time complexity as O() allows to evaluate the essence of an algorithm, ignoring hardware and implementation differences.

 

Abstract Data Type (ADT)

 

Typical Examples of Abstract Data Types

 

Stack

General example:
Stack of trays in cafeteria
Principle:
Last-In-First-Out (LIFO)
Example from IT:
Function stack (local variables, return address, ...)
Main methods:
new, add/push, delete/pop, top
Other methods:
empty? (check whether the stack is empty or not)
top (return the topmost element without removing it from the stack)

 

Axioms for Stacks

It is possible to define a stack using the following four axioms:

  1. Stack.new.empty? ↔ true
  2. s.push(e).empty? ↔ false
  3. s.push(e).top ↔ e
  4. s.push(e).pop ↔ s (here, pop returns the new stack, not the top element)

(s is any arbitrary stack, e is any arbitrary data item)

Axioms can define a contract between implementation and users

 

Queue

General example:
Queue of people in cafeteria waiting for food
Principle:
First-In-First-Out (FIFO)
Example from IT:
Queue of processes waiting for execution
Main methods:
add/enqueue, remove/delete/dequeue
Explain the meaning of GIGO: Garbage in, garbage out.

 

Comparing ADTs

Implementation: 4ADTs.rb; some complexities can be improved by using additional variables

ADT stack queue
Implemented as Array LinearList Array LinearList
create O(n) O(1) O(n) O(1)
add O(1) O(1) or O(n) O(n) or O(1) O(n) or O(1)
delete O(1) O(n) or O(1) O(1) or O(n) O(1) or O(n)
empty? O(1) O(1) O(1) O(1)
length O(1) O(n) O(1) O(n)

 

Summary

 

Homework

(no need to submit)

  1. Order the following orders of growth, and explain the reason for your order:

    O(n2), O(n!), O(n log log n), O(n log n), O(20n)

  2. Write a simple program that uses the classes in 4ADTs.rb.
    Use this program to compare the implementations.
    Hint: Use the second part of 2search.rb as an example.
  3. Implement the priority queue ADT (use Ruby or any other programming language)
    A priority queue keeps a priority value (e.g. integer) for each data item.
    In the simplest case, the data consists of a priority value only.
    The items with the highest priority leave the queue first.
    Your implementation can use an array or a linked list or any other data structure.

 

Glossary

polynomial growth
多項式増加
exponential growth
指数的増加
integers with unlimited precision
非固定長整数
summation
総和
recurrence (relation)
漸化式
ceiling function
天井関数
floor function
床関数
substitution
置換
abstract data type
抽象データ型
encapsulation
カプセル化
data integrity
データの完全性
modularization
モジュール化
type theory
型理論
object-oriented
オブジェクト指向 (形容詞)
type
class
クラス
member function
メンバ関数
method
メソッド
stack
スタック
cafeteria
食堂
axiom
公理
queue
待ち行列、キュー
ring buffer
リングバッファ
priority queue
順位キュー、優先順位キュー、優先順位付き待ち行列