Website Summary Files Commits Branches @commit @diff @stats
diff options
context:
space:
mode:
Commit1d811a4c898d93ff33725254c0efaa89f3fd2dd1 (patch)
Author
 Stoycho Kyosev <stoycho.kk@gmail.com>
2022-11-02 22:20:56 +0200
Committer
 Stoycho Kyosev <stoycho.kk@gmail.com>
2022-11-02 22:20:56 +0200
Files085af57b363043fef9b4620bc50c3a0e516fe128
Data-structures-and-algorithms-1d811a4c898d93ff33725254c0efaa89f3fd2dd1.tar
Data-structures-and-algorithms-1d811a4c898d93ff33725254c0efaa89f3fd2dd1.tar.gz
Data-structures-and-algorithms-1d811a4c898d93ff33725254c0efaa89f3fd2dd1.zip
Parentbc6c369184d433bc03768782b372552d18a530e5 (diff)
fix typos
1 files changed, 19 insertions, 14 deletions
-rw-r--r--Seminar05/README.md33
diff --git a/Seminar05/README.md b/Seminar05/README.md
index 7d2edaf..ce729b4 100644
--- a/Seminar05/README.md
+++ b/Seminar05/README.md
@@ -1,8 +1,8 @@
# Свързани списъци втора част
## Малко за представянията
-Миналия семинар работихме с един класически начин да представим свързан списък, а именно просто чрез указател към първия му елемент. Днес ще разгледаме представянето на свързания списък като клас.
-Разбира се, какво може да е толкова трудното на това да представим свързания списък като клас? Вместо функция *freeLinkedList* ще имаме деструктор, всички нужни функции ще ги направим като член-функции на новосъздадения ни клас и готово.
+Миналия семинар работихме с един класически начин за представяне на свързан списък, а именно просто чрез указател към първия му елемент. Днес ще разгледаме представянето на свързания списък като клас.
+Разбира се, какво може да е толкова трудното на това да представим свързания списък като клас? Правим подходящи конструктори, вместо функция *freeLinkedList* ще имаме деструктор, всички нужни функции ще ги направим като член-функции на новосъздадения ни клас и готово.
Проблемът тук е, че доста често ни се налага да обхождаме списъка. Когато го представяхме чрез указател към първия му елемент нещата бяха лесни:
```cpp
@@ -21,13 +21,13 @@ LinkedListNode* getHead();
## Итератори
Тук на помощ идват итераторите. Итераторите са обекти, които са отговорни за обхождане на контейнери (динамичен масив, свързан списък и тн). В *C++* голяма част от STL използва итератори за постигане на целите си.
-Примерната реализация, с която ще работим, се намира във файла LinkedList.hpp. Представяме свързания списък с два указателя където
+Примерната реализация, с която ще работим, се намира във файла LinkedList.hpp. Представяме свързания списък с два указателя, където
* head сочи към първия (най-левия) елемент
* tail сочи към последния (най-десния) елемент
-* Също така пазим още една допълнителна променлива от тип size_t за да пазим дължината на списъка.
+* Също така пазим още една допълнителна променлива от тип size_t за дължината на списъка.
Разгледайте реализацията, особено алгоритмите за добавяне и премахване в началото и в края. Забележете, че всеки път разглеждаме три случая:
* Дали листа е празен
@@ -35,7 +35,7 @@ LinkedListNode* getHead();
* Дали листа има повече от един елемент
Вече имаме някаква примерна реализация на свързан списък. Хайде да си направим итератор и да видим колко точно сложно ще е.
-Ще направим итератора **вътрешен клас за класът LinkedList**, който ще е **публичен**.
+Ще направим итератора **вътрешен и публичен клас за класа LinkedList**.
```cpp
// ...
public:
@@ -74,7 +74,7 @@ Iterator& operator++() {
return *this;
}
```
-Супер, вече имаме ++it. Но ще е добре и да си направим it++, не знаем за какво ще ни потрябва.
+Супер, вече имаме ++it. Но ще е добре и да си направим it++, не знаем за какво ще ни потрябва.
```cpp
// Защо този път връщаме Iterator а не Iterator&?
@@ -88,7 +88,6 @@ Iterator operator++(int) {
```
Напомняме, че разликата между префиксния и постфиксния operator++ е просто един "служебен" int като аргумент на постфиксния.
-
Супер, вече можем да се движим, но това движение става безполезно ако нямаме начин да видим каква информация имаме в currentNode. Тази задача по конвенция се изпълнява от operator*. Супер, нека го предефинираме:
```cpp
T& operator*() {
@@ -127,7 +126,7 @@ bool operator!=(const Iterator& other) const {
friend class LinkedList;
/// ...
```
-Вече сме готови да проверим дали нашия метод работи.
+Вече сме готови. Нека да проверим дали нашия метод работи:
```cpp
int main() {
LinkedList<int> ll;
@@ -139,8 +138,9 @@ int main() {
std::cout << *it << " ";
}
```
+
## Const и итераторите
-нека разгледаме следния код
+Нека разгледаме следния код:
```cpp
int main() {
const LinkedList<int> ll;
@@ -170,9 +170,9 @@ int main() {
std::cout << ll.back();
}
```
-В случая, въпреки че ll е const с отново променяме стойността му.
+В случая, въпреки че ll е const, отново променяме стойността му. Но защо?
-В случая beg е константен. Той е съставен от един пойнтър, който обаче не е константен. В някакъв смисъл това, че стойността на паметта към която сочи пойнтъра се променя не чупи константността на итератора. За това ще се наложи да дефинираме още един клас, ConstIterator!
+В случая **beg е константен**. Той е съставен от един пойнтър, който обаче **не е константен**. В някакъв смисъл **това, че стойността на паметта към която сочи пойнтъра се променя не чупи константността на итератора**. За това ще се наложи да дефинираме още един клас, ConstIterator!
```cpp
class ConstIterator {
private:
@@ -215,15 +215,18 @@ class ConstIterator {
Реализираме следните:
```cpp
+// Връща константен итератор към началото
ConstIterator cbegin() const {
return ConstIterator(head);
}
+// Връща константен итератор към края
ConstIterator cend() const {
return ConstIterator(nullptr);
}
```
-Сега ако искам да имам итератор за константен списък просто ще създавам ConstIterator. Примерно, искаме да итерираме константен свързан списък:
+Сега, ако искам да имам итератор за константен списък, просто ще създавам ConstIterator. Примерно, искаме да итерираме константен свързан списък:
+
```cpp
void iterate(const LinkedList<int>& ll){
for(LinkedList<int>::ConstIterator it = ll.cbegin(); it != ll.cend(); ++it) {
@@ -233,14 +236,15 @@ void iterate(const LinkedList<int>& ll){
```
## auto
-Най - вероятно вече сте чували за ключовата дума *auto*. Чрез нея карате компилатора сам да прецени какъв тип да използва за променливата. Тя е удобна когато имате дълги типове. Прави кодът по - четим и разбираем. Но като всяко хубаво нещо **с auto не е добре да се прекалява.**
+Най - вероятно вече сте чували за ключовата дума *auto*. Чрез нея карате компилатора сам да прецени какъв тип да използва за променливата. Тя е удобна когато имате дълги типове. Прави кодът по-четим и разбираем. Като всяко хубаво нещо обаче **с auto не е добре да се прекалява.**
```cpp
+// Автоматично разбирам типа на it
for(auto it = ll.begin(); it != ll.end(); ++it) {
//...
}
-auto x = 5; // х е променлива от тип int
+auto x = 5; // х е променлива от тип int
const auto y = 10u; // y e променлива от тип const unsigned
auto f = 10.0f; // f е променлива от тип float
const auto& r = f; // r е променлива от тип const float&
@@ -251,6 +255,7 @@ auto it = ll.begin(); // it e променлива от тип std::list<int>::i
const auto its = ll.end(); // it е променлива от тип ?
auto itss = ll.cend(); // it е променлива от тип ?
```
+
## range based for loops
От c++11 езикът ни предлага начин, чрез който да пишем подобни for цикли още по - бързо.
```cpp