Summary of C++ Data Structures Cheat Sheet, Cheat Sheet of Data Structures and Algorithms

Professor Wayne Goddard of Clemson University summarized data structure in single file

Typology: Cheat Sheet

2020/2021

Uploaded on 04/23/2021

picoo
picoo 🇮🇳

4.5

(13)

235 documents

1 / 77

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
Summary of C++ Data Structures
Wayne Goddard
School of Computing, Clemson University, 2018
Part 0: Review
1 BasicsofC++ ............................... 1
2 BasicsofClasses .............................. 3
3 ProgramDevelopment ........................... 5
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41
pf42
pf43
pf44
pf45
pf46
pf47
pf48
pf49
pf4a
pf4b
pf4c
pf4d

Partial preview of the text

Download Summary of C++ Data Structures Cheat Sheet and more Cheat Sheet Data Structures and Algorithms in PDF only on Docsity!

Summary of C++ Data Structures

Wayne Goddard

School of Computing, Clemson University, 2018

Part 0: Review

1 Basics of C++............................... 1 2 Basics of Classes.............................. 3 3 Program Development........................... 5

CpSc2120 – Goddard – Notes Chapter 1

Basics of C++

1.1 Summary

C++ is an extension of C. So the simplest program just has a main function. The program is compiled on our system with g++, which by default produces an executable a.out that is run from the current directory. C++ has for, while and do for loops, if and switch for conditionals. The standard output is accessed by cout. The standard input is accessed by cin. These require inclusion of iostream library. The language is case-sensitive.

1.2 Data Types

C++ has several data types that can be used to store integers; we will mainly use int. We will use char for characters. Note that, one can treat a char as an integer for arithmetic: for example

char myChar = ’D’; int pos = myChar - ’A’ + 1; cout << "the char " << myChar << " is in position " << pos << " in the alphabet" << endl;

These integer-types also come in unsigned versions. We will not use these much. But do note that arithmetic with unsigned data types is different. For example the code

for( unsigned int X=10; X>=0; X--) cout << X;

is an infinite loop, since decrementing 0 produces a large number. C++ has several data types that can be used to store floating-point numbers; we will almost always use double. There is also bool for boolean (that is, true or false); sometimes integers are substituted, where 0 means false and anything non-zero means true.

1.3 Arrays

Arrays in C++ are declared to hold a specific number of the same type of object. The valid indices are 0 up to 1 less than the size of the array. The execution does no checking for references going outside the bounds of the array. Arrays can be initialized at declaration.

CpSc2120 – Goddard – Notes Chapter 2

Basics of Classes

2.1 Objects

An object is a particular instance of a class and there may be multiple instances of a class. An object has

  • data, called attributes, fields or data members, and
  • functions, called methods or member functions.

A member function is called with the. notation. For example:

object.method();

The code

MyString puppet;

during compilation declares variable puppet to be an object of class MyString, and during execution causes the program to create the variable puppet by reserving memory for it and initializing it by executing the no-argument constructor. (See constructors below.)

2.2 Data Members and Member Functions

Every member function can access every data member. But, usually all data and some member functions are labeled private; user methods are labeled public. (There are other possibilities.) Private means that the external user of this class cannot see or use it. Member functions execute on an object of that class. Most classes have two types of member functions:

  • accessor functions: these allow the user to get data from the object.
  • mutator functions: these allow the user to set data in the object.

2.3 Constructors

A constructor is a special function that initializes the state of the object; it has the same name as the class, but does not have a return type. There can be more than one constructor. Note that the compiler will provide a default no-argument constructor if none is coded. Some constructor is always executed when an object is created.

2.4 Why Objects?

Object-oriented programming rests on the three basic principles of encapsulation:

  • Abstraction: ignore the details
  • Modularization: break into pieces
  • Information hiding : separate the implementation and the function

