EECE 330 Chapter 1 Old Lectures, Fall 2007

American University of Beirut · Data Structures and Algorithms · 59 pages

All EECE 330 files
EECE 330 Chapter 1 Old Lectures, Fall 2007, page 1

Stuck on a question? A tutor can walk you through it.

EECE 330 Chapter 1 Old Lectures, Fall 2007, page 2 EECE 330 Chapter 1 Old Lectures, Fall 2007, page 3 EECE 330 Chapter 1 Old Lectures, Fall 2007, page 4 EECE 330 Chapter 1 Old Lectures, Fall 2007, page 5 EECE 330 Chapter 1 Old Lectures, Fall 2007, page 6 EECE 330 Chapter 1 Old Lectures, Fall 2007, page 7 EECE 330 Chapter 1 Old Lectures, Fall 2007, page 8 EECE 330 Chapter 1 Old Lectures, Fall 2007, page 9 EECE 330 Chapter 1 Old Lectures, Fall 2007, page 10

Showing the first 10 of 59 pages. Download the PDF to see all of it.

More EECE 330 files

Show the text of this lab
An Overview of C++ Douglas C. Schmidt Professor Department of EECS d.schmidt@vanderbilt.edu Vanderbilt University www.dre.vanderbilt.edu/∼schmidt/ (615) 343-8197 August 31, 2009 An Overview of C++ Douglas C. Schmidt C++ Overview • C++ was designed at AT&T Bell Labs by Bjarne Stroustrup in the early 80’s – The original cfront translated C++ into C for portability ∗ However, this was difficult to debug and potentially inefficient – Many native host machine compilers now exist ∗ e.g., Borland, DEC, GNU, HP, IBM, Microsoft, Sun, Symantec, etc. • C++ is a mostly upwardly compatible extension of C that provides: 1. Stronger typechecking 2. Support for data abstraction 3. Support for object-oriented programming 4. Support for generic programming Vanderbilt University 1 An Overview of C++ Douglas C. Schmidt C++ Design Goals • As with C, run-time efficiency is important – Unlike other languages (e.g., Ada) complicated run-time libraries have not traditionally been required for C++ ∗ Note, that there is no language-specific support for concurrency, persistence, or distribution in C++ • Compatibility with C libraries & traditional development tools is emphasized, e.g., – Object code reuse ∗ The storage layout of structures is compatible with C ∗ e.g., support for X-windows, standard ANSI C library, & UNIX/WIN32 system calls via extern block – C++ works with the make recompilation utility Vanderbilt University 2 An Overview of C++ Douglas C. Schmidt C++ Design Goals (cont’d) • “As close to C as possible, but no closer” – i.e., C++ is not a proper superset of C → backwards compatibility is not entirely maintained ∗ Typically not a problem in practice... • Note, certain C++ design goals conflict with modern techniques for: 1. Compiler optimization – e.g., pointers to arbitrary memory locations complicate register allocation & garbage collection 2. Software engineering – e.g., separate compilation complicates inlining due to difficulty of interprocedural analysis – Dynamic memory management is error-prone Vanderbilt University 3 An Overview of C++ Douglas C. Schmidt Major C++ Enhancements 1. C++ supports object-oriented programming features • e.g., abstract classes, inheritance, & virtual methods 2. C++ supports data abstraction & encapsulation • e.g., the class mechanism & name spaces 3. C++ supports generic programming • e.g., parameterized types 4. C++ supports sophisticated error handling • e.g., exception handling 5. C++ supports identifying an object’s type at runtime • e.g., Run-Time Type Identification (RTTI) Vanderbilt University 4 An Overview of C++ Douglas C. Schmidt Important Minor Enhancements • C++ enforces type checking via function prototypes • Provides type-safe linkage • Provides inline function expansion • Declare constants that can be used to define static array bounds with the const type qualifier • Built-in dynamic memory management via new & delete operators • Namespace control Vanderbilt University 5 An Overview of C++ Douglas C. Schmidt Useful Minor Enhancements • The name of a struct, class, enum, or union is a type name • References allow “call-by-reference” parameter modes • New type-secure extensible iostreams I/O mechanism • “Function call”-style cast notation • Several different commenting styles • New mutable type qualifier • New bool boolean type Vanderbilt University 6 An Overview of C++ Douglas C. Schmidt Questionable Enhancements • Default values for function parameters • Operator & function overloading • Variable declarations may occur anywhere statements may appear within a block • Allows user-defined conversion operators • Static data initializers may be arbitrary expressions Vanderbilt University 7 An Overview of C++ Douglas C. Schmidt Language Features Not Part of C++ 1. Concurrency • “Concurrent C” by Gehani • Actor++ model by Lavender & Kafura 2. Persistence • Object Store, Versant, Objectivity • Exodus system & E programming language 3. Garbage Collection • USENIX C++ 1994 paper by Ellis & Detlefs • GNU g++ 4. Distribution • CORBA, RMI, COM+, SOAP, etc. Vanderbilt University 8 An Overview of C++ Douglas C. Schmidt Strategies for Learning C++ • Focus on concepts & programming techniques – Don’t get lost in language features • Learn C++ to become a better programmer – More effective at designing & implementing – Design Patterns • C++ supports many different programming styles • Learn C++ gradually – Don’t have to know every detail of C++ to write a good C++ program Vanderbilt University 9 An Overview of C++ Douglas C. Schmidt Stack Example • The following slides examine several alterative methods of implementing a Stack – Begin with C & evolve up to various C++ implementations • First, consider the “bare-bones” implementation: typedef int T; #define MAX_STACK 100 /* const int MAX_STACK = 100; */ T stack[MAX_STACK]; int top = 0; T item = 10; stack[top++] = item; // push ... item = stack[--top]; // pop • Obviously not very abstract... Vanderbilt University 10 An Overview of C++ Douglas C. Schmidt Data Hiding Implementation in C • Define the interface to a Stack of integers in C in Stack.h: /* Type of Stack element. */ typedef int T; /* Stack interface. */ int create (int size); int destroy (void); void push (T new_item); void pop (T *old_top); void top (T *cur_top); int is_empty (void); int is_full (void); Vanderbilt University 11 An Overview of C++ Douglas C. Schmidt Data Hiding Implementation in C (cont’d) • /* File stack.c */ #include "stack.h" static int top_, size_; /* Hidden within this file. */ static T *stack_; int create (int size) { top_ = 0; size_ = size; stack_ = malloc (size * sizeof (T)); return stack_ == 0 ? -1 : 0; } void destroy (void) { free ((void *) stack_); } void push (T item) { stack_[top_++] = item;} void pop (T *item) { *item = stack_[--top_]; } void top (T *item) { *item = stack_[top_ - 1]; } int is_empty (void) { return top_ == 0; } int is_full (void) { return top_ == size_; } Vanderbilt University 12 An Overview of C++ Douglas C. Schmidt Data Hiding Implementation in C (cont’d) • Use case #include "stack.h" void foo (void) { T i; push (10); /* Oops, forgot to call create! */ push (20); pop (&i); destroy (); } • Main problems: 1. The programmer must call create() first & destroy() last! 2. There is only one stack & only one type of stack 3. Name space pollution... 4. Non-reentrant Vanderbilt University 13 An Overview of C++ Douglas C. Schmidt Data Abstraction Implementation in C • An ADT Stack interface in C: typedef int T; typedef struct { size_t top_, size_; T *stack_; } Stack; int Stack_create (Stack *s, size_t size); void Stack_destroy (Stack *s); void Stack_push (Stack *s, T item); void Stack_pop (Stack *, T *item); /* Must call before pop’ing */ int Stack_is_empty (Stack *); /* Must call before push’ing */ int Stack_is_full (Stack *); /* ... */ Vanderbilt University 14 An Overview of C++ Douglas C. Schmidt Data Abstraction Implementation in C (cont’d) • An ADT Stack implementation in C: #include "stack.h" int Stack_create (Stack *s, size_t size) { s->top_ = 0; s->size_ = size; s->stack_ = malloc (size * sizeof (T)); return s->stack_ == 0 ? -1 : 0; } void Stack_destroy (Stack *s) { free ((void *) s->stack_); s->top_ = 0; s->size_ = 0; s->stack_ = 0; } void Stack_push (Stack *s, T item) { s->stack_[s->top_++] = item; } void Stack_pop (Stack *s, T *item) { *item = s->stack_[--s->top__]; } int Stack_is_empty (Stack *s) { return s->top_ == 0; } Vanderbilt University 15 An Overview of C++ Douglas C. Schmidt Data Abstraction Implementation in C (cont’d) • Use case void foo (void) { Stack s1, s2, s3; /* Multiple stacks! */ T item; Stack_pop (&s2, &item); /* Pop’d empty stack */ /* Forgot to call Stack_create! */ Stack_push (&s3, 10); s2 = s3; /* Disaster due to aliasing!!! */ /* Destroy uninitialized stacks! */ Stack_destroy (&s1); Stack_destroy (&s2); } Vanderbilt University 16 An Overview of C++ Douglas C. Schmidt Main problems with Data Abstraction in C 1. No guaranteed initialization, termination, or assignment 2. Still only one type of stack supported 3. Too much overhead due to function calls 4. No generalized error handling... 5. The C compiler does not enforce information hiding e.g., s1.top_ = s2.stack_[0]; /* Violate abstraction */ s2.size_ = s3.top_; /* Violate abstraction */ Vanderbilt University 17 An Overview of C++ Douglas C. Schmidt Data Abstraction Implementation in C++ • We can get encapsulation and more than one stack: typedef int T; class Stack { public: Stack (size_t size); Stack (const Stack &s); void operator= (const Stack &); ~Stack (void); void push (const T &item); void pop (T &item); bool is_empty (void) const; bool is_full (void) const; private: size_t top_, size_; T *stack_; }; Vanderbilt University 18 An Overview of C++ Douglas C. Schmidt Data Abstraction Implementation in C++ (cont’d) • Manager operations Stack::Stack (size_t s): top_ (0), size_ (s), stack_ (new T[s]) {} Stack::Stack (const Stack &s) : top_ (s.top_), size_ (s.size_), stack_ (new T[s.size_]) { for (size_t i = 0; i < s.size_; i++) stack_[i] = s.stack_[i]; } void Stack::operator = (const Stack &s) { if (this == &s) return; T *temp_stack = new T[s.size_]; delete [] stack_; for (size_t i = 0; i < s.size_; i++) temp_stack[i] = s.stack_[i]; stack_ = temp_stack; top_ = s.top_; size_ = s.size_; } Stack::~Stack (void) { delete [] stack_; } Vanderbilt University 19 An Overview of C++ Douglas C. Schmidt Data Abstraction Implementation in C++ (cont’d) • Accessor & worker operations bool Stack::is_empty (void) const { return top_ == 0; } bool Stack::is_full (void) const { return top_ == size_; } void Stack::push (const T &item) { stack_[top_++] = item; } void Stack::pop (T &item) { item = stack_[--top_]; } Vanderbilt University 20 An Overview of C++ Douglas C. Schmidt Data Abstraction Implementation in C++ (cont’d) • Use case #include "Stack.h" void foo (void) { Stack s1 (1), s2 (100); T item; if (!s1.is_full ()) s1.push (473); if (!s2.is_full ()) s2.push (2112); if (!s2.is_empty ()) s2.pop (item); // Access violation caught at compile-time! s2.top_ = 10; // Termination is handled automatically. } Vanderbilt University 21 An Overview of C++ Douglas C. Schmidt Benefits of C++ Data Abstraction Implemenation 1. Data hiding & data abstraction, e.g., Stack s1 (200); s1.top_ = 10 // Error flagged by compiler! 2. The ability to declare multiple stack objects Stack s1 (10), s2 (20), s3 (30); 3. Automatic initialization & termination { Stack s1 (1000); // constructor called automatically. // ... // Destructor called automatically } Vanderbilt University 22 An Overview of C++ Douglas C. Schmidt Drawbacks with C++ Data Abstraction Implementation 1. Error handling is obtrusive • Use exception handling to solve this (but be careful)! 2. The example is limited to a single type of stack element (int in this case) • We can use C++ “parameterized types” to remove this limitation 3. Function call overhead • We can use C++ inline functions to remove this overhead Vanderbilt University 23 An Overview of C++ Douglas C. Schmidt Exception Handling Implementation in C++ (cont’d) • C++ exceptions separate error handling from normal processing typedef int T; class Stack { public: class Underflow { /* ... */ }; class Overflow { /* ... */ }; Stack (size_t size); ~Stack (void); void push (const T &item) throw (Overflow); void pop (T &item) throw (Underflow); bool is_empty (void) const; bool is_full (void) const; private: size_t top_, size_; T *stack_; }; Vanderbilt University 24 An Overview of C++ Douglas C. Schmidt Exception Handling Implementation in C++ (cont’d) • Stack.cpp void Stack::push (const T &item) throw (Stack::Overflow) { if (is_full ()) throw Stack::Overflow (); stack_[top_++] = item; } void Stack::pop (T &item) throw (Stack::Underflow) { if (is_empty ()) throw Stack::Underflow (); item = stack_[--top_]; } Vanderbilt University 25 An Overview of C++ Douglas C. Schmidt Exception Handling Implementation in C++ (cont’d) • Stack.cpp Stack::Stack (const Stack &s): : top_ (s.top_), size_ (s.size_), stack_ (0) { scoped_array<T> temp_array (new T[s.size_]); for (size_t i = 0; i < s.size_; i++) temp_array[i] = s.stack_[i]; temp_array.swap (stack_); } void Stack::operator = (const Stack &s) { if (this == &s) return; // Check for self-assignment Stack t (s); std::swap (t.top_, top_); std::swap (t.size__, size_); std::swap (t.stack_, stack_); } Vanderbilt University 26 An Overview of C++ Douglas C. Schmidt Exception Handling Implementation in C++ (cont’d) • scoped_array extends auto_ptr to arrays • Deletion of array is guaranteed on destruction of scoped_array template <typename T> class scoped_array { public: explicit scoped_array (T *p = 0) : ptr_ (p) {} ~scoped_array () { delete [] ptr_; } T &operator[](std::ptrdiff_t i) const { return ptr_[i]; } T *get() const { return ptr_; } void swap (T *&b) { T *tmp = b; b = ptr_; ptr_ = tmp; } private: T *ptr_; // Disallow copying scoped_array (const scoped_array<T> &); scoped_array &operator=(const scoped_array<T> &); }; Vanderbilt University 27 An Overview of C++ Douglas C. Schmidt Exception Handling Implementation in C++ (cont’d) • Use case #include "Stack.h" void foo (void) { Stack s1 (1), s2 (100); try { T item; s1.push (473); s1.push (42); // Exception, push’d full stack! s2.pop (item); // Exception, pop’d empty stack! s2.top_ = 10; // Access violation caught! } catch (Stack::Underflow) { /* Handle underflow... */ } catch (Stack::Overflow) { /* Handle overflow... */ } catch (...) { /* Catch anything else... */ throw; } } // Termination is handled automatically. } Vanderbilt University 28 An Overview of C++ Douglas C. Schmidt Template Implementation in C++ • A parameterized type Stack class interface using C++ template <typename T> class Stack { public: Stack (size_t size); ~Stack (void) void push (const T &item); void pop (T &item); bool is_empty (void) const; bool is_full (void) const; private: size_t top_, size_; T *stack_; }; • To simplify the following examples we’ll omit exception handling, but note that it’s important to ensure exception-safety guarantees! Vanderbilt University 29 An Overview of C++ Douglas C. Schmidt Template Implementation in C++ (cont’d) • A parameterized type Stack class implementation using C++ template <typename T> inline Stack<T>::Stack (size_t size) : top_ (0), size_ (size), stack_ (new T[size]) { } template <typename T> inline Stack<T>::~Stack (void) { delete [] stack_; } template <typename T> inline void Stack<T>::push (const T &item) { stack_[top_++] = item; } template <typename T> inline void Stack<T>::pop (T &item) { item = stack_[--top_]; } Vanderbilt University 30 An Overview of C++ Douglas C. Schmidt Template Implementation in C++ (cont’d) • Note minor changes to accommodate parameterized types #include "Stack.h" void foo (void) { Stack<int> s1 (1000); Stack<float> s2; Stack< Stack <Activation_Record> *> s3; s1.push (-291); s2.top_ = 3.1416; // Access violation caught! s3.push (new Stack<Activation_Record>); Stack <Activation_Record> *sar; s3.pop (sar); delete sar; // Termination is handled automatically } Vanderbilt University 31 An Overview of C++ Douglas C. Schmidt Template Implementation in C++ (cont’d) • Another parameterized type Stack class template <typename T, size_t SIZE> class Stack { public: Stack (void); ~Stack (void) void push (const T &item); void pop (T &item); private: size_t top_, size_; T stack_[SIZE]; }; • No need for dynamic memory, though SIZE must be const, e.g., Stack<int, 200> s1; Vanderbilt University 32 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ • Problems with previous examples: – Changes to the implementation will require recompilation & relinking of clients – Extensions will require access to the source code • Solutions – Combine inheritance with dynamic binding to completely decouple interface from implementation & binding time – This requires the use of C++ abstract base classes Vanderbilt University 33 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ (cont’d) • Defining an abstract base class in C++ template <typename T> class Stack { public: virtual ~Stack (void) = 0; // Need implementation! virtual void push (const T &item) = 0; virtual void pop (T &item) = 0; virtual bool is_empty (void) const = 0; virtual bool is_full (void) const = 0; void top (T &item) { // Template Method pop (item); push (item); } }; • By using “pure virtual methods,” we can guarantee that the compiler won’t allow instantiation! Vanderbilt University 34 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ (cont’d) • Inherit to create a specialized stack implemented via an STL vector: #include "Stack.h" #include <vector> template <typename T> class V_Stack : public Stack<T> { public: enum { DEFAULT_SIZE = 100 }; V_Stack (size_t size = DEFAULT_SIZE); virtual void push (const T &item); virtual void pop (T &item); virtual bool is_empty (void) const; virtual bool is_full (void) const; private: size_t top_; // built-in std::vector<T> stack_; // user-defined }; Vanderbilt University 35 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ (cont’d) • class V Stack implementation template <typename T> V_Stack<T>::V_Stack (size_t size): top_ (0), stack_ (size) {} template <typename T> void V_Stack<T>::push (const T &item) { stack_[top_++] = item; } template <typename T> void V_Stack<T>::pop (T &item) { item = stack_[--top_]; } template <typename T> int V_Stack<T>::is_full (void) const { return top_ >= stack_.size (); } Vanderbilt University 36 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ (cont’d) • Inheritance can also create an linked list stack: template <typename T> class Node; // forward declaration. template <typename T> class L_Stack : public Stack<T> { public: enum { DEFAULT_SIZE = 100 }; L_Stack (size_t hint = DEFAULT_SIZE); ~L_Stack (void); virtual void push (const T &new_item); virtual void pop (T &top_item); virtual bool is_empty (void) const { return head_ == 0; } virtual bool is_full (void) const { return 0; } private: // Head of linked list of Node<T>’s. Node<T> *head_; }; Vanderbilt University 37 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ (cont’d) • class Node implementation template <typename T> class Node { friend template <typename T> class L_Stack; public: Node (T i, Node<T> *n = 0): item_ (i), next_ (n) {} private: T item_; Node<T> *next_; }; • Note that the use of the “Cheshire cat” idiom allows the library writer to completely hide the representation of class V Stack... Vanderbilt University 38 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ (cont’d) • class L Stack implementation: template <typename T> L_Stack<T>::L_Stack (size_t): head_ (0) {} template <typename T> void L_Stack<T>::push (const T &item) { Node<T> *t = new Node<T> (item, head_); head_ = t; } template <typename T> void L_Stack<T>::pop (T &top_item) { top_item = head_->item_; Node<T> *t = head_; head_ = head_->next_; delete t; } template <typename T> L_Stack<T>::~L_Stack (void) { for (T t; head_ != 0; pop (t)) continue; } Vanderbilt University 39 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ (cont’d) • Using our abstract base class, it is possible to write code that does not depend on the stack implementation, e.g., template <typename T> Stack<T> *make_stack (bool use_V_Stack) { return use_V_Stack ? new V_Stack<T> : new L_Stack<T>; } template <typename T> void foo (Stack<T> *stack, const T &t) { T s; stack->push (t); stack->pop (s); // ... } foo<int> (make_stack<int> (true), 10); Vanderbilt University 40 An Overview of C++ Douglas C. Schmidt Object-Oriented Implementation in C++ (cont’d) • Moreover, we can make changes at run-time without modifying, recompiling, or relinking existing code – i.e., can use “dynamic linking” to select stack representation at run-time, e.g., char stack_symbol[MAXNAMLEN]; char stack_file[MAXNAMLEN]; cin >> stack_file >> stack_symbol; void *handle = ACE_OS::dlopen (stack_file); void *sym = ACE_OS::dlsym (handle, stack_symbol); if (Stack<int> *sp = // Note use of RTTI dynamic_cast <Stack<int> *> (sym)) foo (sp); • Note, no need to stop, modify, & restart an executing application! – Naturally, this requires careful configuration management... Vanderbilt University 41 An Overview of C++ Douglas C. Schmidt Summary • A major contribution of C++ is its support for defining abstract data types (ADTs) & for generic programming – e.g., classes, parameterized types, & exception handling • For some systems, C++’s ADT support is more important than using the OO features of the language • For other systems, the use of C++’s OO features is essential to build highly flexible & extensible software – e.g., inheritance, dynamic binding, & RTTI Vanderbilt University 42 EECE 330 Data Structures and Algorithms American University of Beirut Topic #01: INTRODUCTION TO ALGORITHM ANALYSIS; SORTING PROBLEM READINGS: [Shaffer] Chapters 2,3 REFERENCES: [CLRS] Chapters 1,2 • MOTIVATION: Linear Search, Binary Search • SORTING PROBLEM • INSERTION SORT • MERGE SORT – E.C.E., AUB – 1 THE SORTING PROBLEM; MOTIVATION • One of the most frequently performed tasks −→ Introduction to “algorithm analysis” • Having “sorted” data makes searching more efficient Recall Linear Search Binary Search – E.C.E., AUB – 2 Linear Search: Pseudocode: LINEAR-SEARCH(A[1,··· ,n],key) 1 for i ← 1 to n 2 do if A[i] = key 3 then return i 4 return Not Found Translation into C++: Running Time: – E.C.E., AUB – 3 Binary Search: Assumes the array is already sorted Compare the key to middle element If smaller, search first half If greater, search second half BINARY-SEARCH(A[1,··· ,n],key) 1 min ← 1 2 max ← n 3 while min ≤ max 4 do mid ← (min+max)/2 5 if key = A[mid] 6 then return mid 7 else if key > A[mid] 8 then min ← mid +1 9 else max ← mid −1 10 return Not Found – E.C.E., AUB – 4 Translation into C++: Running Time: – E.C.E., AUB – 5 THE SORTING PROBLEM; DEFINITION Definition: Sorting Problem Input: sequence (a1,a2,··· ,an) of numbers Output: permutation (a′ 1,a′ 2,··· ,a′ n) such that a′ 1 ≤ a′ 2 ≤ ··· ≤ a′ n Example: −→ Need an algorithm to solve this problem We will see 2 algorithms: Insertion sort and Merge sort – E.C.E., AUB – 6 INSERTION SORT Like sorting your deck of cards in a game of “Tarnib” Example: INSERTION-SORT(A[1,··· ,n]) 1 for i ← 2 to n 2 do key ← A[i] 3 j ← i−1 4 while j > 0 and A[j] > key 5 do A[j +1] ← A[j] 6 j ← j −1 7 A[j +1] ← key – E.C.E., AUB – 7 Correctness Proof Claim: At the end of each iteration of the for loop, A[1,··· ,i] consists of the original elements of A[1,··· ,i] but in sorted order Proof of claim: Proof of correctness of Insertion-Sort: Note: loop-invariant properties ⇐⇒ arguments by induction – E.C.E., AUB – 8 Running Time Best case? Worst case? “Average” case? −→ Function of the input size −→ Machine dependent ! Notes: Remove machine-dependencies: ignore machine-dependent constants Consider asymptotic growth: as input-size n increases to infinity −→ Drop low order terms −→ Ignore constants Example: – E.C.E., AUB – 9 Notation: We say 5n2 +n ∈ Θ(n2) or simply 5n2 +n = Θ(n2) Examples: 2n−6√n = Θ(n), 4n+logn = Θ(n) Formal definitions ... later Worst-case running-time of Insertion-Sort: Let T(n) be the max running time on all inputs of size n Occurs when input is sorted in reverse order! Fix such input Let u(i) be the time of the i-th iteration in the “for loop” – E.C.E., AUB – 10 T(n) = n ∑ i=2 u(i) Now u(i) = c2 +c3 +c4i+c5(i−1)+c6(i−1)+c7, Since n ∑ i=2 i = ⇒ T(n) = – E.C.E., AUB – 11 MERGE SORT It’s a recursive procedure as opposed to iterative (like Insertion Sort) Idea: Input A[1···n] (i) If n = 1 DONE (ii) If n > 1, recursively sort A[1,··· ,⌈n/2⌉] and A[⌈n/2⌉+1,··· ,n] (iii) Merge the two sorted arrays Big Picture: Divide & Conquer approach Divide the problem into a number of subproblems Conquer subproblems by solving them recursively (until sizes are small enough) Combine the solutions of the subproblems into the solution of the original problem Example: – E.C.E., AUB – 12 MERGE-SORT(A, p,r) 1 if p < r 2 then q ← ⌊ p+r 2 ⌋ 3 MERGE-SORT(A, p,q) 4 MERGE-SORT(A,q+1,r) 5 MERGE(A[p,··· ,q],A[q+1,··· ,r]) Note: Initial call: Merge-Sort (A,1,n) The “Merge” function takes as input two sorted arrays – E.C.E., AUB – 13 MERGE(L[1,··· ,n1],R[1,··· ,n2]) 1 Construct an all-zero array C of size n1 +n2 2 i ← 1 3 j ← 1 4 for k ← 1 to n1 +n2 5 do if L[i] ≤ R[j] 6 then C[k] ← L[i] 7 i ← i+1 8 else C[k] ← R[j] 9 j ← j +1 10 return C Running-Time of “Merge”: – E.C.E., AUB – 14 Correctness Proof of Merge-sort ... (by induction) Worst-case running time of Merge-Sort Let T(n) be the max running time on all inputs of size n Recurrence: T(n) = � Θ(1) if n = 1 T � ⌈n 2⌉ � +T � ⌊n 2⌋ � +Θ(n) if n > 1 Consider a simplified version of the recurrence: n a power of 2 general case ... later Assume the running time of “Merge” is cn, where c is a positive constant ⇒ Recurrence: T(n) = � c0 if n = 1 2T �n 2 � +cn if n > 1 – E.C.E., AUB – 15 Solution: using the Recursion-tree method depth/height of the tree? count the leaves: T(n) = – E.C.E., AUB – 16 Summary • Insertion Sort • Merge Sort • Note: There are hidden constants in asymptotic running-time analysis • Recursive algorithm, Divide and Conquer approach, Recurrence relation, Recursion-Tree method, proof by Induction – E.C.E., AUB – 17 EECE 330 Data Structures and Algorithms American University of Beirut Topic #05: C++ REVIEW READINGS: [Malik] Chapters 14, 13 • TEMPLATES • VIRTUAL FUNCTIONS – E.C.E., AUB – 1 TEMPLATES Example • Arrays are essentially pointers in disguise An array “a” is a pointer to (memory address of) the first element of the array “a” “T a[size];” creates a variable a of type “T *” it will be pointing to “a[0]” Similarly, “a” is simply “&a[0]” In general: “a[i]” is equivalent to “*(a+i)” “a+i” is equivalent to “&a[i]” – E.C.E., AUB – 2 • To pass an array as an argument to a function void f(int * a, int n) { //do something } Or void f(int a[], int n) { //do something } – E.C.E., AUB – 3 Or void f(int a[10]) { //assume a has size 10 //do something } Misleading!, because • What if we want the compiler to fully enforce the type on the argument? (a function that takes as parameter an array of integers of size 10, i.e. the whole thing as one entity, not just the pointer) −→ pass the array by reference It fully preserves the information about the type of the array – E.C.E., AUB – 4 void f(int (&a)[10]) { . . . } • We lost some flexibility! We need a function for every possible array size void f(int (&a)[1]) { //process array of size 1 } void f(int (&a)[2]) { //process array of size 2 } . . void f(int (&a)[100]) { //process array of size 100 } – E.C.E., AUB – 5 • what if we can generate the appropriate function only when we need it? • C++ provides such ability using a template template <int n> void f(int (&a)[n]) { //process array of size n } • Represents an infinite number of functions, one for each possible value of n • Compiler however does not generate all of them (it is impossible to do so) • When needed, the compiler performs the appropriate specialization of the template, determines a specific value for n (called the parameter of the template) generates the corresponding function – E.C.E., AUB – 6 Can go further! make the function independent of the type of elements of the array template<class T, int n> void f(T (&a)[n]) { //process an array of Ts of size n } General syntax: for templated functions and classes template <class Type> declaration; “Type” is the type of the data; specifies type of parameters, return type of a function, declares variables within a function “declaration” is either a function declaration or a class declaration “class” refers to any user-defined type or built-in type – E.C.E., AUB – 7 #include <iostream> #include <string> using namespace std; template <class Type> Type larger(Type x, Type y); int main() { string str1 = "Hello"; string str2 = "Happy"; cout << "Larger of 5 and 6 = " << larger(5, 6) << endl; cout << "Larger of A and B = " << larger(’A’, ’B’) << endl; cout << "Larger of 5.6 and 3.2 = " << larger(5.6, 3.2) << endl; cout << "Larger of " << str1 << " and " << str2 << " = " << larger(str1, str2) << endl; return 0; } template<class Type> Type larger(Type x, Type y) { if (x >= y) return x; else return y; } – E.C.E., AUB – 8 Syntax: definition of member functions of templated classes template<class Type> returnType className<Type>::memberFunction(){ //do whatever it needs to do} −→ The function members of a class template are considered function templates className<specificType> anObject; For the compiler to specialize the template, all parameters of the template must be known at compile time Passing parameters to a function takes effect at run time Passing a parameter to a class template takes effect at compile time – E.C.E., AUB – 9 Consequences: Cannot compile the implementation file independently of the user code Can put class definition and the definitions of the function templates directly in the user code Can put class definition and the definitions of the function templates in the same header file Or you can have declaration in header .h file along with a directive to include definition from a definition .cpp file – E.C.E., AUB – 10 VIRTUAL FUNCTIONS • Recall a class object can be passed by value or by reference, but parameters need to match • In C++, we can pass an object of a derived class to a formal parameter of the base class type • Without virtual functions, C++ would associate the function with the proper class. This is called compile-time binding: necessary code to call a specific function is generated by the compiler. Also known as static binding – E.C.E., AUB – 11 Example: class baseClass { public: void print(); baseClass( int u = 0); private: int x; }; #include <iostream> #include "baseClass.h" using namespace std; void baseClass::print() //Note