-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcormenalgo.h
More file actions
2221 lines (2082 loc) · 59.9 KB
/
cormenalgo.h
File metadata and controls
2221 lines (2082 loc) · 59.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef CORMEN_ALGORITHM
#define CORMEN_ALGORITHM
#include <cmath>
#include <iostream>
#include <ostream>
#include <vector>
#include <list>
#include <stack>
using namespace std;
using std::vector;
namespace cormen {
template <typename T, typename Comparable>
void insertion_sort(vector<T>& data, Comparable comp) {
auto len = data.size();
auto j = 0;
auto key = T();
for (auto i = 1; i < len; ++i) {
j = i - 1;
key = data[i];
while (j >= 0 && comp(data[j], key)) {
data[j + 1] = data[j];
--j;
}
data[j + 1] = key;
}
}
template <typename T> void insertion_sort(vector<T>& data) {
auto len = data.size();
auto j = 0;
auto key = T();
for (auto i = 1; i < len; ++i) {
j = i - 1;
key = data[i];
while (j >= 0 && data[j] > key) {
data[j + 1] = data[j];
--j;
}
data[j + 1] = key;
}
}
template <typename T> class linked_list;
template <typename T> class node {
public:
node() = default;
explicit node(T it) : item(std::move(it)), next(nullptr) {}
private:
T item;
node<T>* next;
friend class linked_list<T>;
};
template <typename T> class linked_list {
public:
linked_list();
~linked_list();
[[nodiscard]] constexpr bool empty() const;
[[nodiscard]] constexpr T& front() const;
[[nodiscard]] const T& back() const;
void push_back(const T& item);
void push_front(const T& item);
void pop_front();
void clear();
void print();
[[nodiscard]] size_t size() const;
private:
node<T>* head;
size_t sz = 0;
node<T>* get_tail();
};
template <typename T> linked_list<T>::linked_list() : head(nullptr) {}
template <typename T> linked_list<T>::~linked_list() {
while (!empty())
pop_front();
}
template <typename T> constexpr bool linked_list<T>::empty() const {
return head == nullptr;
}
template <typename T> constexpr T& linked_list<T>::front() const {
return head->item;
}
template <typename T> const T& linked_list<T>::back() const {
auto temp = head;
while (temp->next)
temp = temp->next;
return temp->item;
}
template <typename T> void linked_list<T>::push_back(const T& item) {
auto new_item = new node<T>(item);
auto tail = get_tail();
if (!tail)
push_front(item);
else {
tail->next = new_item;
++sz;
}
}
template <typename T> void linked_list<T>::push_front(const T& item) {
auto temp = new node<T>;
temp->item = item;
temp->next = head;
head = temp;
++sz;
}
template <typename T> void linked_list<T>::pop_front() {
if (!head)
throw std::out_of_range("linked_list is empty before pop_front");
auto old = head;
head = old->next;
--sz;
delete old;
}
template <typename T> void linked_list<T>::clear() {
while (!empty())
pop_front();
sz = 0;
}
template <typename T> void linked_list<T>::print() {
auto temp = head;
while (temp) {
cout << temp->item << " ";
temp = temp->next;
}
}
template <typename T> size_t linked_list<T>::size() const { return sz; }
template <typename T> node<T>* linked_list<T>::get_tail() {
if (!head)
return nullptr;
auto temp = head;
while (temp->next)
temp = temp->next;
return temp;
}
template <typename T> class d_linked_list;
template <typename T> class d_node {
public:
explicit d_node(const T& d = T{}, d_node<T>* p = nullptr,
d_node<T>* n = nullptr)
: item(d), prev(p), next(n) {}
// for debugging purposes
const T& get_item() const { return item; }
const d_node<T>* get_prev() const { return prev; }
const d_node<T>* get_next() const { return next; }
private:
T item;
d_node<T>* prev;
d_node<T>* next;
friend class d_linked_list<T>;
};
template <typename T> class d_linked_list {
public:
d_linked_list();
~d_linked_list();
bool empty() const;
const T& front() const;
const T& back() const;
void push_front(const T&) noexcept;
void push_back(const T&) noexcept;
void pop_back();
void pop_front();
size_t size() const;
const d_node<T>* get_head() const { return head; }
const d_node<T>* get_tail() const { return tail; }
private:
d_node<T>* head;
d_node<T>* tail;
size_t sz = 0;
protected:
void add(d_node<T>* pos, const T& val);
void remove(d_node<T>* pos);
};
// ctor for doubly linked list, head and tail is sentinel node for quick access
template <typename T> d_linked_list<T>::d_linked_list() {
head = new d_node<T>(); // create a sentinel, this is must be not null
tail = new d_node<T>(); // but it's only dummy node
head->next = tail;
tail->prev = head;
}
// dtor of the doubly linked list, destroy all only if the list is not empty
template <typename T> d_linked_list<T>::~d_linked_list() {
while (!empty())
pop_front(); // clear all node
delete head; // clear the sentinel node
delete tail;
}
// empty: checking the current list if contain any element except on head and
// tail
template <typename T> bool d_linked_list<T>::empty() const {
return (head->next == tail);
}
// front: get the first element from doubly linked list
template <typename T> const T& d_linked_list<T>::front() const {
if (empty())
throw std::out_of_range("call front on empty list");
return head->next->item;
}
// back: get the last element from doubly linked list
template <typename T> const T& d_linked_list<T>::back() const {
if (empty())
throw std::out_of_range("call back on empty list");
return tail->prev->item;
}
// push_front: adding new element on the front of the list
template <typename T> void d_linked_list<T>::push_front(const T& val) noexcept {
add(head->next, val);
++sz;
}
// push_back: adding new element on the back of the list
template <typename T> void d_linked_list<T>::push_back(const T& val) noexcept {
add(tail, val);
++sz;
}
// pop_back: removing the element from the bottom of the list
template <typename T> void d_linked_list<T>::pop_back() {
if (empty())
throw std::out_of_range("call pop_back on empty list");
remove(tail->prev);
--sz;
}
// pop_front: removing the element from the top of the list
template <typename T> void d_linked_list<T>::pop_front() {
if (empty())
throw std::out_of_range("call pop_front on empty list");
remove(head->next);
--sz;
}
// size: total element on doubly linked list, except head and tail element
template <typename T> size_t d_linked_list<T>::size() const { return sz; }
// add: protected member of the doubly linked list class, adding item before pos
template <typename T> void d_linked_list<T>::add(d_node<T>* pos, const T& val) {
auto new_item = new d_node<T>(val);
new_item->next = pos; // link new_item in between pos
new_item->prev = pos->prev; // and pos->prev
pos->prev->next = new_item; // update the next pointer of the node at the
// position where new_item is inserted
pos->prev = new_item; // update the prev pointer of the node at the
// position where new_item is inserted
}
// remove: removing node pos from list, u: predecessor, w: successor
template <typename T> void d_linked_list<T>::remove(d_node<T>* pos) {
auto u = pos->prev; // remove pos from list
auto w = pos->next; // [u -> pos ->w]
u->next = w;
w->prev = u;
delete pos;
}
template <typename T>
void merge(std::vector<T>& ls, const int& beg, const int& mid, const int& end) {
vector<T> temp;
for (auto k = beg; k <= end; ++k) // copy ls[low...hi] to temp
temp.push_back(ls[k]);
// merge the element in sorted order
auto i = beg;
auto j = mid + 1;
for (auto k = beg; k <= end; ++k) {
if (i > mid)
ls[k] = temp[j++ - beg];
else if (j > end)
ls[k] = temp[i++ - beg];
else if (temp[j - beg] < temp[i - beg])
ls[k] = temp[j++ - beg];
else
ls[k] = temp[i++ - beg];
}
}
template <typename T>
void merge_sort(vector<T>& ls, const int& beg, const int& end) {
if (end <= beg)
return;
int mid = beg + (end - beg) / 2;
merge_sort(ls, beg, mid);
merge_sort(ls, mid + 1, end);
merge(ls, beg, mid, end);
}
// merge sort with lambada params, custom comparable, default is less than
template <typename T, typename Comparable>
void merge(std::vector<T>& ls, const int& beg, const int& mid, const int& end,
Comparable comp) {
std::vector<T> temp;
for (auto k = beg; k <= end; ++k)
temp.push_back(ls[k]);
auto i = beg;
auto j = mid + 1;
for (auto k = beg; k <= end; ++k) {
if (i > mid) // control the half left
ls[k] = temp[j++ - beg];
else if (j > end) // control the left right
ls[k] = temp[i++ - beg];
else if (comp(temp[j - beg],
temp[i - beg])) // compare half right with half left
ls[k] = temp[j++ - beg];
else
ls[k] = temp[i++ - beg];
}
}
template <typename T, typename Comparable>
void merge_sort(vector<T>& ls, const int& beg, const int& end,
Comparable comp) {
if (end <= beg)
return;
int mid = beg + (end - beg) / 2;
merge_sort(ls, beg, mid, comp);
merge_sort(ls, mid + 1, end, comp);
merge(ls, beg, mid, end, comp);
}
template <typename T> class circle_list;
template <typename T> class node_circle {
public:
node_circle(const T& value) : item{ value }, next{ nullptr } {}
~node_circle() { next = nullptr; }
const T& get_item() const { return item; }
private:
T item;
node_circle* next;
friend class circle_list<T>;
};
template <typename T> class circle_list {
public:
circle_list() : cursor{ nullptr } {}
~circle_list() {
while (!empty())
remove();
}
bool empty() const;
const T& front() const; // element following cursor, if not advance,
// the front is the last inserted element
const T& back() const; // element at the cursor, conversly to front behavior
void advance(); // advance cursor
void add(const T&); // add item after cursor, if current [a,b], add 'c'
// will make the list [c,a,b], this maintain the circular behavior
void remove(); // remove node after cursor
private:
node_circle<T>* cursor;
};
template <typename T> void circle_list<T>::remove() {
if (empty())
throw std::out_of_range("calling remove() on empty circle_list");
auto old = cursor->next;
if (old == cursor)
cursor = nullptr;
else
cursor->next = old->next;
delete old;
}
template <typename T> bool circle_list<T>::empty() const {
return cursor == nullptr;
}
template <typename T> const T& circle_list<T>::back() const {
if (empty())
throw std::out_of_range("calling back() on empty circle_list");
return cursor->item;
}
template <typename T> const T& circle_list<T>::front() const {
if (empty())
throw std::out_of_range("calling front() on empty circle_list");
return cursor->next->item;
}
template <typename T> void circle_list<T>::advance() { cursor = cursor->next; }
template <typename T> void circle_list<T>::add(const T& item) {
auto new_node = new node_circle<T>(item);
if (empty()) {
new_node->next = new_node; // since we deal with circular list
cursor = new_node; // cursor point to new_node
}
else {
new_node->next = cursor->next; // link in v after cursor
cursor->next = new_node; // cursor next point to newly added node
}
}
template <typename T> void rdoubly_linked_list(d_linked_list<T>& ls) {
d_linked_list<T> temp;
while (!ls.empty()) { // copying the original ls to temp
const auto item = ls.front();
ls.pop_front();
temp.push_front(item);
}
while (!temp.empty()) {
const auto item = temp.front();
temp.pop_front();
ls.push_back(item);
}
}
// recursive example by drawing a ruler
void draw_one_tick(const size_t& tick_len, const int& tick_lbl = -1) {
for (auto i = 0; i < tick_len; ++i)
std::cout << "-";
if (tick_lbl >= 0)
std::cout << " " << tick_lbl;
std::cout << std::endl;
}
void draw_ticks(const size_t& tick_len) { // draw tick of given length
if (tick_len > 0) { // stop when length drop to 0
draw_ticks(tick_len - 1); // recursively draw left ticks
draw_one_tick(tick_len); // draw center tick
draw_ticks(tick_len - 1); // recursively draw right ticks
}
}
void draw_ruler(const size_t& ninches, const size_t& major_len) {
draw_one_tick(major_len, 0); // draw tick 0 and it's label
for (auto i = 1; i <= ninches; ++i) {
draw_ticks(major_len - 1); // draw ticks for this inch
draw_one_tick(major_len, i); // draw tick i and its label
}
}
// recusively sum of all element on a vector, with linear running time
template <typename Number>
Number recursive_sum(const vector<Number>& ls, const size_t& ls_len) {
if (ls.empty())
throw std::out_of_range("calling recursive_sum() on empty container");
if (ls_len == 1) // base case
return ls[0];
return recursive_sum(ls, ls_len - 1) + ls[ls_len - 1]; // recursive case
}
// reversing element on array by linear recursion
template <typename T>
void reverse_array(vector<T>& ls, const size_t& beg = 0,
const size_t& end = 0) {
if (ls.empty())
throw std::out_of_range("calling reverse_array() on empty container");
if (beg < end) {
std::swap(ls[beg], ls[end]);
reverse_array(ls, beg + 1, end - 1);
}
return; // dealing with size of ls is odd, beg==end
}
// binary_sum: performing binary recursion by summing all element on container
template <typename Number>
Number binary_sum(const vector<Number>& ls, const size_t& beg = 0,
const size_t& last = 0) {
if (last == 1)
return ls[beg];
return binary_sum(ls, beg, floor(last / 2.0)) +
binary_sum(ls, beg + floor(last / 2.0), ceil(last / 2.0));
}
// binary_fib: performing binary recursion by calculate fibonacci number
size_t binary_fib(const size_t& n) {
if (n <= 1)
return n; // base case
return binary_fib(n - 1) + binary_fib(n - 2); // since F_i = f_i-1+ f_i-2
}
// linear_fib: performing linear recursion by calculate fibonacci number
// return a pair of fibonacci number of n, and n-1
std::pair<size_t, size_t> linear_fib(const size_t& n) {
std::pair<size_t, size_t> result = { 0, 0 };
if (n <= 1)
return std::make_pair(n, 0);
else {
result = linear_fib(n - 1);
return { result.first + result.second, result.first };
}
}
// prefix_averages(): demonstrate the running time O(n^2) by computing prefix
// avg
template <typename Number>
std::vector<double> prefix_averages(const std::vector<Number>& ls) {
std::vector<double> result;
for (auto i = 0; i <= ls.size() - 1; ++i) {
auto temp = 0.0;
for (auto j = 0; j <= i; ++j) // 1 + 2 + 3 + .... + n = (n(n+1))/2
temp += ls[j];
result.push_back(temp / (i + 1));
}
return result;
}
// prefix_averages_lin(): demonstrate the running time O(n) by computing prefix
// avg
template <typename Number>
std::vector<double> prefix_averages_lin(const vector<Number>& ls) {
auto temp = 0.0;
vector<double> result;
for (auto i = 0; i < ls.size(); ++i) {
temp += ls[i]; // remember the last sum, this and the next line O(n)
result.push_back(temp / (i + 1));
}
return result;
}
// power_linear(): demonstrate the running time O(n) by computing power of x by
// n
template <typename Number>
Number power_linear(const Number& x, const size_t& n) {
if (n == 0)
return 1;
return x * power_linear(x, n - 1);
}
// power_logarithm(): demonstrate the running time O(log n) by computing power
// of x by n
template <typename Number>
Number power_logarithm(const Number& x, const size_t& n) {
if (n == 0)
return 1;
if (n % 2 != 0) {
auto y = power_logarithm(x, (n - 1) / 2);
return x * y * y;
}
else {
auto y = power_logarithm(x, n / 2);
return y * y;
}
}
template <typename T> class stack_array {
enum { INITIAL_CAPACITY = 100 };
public:
stack_array(const size_t& cap = INITIAL_CAPACITY);
size_t size() const;
bool empty() const;
const T& top() const;
void push(const T&);
void pop();
private:
T* s;
size_t capacity;
int pos;
};
template <typename T>
stack_array<T>::stack_array(const size_t& cap)
: s(new T[cap]), capacity{ cap }, pos{ -1 } {}
template <typename T> size_t stack_array<T>::size() const { return pos + 1; }
template <typename T> bool stack_array<T>::empty() const { return pos < 0; }
template <typename T> const T& stack_array<T>::top() const {
if (empty())
throw std::out_of_range("calling top() on empty stack array based");
return s[pos];
}
template <typename T> void stack_array<T>::push(const T& item) {
if (size() == capacity)
throw std::out_of_range("calling push() on full stack array based");
s[++pos] = item;
}
template <typename T> void stack_array<T>::pop() {
if (empty())
throw std::out_of_range("calling pop() on empty stack array based");
--pos;
}
// stack based on singly linked list
template <typename T> class stack_linked {
public:
stack_linked() : s(), n{ 0 } {}
size_t size() const;
bool empty() const;
const T& top() const;
void pop();
void push(const T&);
private:
linked_list<T> s;
size_t n;
};
template <typename T> inline size_t stack_linked<T>::size() const { return n; }
template <typename T> inline bool stack_linked<T>::empty() const {
return size() == 0;
}
template <typename T> inline const T& stack_linked<T>::top() const {
if (empty())
throw std::out_of_range("calling top() on empty stack based linked list");
return s.front();
}
template <typename T> inline void stack_linked<T>::pop() {
if (empty())
throw std::out_of_range("calling po() on empty stack based linked list");
s.pop_front();
--n;
}
template <typename T> inline void stack_linked<T>::push(const T& item) {
s.push_front(item);
++n;
}
// parent_pair(): matching parentheses problem, applications of stack, O(n)
bool parent_pair(const std::string& ls) {
char opening[] = { '{', '[', '(' };
char closing[] = { '}', ']', ')' };
stack_linked<char> temp;
for (const auto& i : ls) {
if (i == opening[0] || i == opening[1] || i == opening[2])
temp.push(i);
else {
if (temp.empty())
return false; // no matching pair
else { // not match as a pair
if (temp.top() == opening[0]) {
if (i != closing[0])
return false;
}
else if (temp.top() == opening[1]) {
if (i != closing[1])
return false;
}
else if (temp.top() == opening[2]) {
if (i != closing[2])
return false;
}
}
temp.pop(); // match, pop it
}
}
return temp.size() == 0;
}
// queue interface, data structure that maintain the FIFO behavior, using
// circular
template <typename T> class queue_array {
enum { INITIAL_CAPACITY = 100 };
public:
queue_array(const size_t& cap = INITIAL_CAPACITY)
: pointer{ 0 }, first{ 0 }, curr{ 0 }, capacity{ cap }, s(new T[cap]) {}
size_t size() const;
bool empty() const;
const T& front() const;
void enqueue(const T&);
void dequeue();
private:
int pointer;
int first;
int curr;
size_t capacity;
T* s;
};
template <typename T> size_t queue_array<T>::size() const { return curr; }
template <typename T> bool queue_array<T>::empty() const { return size() == 0; }
template <typename T> const T& queue_array<T>::front() const {
if (empty())
throw std::out_of_range("calling front() on empty queue");
return s[first]; // first, current postion after or before dequeue
}
template <typename T> void queue_array<T>::enqueue(const T& item) {
if (size() == capacity)
throw std::out_of_range("calling enqueue() on full queue");
s[pointer] = item; // position to insert the element
pointer = (pointer + 1) % capacity; // if r+1 >= n, go back, set r = remainder
++curr; // increase the size()
}
template <typename T> void queue_array<T>::dequeue() {
if (empty())
throw std::out_of_range("calling dequeue() on empty queue");
first = (first + 1) % capacity; // move forward without copy entire remainder
--curr; // reduce the size
}
// queue_linked: queue data structure based on doubly linked list
template <typename T> class queue_linked {
public:
queue_linked() : sz{ 0 }, ls() {}
int size() const { return sz; }
bool empty() const { return sz == 0; }
const T& front() const;
void enqueue(const T&);
void dequeue();
private:
size_t sz;
circle_list<T> ls;
};
template <typename T> const T& queue_linked<T>::front() const {
if (empty())
throw std::out_of_range(
"calling front() on empty queue based on circular ls");
return ls.front();
}
template <typename T> void queue_linked<T>::enqueue(const T& item) {
ls.add(item);
ls.advance();
++sz;
}
template <typename T> void queue_linked<T>::dequeue() {
if (empty())
throw std::out_of_range(
"calling dequeue() on empty queue based on circular ls");
ls.remove();
--sz;
}
template <typename T> class queue_doubly_linked {
public:
queue_doubly_linked() : sz{ 0 }, ls() {}
bool empty() const { return sz == 0; }
size_t size() const { return sz; }
const T& front() const;
const T& back() const;
void push_front(const T&) noexcept;
void push_back(const T&) noexcept;
void pop_back();
void pop_front();
private:
size_t sz;
d_linked_list<T> ls;
};
template <typename T> inline const T& queue_doubly_linked<T>::front() const {
if (empty())
throw std::out_of_range("calling front() on empty deque");
return ls.front();
}
template <typename T> inline const T& queue_doubly_linked<T>::back() const {
if (empty())
throw std::out_of_range("calling back() on empty deque");
return ls.back();
}
template <typename T>
inline void queue_doubly_linked<T>::push_front(const T& item) noexcept {
ls.push_front(item);
++sz;
}
template <typename T>
inline void queue_doubly_linked<T>::push_back(const T& item) noexcept {
ls.push_back(item);
++sz;
}
template <typename T> inline void queue_doubly_linked<T>::pop_back() {
if (empty())
throw std::out_of_range("calling pop_back() on empty deque");
ls.pop_back();
--sz;
}
template <typename T> inline void queue_doubly_linked<T>::pop_front() {
if (empty())
throw std::out_of_range("calling pop_front() on empty deque");
ls.pop_front();
--sz;
}
// vector_arr: vector class based on array behavior, if size()==n, increase it
template<typename T>
class vector_arr {
public:
explicit vector_arr(const size_t init_sz = 0) : sz{ init_sz },
capacity{ init_sz + SPARSE_CAPACITY } {
arr = new T[capacity];
}
vector_arr(const vector_arr& rhs);
vector_arr& operator=(const vector_arr& rhs);
~vector_arr() { delete[]arr; }
void reserve(const size_t&);
void resize(const size_t&);
T& operator[](const size_t&);
const T& operator[](const size_t&)const;
bool empty()const { return sz == 0; }
size_t size()const { return sz; }
//size_t capacity_v()const { return capacity; }
void push_back(const T&);
void pop_back();
const T& back()const;
const T& front()const;
protected:
static const size_t SPARSE_CAPACITY = 16;
private:
size_t sz;
size_t capacity;
T* arr;
};
template<typename T>
inline vector_arr<T>::vector_arr(const vector_arr& rhs) :
sz{ rhs.size }, capacity{ rhs.capacity }, arr{ nullptr }
{
arr = new T[capacity];
for (size_t i = 0; i < sz; ++i)
arr[i] = rhs.arr[i];
}
template<typename T>
inline vector_arr<T>& vector_arr<T>::operator=(const vector_arr& rhs)
{
vector_arr<T> cp = rhs;
std::swap(*this, cp);
return *this;
}
template<typename T>
inline void vector_arr<T>::reserve(const size_t& n_cap)
{
if (n_cap < sz)
return;
auto temp = new T[n_cap]; //request new capacity
for (size_t i = 0; i < sz; ++i)
temp[i] = std::move(arr[i]);
capacity = n_cap;
std::swap(arr, temp);
delete[]temp;
}
template<typename T>
inline void vector_arr<T>::resize(const size_t& n_cap)
{
if (n_cap > capacity)
reserve(n_cap * 2);
sz = n_cap;
}
template<typename T>
inline T& vector_arr<T>::operator[](const size_t& pos)
{
if (empty())
throw std::out_of_range("vector: index out of range()");
else if (pos >= sz && pos != 0)
throw std::out_of_range("vector: index out range");
return arr[pos];
}
template<typename T>
inline const T& vector_arr<T>::operator[](const size_t& pos) const
{
if (empty())
throw std::out_of_range("vector: index out of range");
else if (pos >= sz && pos != 0)
throw std::out_of_range("vector: index out range");
return arr[pos];
}
template<typename T>
inline void vector_arr<T>::push_back(const T& item)
{
if (sz == capacity)
reserve(2 * capacity + 1);
arr[sz++] = item;
}
template<typename T>
inline void vector_arr<T>::pop_back()
{
if (empty())
throw std::out_of_range("calling pop_back() on empty vector");
--sz;
}
template<typename T>
inline const T& vector_arr<T>::back() const
{
if (empty())
throw std::out_of_range("calling back() on empty vector");
return arr[sz - 1];
}
template<typename T>
inline const T& vector_arr<T>::front() const
{
if (empty())
throw std::out_of_range("calling front() on empty vector");
return arr[0];
}
template<typename T>
class list_adt {
private:
struct node {
public:
node(const T& d = T{}, node* p = nullptr, node* n = nullptr) :
item{ d }, prev{ p }, next{ n } {}
T item;
node* prev;
node* next;
};
public:
class iterator_adt {
public:
// prefer inline
T& operator*() {
return itr_node->item;
}
bool operator==(const iterator_adt& rhs)const {
return itr_node == rhs.itr_node;
}
bool operator!=(const iterator_adt& rhs)const {
return itr_node != rhs.itr_node;
}
iterator_adt& operator++() {
itr_node = itr_node->next;
return *this;
}
iterator_adt& operator--() {
itr_node = itr_node->prev;
return *this;
}
friend class list_adt;
private:
node* itr_node; // pointer to the node
iterator_adt(node* node_u) { itr_node = node_u; } //create from node
};
public:
list_adt();
~list_adt();
size_t size()const {
return sz;
}
bool empty()const {
return sz == 0;
}
iterator_adt begin()const { return iterator_adt(head->next); } //begin of container
iterator_adt end()const { return iterator_adt(tail); } //last+1 container
void push_back(const T& item) { insert(end(), item); }
void push_front(const T& item) { insert(begin(), item); }
void pop_back() { erase(--end()); }
void pop_front() { erase(begin()); }
void erase(const iterator_adt& pos);
void insert(const iterator_adt& pos, const T& item);
const T& back()const {
if (empty())
throw std::out_of_range("calling back() on empty list");
return *--end();
}