OOP uses the idea of classes. A class is a structure which houses data together with operations that act on that data. We strive for loose coupling : each class is largely independent and communicates with other classes via a small well-defined interface. We strive for cohesion: each class performs one and only one task (for readability, reuse). We strive for responsibility-driven design: each class should be responsible for its own data. You should ask yourself: What does the class need to know? What does it do? The power of OOP also comes from two further principles which we will discuss later:

  • Inheritance: classes inherit properties from other classes (which allows partial code reuse)
  • Polymorphism: there are multiple implementations of methods and the correct one is executed

Sample Code

Below is a sample class and a main function. But note that there are several style problems with it, some of which we will fix later. The output is

GI Joe can drink Barbie can’t drink

Citizen.cpp

Summary of C++ Data Structures

Wayne Goddard

School of Computing, Clemson University, 2018

Part 1: Fundamentals

4 More about Classes, Files and I/O.................... 6 5 Standard Class Methods.......................... 10 6 Algorithmic Analysis............................ 14 7 Recursion.................................. 17

CpSc2120 – Goddard – Notes Chapter 4

More about Classes, Files and I/O

4.1 Scope, Lifetime and Static

A variable has a scope (where it is accessible from) and a lifetime (when it exists). The variables defined in a function are called local variables and are accessible only within the function and exist only while the function is being executed. An exception is static variables whose lifetime is the program’s execution: they are always available, and there is only one copy per class. If public, a static variable can be accessed be using the scope resolution operator: prefixing it with the classname followed by ::. Note that global static variables are created before main is started.

4.2 Object Storage, Allocation and Destructors

Some objects are created and destroyed automatically : local variables in a function or block, member variables in a object, and temporary variables during expression evaluation. Some objects are created dynamically : this uses the new command and the result is usually assigned to a pointer. The user must deallocate these and release them to the system to avoid memory leaks. The delete command takes a pointer and recycles what the pointer points to. Note that an array that is new’ed needs to be deallocated with delete[]. A class should often have a destructor ; this has the name of the class preceded by a tilde, and is called to properly release memory. The destuctor method is not usually invoked by name, but is automatically called by the delete command. Note that, like constructors, if you do not provide code for a destructor the compile will create a primitive one. For example:

Tiger T; // user should not run delete on this Unicorn *U = new Unicorn( ); // dynamic allocation Vole *V = new Vole[10]; // create array of Voles; default constr. run on each ... delete U; // invokes destructor and releases space delete[] V; // invokes destructors on each Vole and space released

4.3 Passing an Object to a Function: Pointers and References

In C++ functions, you can pass parameters by value or by address/reference. Pass- by-value uses a separate copy of the variable; changing this copy does not affect the

One can indicate that an argument is not changed by a function, by putting a const before it:

void myMethod( const Foo & bar ) { ... }

One can indicate that the method does not change the object on which it is invoked by putting a const after the parameter list:

void myMethod( Foo & bar ) const { ... };

One can of course use both. The compiler will try to check that the claims are correct. But it cannot guarantee them, since one can create a pointer and get it to point to a variable.

4.7 Initializer Lists

When a constructor is called, any member data is initialized before any of the com- mands in the body of the constructor. In particular, any member that is a class has its constructor called automatically. (This occurs in the order that the member data is listed when defined.) So one should use specific initializers; this is a list after the header before the body.

class Foo { public: Foo( ) : Bar(1) , ging(’d’) // no-argument constructor { } private: Iso Bar; char ging; };

4.8 Libraries

Mathematical functions are available in the library cmath. Note that angles are repre- sented in radians. A namespace is a context for a set of identifiers. By writing std::string, we say to use the string from that namespace. A way to avoid writing the namespace every time is to use the using expression. But, the user can create a class with the same name as one in std, and then the compiler doesn’t know which to use.

4.9 More on Output

Including allows one to format stream output using what are called manip- ulators. For example, setw() sets the minimum size of the output field, setprecision() sets the precision, and fixed ensures that a fixed number of decimal places are displayed. For example

double A = 4.999; cout << setprecision(2) << showpoint; cout << A;

produces 5.0 as output.

4.10 File Input

File input can be made through use of an input file stream. This is opened with the external name of the file. There are cin-style operators: that is, stream >> A reads the variable A); note that the stream becomes null if the read fails. There are also functions taking the stream and a variable. The file should be closed after using. Here is sample code to copy a file to the standard output:

