CITB303 Структури от данни


Език за програмиране С++

Основни елементи на C++

Проста С++ програма

#include <stdlib>
#include <iostream>
int main()
{ int x, y;
  std::cout << "Please enter two numbers: ";
  std::cin >> x >> y; // input stream
  int sum = x + y;
  std::cout << "Their sum is " << sum << std::endl;
return EXIT_SUCCESS;
}

Highlighting the C++ Elements

-- оператор (statement) - 
-- операция (operator) - елемент на езика (+, =, ==)
-- операция (operation)  - като действие или състояние (събиране, присвояване, равно)

Основни типове

bool
char
short
int
long
float
double
enum
boolean
character
short integer
integer
long
integer
single-precision floating point
double-precision floating-point
enumeration
true, false
писмен знак, символ - 'A'
къс цял
цял
дълъг цял
единична точност плаваща запетая
двойна точност плаваща запетая
изброяване - множество от отделни стойности

bool, char, int и enum се наричат интегрални типове (integral types).
void показва липса на всякаква информация за типа (само за тип на функция).

Символи

char променливата съдържа един символ - обикновено 8 бита (bits) или 1 байт (byte).
Литерал (literal) е константна стойност в програма.
'a', 'Q', '+', '\n', '9' са литерали.
Всеки символ е свързан с цяло число, наречено ASCII код.
cout << 'a' << int('a') << static_cast<int>('a');

Цели числа

2 bytes <= sizeof(short) <= sizeof(int) <= sizeof(long) and
sizeof(long) >= 4 bytes

Изброен тип

Изброяване (enumeration) е дефиниран от потребителя тип, който съдържа отделни стойности.
enum Color { RED, GREEN, BLUE };  // default values are 0, 1, 2
enum Week { MONDAY = 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};
// values are 1, 2, 3, .., 7
enum Mood { HAPPY = 3, SAD = 1, ANXIOUS = 4, SLEEPY = 2 };
Color skyColor = BLUE;
Mood myMood = SLEEPY;
Week day = TUESDAY;

Плаваща запетая

-- double constants: 1.5402, 1.2E8, -2.25e-3, 1e5 (12-14 decimal digits)
-- float constants: 1.23f, 6f, 1.234F, 23e-2F (6-8 decimal digits)

Указатели (pointers), масиви (arrays) и структури (structures)

Указатели

Всяка променлива се съхранява в паметта на компютъра на някакво място, или адрес. A указателят съдържа стойността на такъв адрес.
Операция адрес (&) връща адреса на дадена променлива.
Достъп до обекта, адресиран от указателя се нарича стойност на указател (dereferencing), и се означава със  *.
char ch = 'Q';  
char* p = &ch; // p holds the address of ch
cout << *p; // outputs the character 'Q'
ch = 'Z'; // ch now holds 'Z'
cout << *p; // outputs the character 'Z'

Масиви

Масив е множество (редица) от елементи от едни и същи тип.
double f[3];    // array of 3 doubles f[0], f[1], f[2]
double* p[10]; // array of 10 double pointers p[0]..p[9]
f[2] = 2.5;
p[4] = &f[2]; // p[4] points to f[2]
cout << *p[4]; // outputs 2.5
int a[] = { 10, 11, 12, 13 }; // initialization
int b[20] = { 0 }; // initialize all elements with value 0
C++ не поддържа проверка за излизане на индексите извън границите на масива [common programming error]!

Указатели и масиви

Името на масива може да се използва като указател към първия елемент на масива и обратно.
char c[] = {'c', 'a', 't'};
char* p = c; // p points to c[0]
char* q = &c[0]; // q also points to c[0]
cout << c[2] << p[2] << q[2]; // outputs "ttt"
За двата масива c и d, сравнението c == d не проверява дали масивите са имат равни елементи!

Низове в С++

#include<string>;
using std::string;
//...
string s = "to be";
string t = "not " + s; // t := "not to be"
string u = s + " or " + t; // u := "to be or not to be"
if (s > t) cout u;
//...
s = "John";
int i = s.size(); // i = 4
char c = s[3]; // c = 'n'
s += " Smith"; // s = "John Smith"
char *p = s.c_str(); // p is a C-style string

C-структури

Структурата е полезна за съхраняване на съвкупност от елементи. Елементите (членове или полета) могат да бъдат от различни типове.

enum MealType { NO_PREF, REGULAR, LOW_FAT, VEGETARIAN };
struct Passenger {
string name; // "John Smith"
MealType mealPref; // LOW_FAT
bool isFreqFlyer; // true
string freqFlyerNo; // "293145"
};

Дефинира се нов тип Passenger. Достъп до член на структурата се дава с операция "точка": struct_variable.member.

	
Passenger pass = { "John Smith",
LOW_FAT, true, "293145" };
pass.name = "Pocahontas"; // change name
pass.mealPref = VEGETARIAN; // change meal preference

Това е C-структура. Като цяло, структури и класове в C++ предоставят много по-широка гама от възможности, отколкото това, което е възможно в C-структурите (член функции, контрол на достъпа и др.).

Указатели, динамична памет, операция new

C++ системата за изпълнение на задания (runtime system) запазва блок от паметта на компютъра, наречена динамична памет (free memory, dynamic memory or heap memory).
Операция new динамично разпределя точното количество памет за обект от даден тип и връща адреса на обекта.

Passenger *p;
//...
p = new Passenger; // p points the new Passenger
p->name = "Pocahontas"; // member selection(arrow) operator
p->mealPref = VEGETARIAN; // change meal preference
p->isFreqFlyer = false;
p->freqFlyerNo = "NONE";
//...
delete p;

Новият обект от тип  Passenger съществува в динамичната памет докато не бъде изтрит.

Memory Leaks

Ако обектът е създаден с операция new, то той трябва да се изтрие (да се освободи заеманата динамична памет) с delete.
char* buffer = new char[500];
//...
delete buffer; // ERROR: delete only the fist element buffer[0]
Оставяне на недостъпни обекти в динамичната памет се нарича "изтичане на памет" (memory leak).
char* buffer = new char[500];
//...
delete [] buffer; // delete all elements

Обхват (scope) и пространства от имена (namespaces)

Константи и typedef

const double PI = 3.14159265;
const int CUT_OFF[] = {90, 80, 70, 60}
;
const int N_DAYS = 7;
const int N_HOURS = 24*N_DAYS;
int counter[N_HOURS];
Често е полезно да се асоциира ново име с някой (обикновено съставен) тип:
typedef char* BufferPtr;   // type BufferPtr is a pointer to char
typedef double Coordinate
; // type Coordinate is a double
//...
BufferPtr p; // p is a pointer to a char
Coordinate x, y; // x and y are of type double

Локален и глобален обхват (видимост)

Частта от програмата, където дадено име е достъпно се наричат ​​негов обхват (scope).
const int cat = 1;      // global cat
int main()

{
const int
cat = 2; // local cat (to main)
cout << cat; // outputs 2
return 0;
}
int dog = cat; // dog = 1 (from global cat)

Namespaces

Именното пространство е механизъм, който позволява на група от свързани имена да бъдат дефинирани на едно място.
namespace myglobals {
int cat;

string dog = "bow wow";
}

int d = myglobals::cat;
  Достъп до обект x в именното пространство group дава операция "принадлежност" :: (scope):  group::x.
namespace.cpp

  Оператор using

using std::cout;
using myglobals::cat;
или
using namespace std;
using namespace myglobals;

Изрази

Изразът съчетава променливи и литерали с операции за създаване на нови стойности.

Избиране на член (member selection) и индекс

Нека:
Операции (lvalue):
class_name.member class/structure member selection
dot (member selection) operator операция "точка"
pointer->member
class/structure member selection arrow operator
операция "стрелка"
array[exp]
array subscripting
index (subscript) operator
операция "индекс"

Аритметични операции

Бинарни аритметични операции (rvalue):
exp + exp
addition
събиране
exp - exp subtraction
изваждане
exp * exp multiplication
умножение
exp / exp division
деление
exp % exp modulo (remainder)
остатък

Унарни операции: +x и -x.

Операции увеличаване (increment) и намаляване (decrement)

var++
post increment
var--
post decrement
++var pre increment
--var pre decrement

int a[] = { 0, 1, 2, 3 };
int i = 2;
int j = i++; // j = 2 and then i = 3
int k = --i; // i = 2 and then k = 2
cout << a[k++]; // a[2] (=2) is output; then k = 3

Релационни и логически операции

Операции за сравнение:
exp < exp
less than
по-малко
exp > exp greater than
по-голямо
exp <= exp less than or equal to
по-малко или равно
exp >= exp greater than or equal to по-голямо или равно
exp == exp equal to
равно
exp != exp not equal to
неравно
Стойности на тези операции са логическите стойности - true и false.