ifstream inFile; inFile.open( "testing.txt" ); if( !inFile ) cout << "Could not open file" << endl; else { string oneLine; while( inFile.peek() != EOF ) { getline(inFile, oneLine); cout << oneLine << endl; } inFile.close(); }

Sample Code

Consider a revision to our Citizen class. This is compiled by

g++ CitizenToo.cpp TestCitizenToo.cpp

CitizenToo.cpp CitizenToo.h TestCitizenToo.cpp

5.3 Inputting or Outputting a Class

Output of a class can be achieved by overloading the stream insertion operator <<. This is usually a separate global function (that is, not a member function). In order to access the private variables of your class, you usually need to make it a friend of your class (by adding its prototype inside the class).

class Foo { private: int bar1,bar2; friend ostream &operator<< (ostream &, const Foo &); };

ostream &operator<< (ostream &out, const Foo &myFoo) { out << myFoo.bar1 << ":" << myFoo.bar2 << endl; return out; }

Note that the arguments are passed by reference, and the stream itself is returned by reference (so that the operator works with successive <<). One can use the same approach to read an object from the user. Usually the user data is read into a string and then parsed internally. This is to handle malformed data without crashing.

5.4 Copying and Cloning

When a class is passed by value (into or out of a function), a copy is made using the copy constructor. Often the default compiler-inserted copy constructor is fine. This provides a shal- low copy —only the declared variables are copied. For example, if the class contains the header pointer to a linked list, the pointer will be copied, but both the header in the new object and the old object will point to the same Node in memory. This is usually not what you want. Instead a deep copy produces a completely separate object.

class Foo { private: Bar *barPtr; public: Foo( const Foo &other ) {

barPtr = new Bar( *(other.barPtr) ); } };

You should assume the deep copy is required unless otherwise specified. Note that the code A=B uses the assignment operator. There is a fundamental trio: either the default copy constuctor, assignment operator and destructor are all okay, or you need to provide all three.

We see how to create an assignment operator next.

5.5 Class Assignment

Suppose we have defined a class Foo. If we write:

Foo *bar1 = new Foo(); Foo *bar2 = bar1;

then the pointer bar2 points to the same instance of Foo that bar1 does. In particular, only one object exists. If we write: Foo bar1, bar2; // changes to the two objects bar2 = bar1;