Логически операции:
! exp
logical not логическо "не"
exp && exp logical and логическо "и"
exp || exp logical or логическо "или"
exp може да бъде логически или аритметичен израз (0 означава false, ненула означава true).

Побитови операции:

~exp
bitwise complement, ex.
~100010 -> 011101 побитово отрицание
exp & exp bitwise and (conjunction), ex.
1001 & 1100 -> 1000 побитово "и"
exp ^ exp bitwise exclusive-or
1001 ^ 1100 -> 0101
побитово изключващо "или"
exp | exp bitwise or (disjunction)
1001 | 1100 -> 1101
побитово "или"
exp << exp shift left 11001 << 1  -> 10010
преместване наляво
exp >> exp shift right
11001 >> 1 -> 01100
преместване надясно

Операции за присвояване

Аритметичните операции (+, -, *,  /, % ) и побитовите бинарни операции (&, ^, |, <<, >>) се комбинират с оператора за присвояване =.

int i = 10; 
int j = 5;
int k = 1;
i -= 4; // i = i - 4; result 6

j *= -2; // j = j * (-2); result -10
k <<= 1; // k = k << 1; result 2

Други операции

class_name :: member
class scope resolution
принадлежност към клас
namespace_name :: member namespace scope resolution принадлежност към именно пространство
exp ? exp : exp
conditional expression
условна операция
stream >> var
input stream (overloaded)
входен поток
stream << exp
output stream (overloaded)
изходен поток

Приоритет на операциите

Операциите в C + + имат приоритет, който определя реда, по който операциите се извършват при липса на скоби.
Operator Description Associativity
:: scope Left
() [ ] -> . sizeof   Left
++ -- increment, decrement Right
~ bitwise complement
! (not)
unary NOT
& * reference and dereference
..._cast, (type)
type casting
+ - unary + and -
* / % arithmetic operators Left
+ - addition, subtraction Left
<< >> bitwise shifts
Left
< <= > >= relational operators Left
== != relational operators Left
&
bitwise and
Left
^ bitwise exclusive-or Left
| bitwise or
Left
&& (and)
logical operator and
Left
|| (or)
logical operator or
Left
?: conditional operator
Left
= += -= *= /= %=
>>= <<= &= ^= |=
assignment operators
Right
, comma, separator Left

int a = 10, b, c, d;  
// right associativity
d = c = b = a; // is equivalent to d = (c = (b = a));
// left associativity
d - c + b - a; // is equivalent to ((d - c) + b) - a;
// precedence
d > c && -b <= a // is equivalent to (d > c) && ((-b) <= a)

Casting in Expressions (преобразуване на типове данни)

Casting е операция, която променя типа на променливата.

Традиционен C-casting

int cat = 14;  
double dog = (double)cat;
double pig = double(cat);

C++ casting операции

Casting операцията може да варира от безвредни до опасна в зависимост от това колко са подобни двата вида са и дали се губи информация.

Стандартът на C++ поддържа 4 casting операции:

като се използва означението: some_cast<T>(exp).

Статично (Static Casting)

static_cast<T>(exp)

int cat = 14;  
double dog = static_cast<double>(cat); // dog := 14.0
double lion = 155.99;
int pig = static_cast<int>(lion); // pig := 155

Неявно (Implicit Casting)

Има много случаи, когато програмистът не е задал изрично casting, но промяната на типа е задължително. В много от тези случаи, C++ ще изпълни неявно промяна на типa (casting). Това означава, че компилаторът автоматично ще вмъкне в програмата генериран код за смяна на типа към по-общия тип (без загуба на информация).
char - short - int - long -? float - double

implicit_cast.cpp


Управляващи оператори

if (<condition>) <operator>;
if (<condition>) <operator1>; else <operator2>;
while(<condition>) <opetator>;
do <operator>; while(<condition>);
for ([<initialization>]; [<condition>]; [<increment>]) <operator>;
for ([<expression1>]; [<expression2>]; [<expression3>]) <operator>;
return [<expression>];


Функции

Предаване на параметри

Предефиниране (overloading)

Предефиниране на функции

Предефиниране на функции имаме, когато две или повече функции са дефинирани със същото име, но различни списъци от параметри.
void print(int x)
{ cout << x; }
	
void
print(const Passenger &pass)
{
cout << pass.name << " " << pass.mealPref;
if (pass.isFreqFlyer) cout << pass.freqFlyerNo;
}

Предефиниране на операции
Тест за равенство за два Passenger обекти:
bool operator==(const Passenger &x, const Passenger &y)
{
return x.name == y.name &&
x.mealPref == y.mealPref &&
x.isFreqFlyer == y.isFreqFlyer &&
x.freqFlyerNo == y.freqFlyerNo;
}


Използване на предефинирането
	
ostream& operator<<(ostream &out, const Passenger &pass)
{
out << pass.name << " "
<< pass.mealPref;
if (pass.isFreqFlyer) out << pass.freqFlyerNo;

return out;
}
//...
Passenger pass1 = // details omitted
Passenger pass2 = // details omitted
cout << pass1 << pass2 << endl;


Класове

Структура на класа

Класът се състои от членове. Членове, които са променливи или константи са данни (член-променливи) и членове, които са ​​функции се наричат член-функции (методи).

Достъп

Членовете могат да бъдат обявени за публични (public) и те са достъпни за функции извън класа или частни (private), които са достъпни само за функциите от този клас. По подразбиране всички членове са частни.

Член-функции

enum MealType { NO_PREF, REGULAR, LOW_FAT, VEGETARIAN };
class Passenger {
private:
string name; // "John Smith"
MealType mealPref; // LOW_FAT
bool isFreqFlyer; // true
string freqFlyerNo; // "293145"
public:
Passenger(); // default constructor
bool isFreqFlyer() const; // accessor function
void makeFreqFlyer(const string &newFreqFlyerNo);
// update (mutator) function
};
// ...
bool Passenger::isFreqFlyer() const
{
return
isFreqFlyer;
}
void Passenger::makeFreqFlyer(const string &newFreqFlyerNo)
{
isFreqFlyer = true;
freqFlyerNo = newFreqFlyerNo;
}
//...
Passenger pass;
//...
if (!pass.isFreqFlyer()) // OK
pass.makeFreqFlyer("999999"); // OK
pass.name = "Joe Blow"; // ERROR: private member

Дефиниции на функции в класа (in-class)

	enum MealType { NO_PREF, REGULAR, LOW_FAT, VEGETARIAN };
class Passenger {
private:
string name; // "John Smith"
MealType mealPref; // LOW_FAT
bool isFreqFlyer; // true
string freqFlyerNo; // "293145"
public:
Passenger();
bool isFreqFlyer() const
{ return isFreqFlyer; }  
void makeFreqFlyer(const string &newFreqFlyerNo)
{
isFreqFlyer = true;
freqFlyerNo = newFreqFlyerNo;
}
};

Конструктори и деструктори

Класове и резервиране на памет

Приятелски класове

class Matrix;              // Matrix definition comes later
class Vector {             // a 3-element vector
private:
  double coord[3];
public:
  // ...
  friend class Matrix;     // allow Matrix access to coord
};
class Matrix {             // a 3x3 array
private:
  double a[3][3];
public:
  // ...
  Vector multiplyBy(const Vector& v) {  // multiply (a * v)
    Vector w(0, 0, 0);
    for (int i = 0; i < 3; i++)
      for (int j = 0; j < 3; j++)
        w.coord[i] += a[i][j] * v.coord[j]; // access private data
    return w;
  }
};

Вложени класове

Класовете може да съдържат променливи, член-функции и типове. Може да се влагат и дефиниции други класове.
class Complex {
private:
class Node {
// ...
};
//...
};

Стандартна библиотека с шаблони (STL)

Шаблони и STL класа vector

Стандартната библиотека с шаблони (Standard Template Library - STL) е колекция от полезни класове за общи структури от данни.
Стандартни контейнери:
stack
Container with last-in, first-out access
стек
Контейнер с достъп LIFO
queue
Container with first-in, first-out access опашка
Контейнер с достъп FIFO
deque
Double-ended queue
дек
Опашка с два края
vector
Resizeable array
вектор
Масив с променлива дължина
list
Doubly linked list

Двусвързан списък
priority_queue
Queue ordered by value

Приоритетна опашка
set, multiset
Set
множество

map, multimap
Associative array (dictionary)

Асоциативен масив (речник)

  Всеки STL-клас може да съдържа обекти от произволен тип.
vector<int> scores(100);  
vector<char> buffer(500);
vector<Passenger> passList(20);
vector<int> newScores = scores;
vector.cpp