then bar2 is now a copy of bar1. Unless you specify otherwise, this is done by the default assignment operator, which is a shallow copy —only the declared variables are copied. For example, if Foo contains a head pointer to a linked list, the pointer will be copied, but both the head in bar1 and the one in bar2 will point to the same Node in memory. This is usually not what you want. To create your own assignment operator, start with: Foo & operator= (const Foo &other) { // make copies of other’s members and assign them to this object return *this; }

The this pointer always refers to the object on which the member function is being invoked. (The function has to return the object, so that A=B=C works.) Now, one should first deallocate the old stuff in the object using the delete command. However, if the user writes bar=bar, assigning an object to itself, this can cause a problem. Thus, one adds a test to avoid any changes occurring in this case:

if( this != &other ) {

CpSc2120 – Goddard – Notes Chapter 6

Algorithmic Analysis

6.1 Algorithm Analysis

The goal of algorithmic analysis is to determine how the running time behaves as n gets large. The value n is usually the size of the structure or the number of elements it has. For example, traversing an array takes time proportional to n time. We want to measure either time or space requirements of an algorithm. Time is the number of atomic operations executed. We cannot count everything: we just want an estimate. So, depending on the situation, one might count: arithmetic oper- ations (usually assume addition and multiplication atomic, but not for large integer calculations); comparisons; procedure calls; or assignment statements. Ideally, pick one which simple to count but mirrors the true running time.

6.2 Order Notation

We define big-O:

f (n) is O(g(n)) if the growth of f (n) is at most the growth of g(n).

So 5n is O(n^2 ) but n^2 is not O(5n). Note that constants do not matter; saying f is O(

n) is the same thing as saying f is O(

22 n). The order (or growth rate) of a function is the simplest smallest function that it is O of. It ignores coefficients and everything except the dominant term.

Example. Some would say f (n) = 2n^2 + 3n + 1 is O(n^3 ) and O(n^2 ). But its order is n^2.

Terminology: The notation O(1) means constant-time. Linear means proportional to n. Quadratic means O(n^2 ). Sublinear means that the ratio f (n)/n tends to 0 as n → ∞ (somtimes written o(n)).

Long Arithmetic. Long addition of two n-digit numbers is linear. Long multiplication of two n-digit numbers is quadratic.

(Check!)

6.3 Combining Functions

  • Add. If T 1 (n) is O(f (n)) and T 2 (n) is O(g(n)), then T 1 (n) + T 2 (n) is max(O(f (n)), O(g(n))). That is, when you add, the larger order takes over.
  • Multiply. If T 1 (n) is O(f (n)) and T 2 (n) is O(g(n)), then T 1 (n) × T 2 (n) is O(f (n) × g(n)).

Example. (n^4 + n) × (3n^3 − 5) + 6n^6 has order n^7

6.4 Logarithms

The log base 2 of a number is how many times you need to multiply 2 together to get that number. That is, log n = L ⇐⇒ 2 L^ = n. Unless otherwise specified, computer science log is always base 2. So it gives the number of bits. The function log n grows forever, but it grows (much) slower than any power of n.

Example. Binary search takes O(log n) time.

6.5 Loops and Consecutiveness

  • Loop: How many times × average case of loop
  • Consecutive blocks: this is the sum and hence the maximum

Primality Testing. The algorithm is

for(int y=2; y<N; y++) if( N%y==0 ) return false; return true;

This takes O(

N ) time if the number is not prime, since then the small- est factor is at most

N. But if the number is prime, then it takes O(N ) time. And, if we write the input as a B-bit number, this is O(2B/^2 ) time. (Can one do better?)

Note that array access is assumed to take constant time.

CpSc2120 – Goddard – Notes Chapter 7

Recursion

Often in solving a problem one breaks up the problem into subtasks. Recursion can be used if one of the subtasks is a simpler version of the original problem.

7.1 An Example

Suppose we are trying to sort a list of numbers. We could first determine the minimum element; and what remains to be done is to sort the remaining numbers. So the code might look something like this:

void sort(Collection &C) { min = C.getMinimum(); cout << min; C.remove(min); sort(C); }

Every recursive method needs a stopping case: otherwise we have an infinite loop or an error. In this case, we have a problem when C is empty. So one always checks to see if the problem is simple enough to solve directly.

void sort(Collection &C) { if( C.isEmpty() ) return; ... // as before

Example. Printing out a decimal number. The idea is to extract one digit and then recursively print out the rest. It’s hard to get the most significant digit, but one can obtain the least significant digit (the “ones” column): use num % 10. And then num/ is the “rest” of the number.

void print( int n ) { if( n>0 ) { print ( n/10 ); cout << n%10 ; } }

7.2 Tracing Code

It is important to be able to trace recursive calls: step through what is happening in the execution. Consider the following code:

void g( int n ) { if( n==0 ) return; g(n-1); cout << n; }

It is not hard to see that, for example, g(3) prints out the numbers from 3 down to 1. But, you have to be a bit more careful. The recursive call occurs before the value 3 is printed out. This means that the output is from smallest to biggest.

1 2 3 Here is some more code to trace:

void f( int n ) { cout << n; if(n>1) f(n-1); if(n>2) f(n-2); }

If you call the method f(4), it prints out 4 and then calls f(3) and f(2) in succession. The call to f(3) calls both f(2) and f(1), and so on. One can draw a recursion tree: this looks like a family tree except that the children are the recursive calls.

f(1)

f(2) f(1) f(1)

f(3) f(2)

f(4)

Then one can work out that f(1) prints 1 , that f(2) prints 21 and f(3) prints 3211. What does f(4) print out?