From b518212ba750a6cefabf580386249a6b01ee458d Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Mon, 5 Mar 2018 15:54:44 -0800 Subject: [PATCH] ods: Working on DualArrayDeque. --- ods/notes/chapter2.txt | 11 ++++ ods/src/array_test.cc | 31 ++++++++++++ ods/src/ods/array_stack.h | 1 + ods/src/ods/dual_array_deque.h | 91 ++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 ods/src/ods/dual_array_deque.h diff --git a/ods/notes/chapter2.txt b/ods/notes/chapter2.txt index 3f2afe0..9c8987e 100644 --- a/ods/notes/chapter2.txt +++ b/ods/notes/chapter2.txt @@ -57,3 +57,14 @@ resizing isn't too bad. set/get in time O(1) time per operation, and add/remove in O(1+min(i, n-1)) time per operation. Beginning with an empty ArrayDeque, performing any sequence of m operations results in a total of O(m) time resizing. + +## Dual Array Deque + +* Same performance bounds as ArrayDeque using a pair of ArrayStacks. +* While not better, it's instructive as an example of building a more complex + data structure from simpler ones. +* List is represented as a pair of ArrayStacks; these are fast when a + modification occurs at the end. The DAD uses two ArrayStacks called + front and back. + * front: list elements that are 0...front.size()-1 + * back: same but reverse order diff --git a/ods/src/array_test.cc b/ods/src/array_test.cc index bf900eb..ae8c69c 100644 --- a/ods/src/array_test.cc +++ b/ods/src/array_test.cc @@ -4,6 +4,7 @@ #include #include #include +#include using namespace std; using namespace ods; @@ -78,4 +79,34 @@ main(void) ad.remove(3); ad.remove(4); cout << "size: " << ad.size() << ", cap: " << ad.cap() << endl; + + cout << "=== DualArrayDeque ===" << endl; + DualArrayDeque dad(1); + for (int i = 0; i < 5; i++) { + dad.add(0, 4-i); + } + cout << "size: " << dad.size() << ", cap: " << dad.cap() << endl; + + for (int i = 0; i < 5; i++) { + dad.add(dad.size(), i); + } + cout << "size: " << dad.size() << ", cap: " << dad.cap() << endl; + + for (int i = 0; i < dad.size(); i++) { + cout << i << "\t" << dad.get(i) << endl; + } + + x = dad.remove(1); + assert(x == 1); + x = dad.remove(7); + assert(x == 3); + cout << "size: " << dad.size() << ", cap: " << dad.cap() << endl; + + for (int i = 0; i < dad.size(); i++) { + cout << i << "\t" << dad.get(i) << endl; + } + dad.remove(2); + dad.remove(3); + dad.remove(4); + cout << "size: " << dad.size() << ", cap: " << dad.cap() << endl; } diff --git a/ods/src/ods/array_stack.h b/ods/src/ods/array_stack.h index 617c67a..b856e3a 100644 --- a/ods/src/ods/array_stack.h +++ b/ods/src/ods/array_stack.h @@ -10,6 +10,7 @@ template class ArrayStack { public: ArrayStack(int len) : n(0), a(Array(len)) {} + ArrayStack(Array na, int len) : n(len), a(na) {} int size(void) { return n; } int cap(void) { return a.length; } T get(int i) { return a[i]; } diff --git a/ods/src/ods/dual_array_deque.h b/ods/src/ods/dual_array_deque.h new file mode 100644 index 0000000..9b62f05 --- /dev/null +++ b/ods/src/ods/dual_array_deque.h @@ -0,0 +1,91 @@ +#ifndef __ODS_ODS_DUAL_ARRAY_DEQUE__ +#define __ODS_ODS_DUAL_ARRAY_DEQUE__ + +#include +#include +#include + +namespace ods { + + +template +class DualArrayDeque { +public: + DualArrayDeque(int len) : front(ArrayStack(len)), back(ArrayStack(len)) {} + int size(void) { return front.size() + back.size(); } + int cap(void) { return front.cap() + back.cap(); } + T get(int i) { + if (i < front.size()) { + return front.get(front.size() - i - 1); + } + else { + return back.get(i - front.size()); + } + } + T set(int i, T x) { + if (i < front.size()) { + return front.set(front.size() - i - 1, x); + } + else { + return back.set(i - front.size()); + } + } + + void add(int i, T x) { + if (i < front.size()) { + front.add(front.size() - i, x); + } + else { + back.add(i - front.size(), x); + } + balance(); + } + + T remove(int i) { + T x; + if (i < front.size()) { + x = front.remove(front.size() - i - 1); + } + else { + x = back.remove(i - front.size()); + } + balance(); + return x; + } + +private: + ArrayStack front; + ArrayStack back; + + static inline int max(int x, int y) { + return x > y ? x : y; + } + + void balance(void) { + if ((3 * front.size() < back.size()) || + (3 * back.size() < front.size())) { + std::cerr << "rebalancing\n"; + auto n = front.size(); + auto nf = n / 2; + Array af(max(2*nf, 1)); + for (int i = 0; i < nf; i++) { + af[nf-i-1] = this->get(i); + } + + auto nb = n - nf; + Array ab(max(2*nb, 1)); + for (int i = 0; i < nb; i++) { + ab[i] = this->get(nf+i); + } + + ArrayStack fas(af, nf); + ArrayStack bas(ab, nb); + this->front = fas; + this->back = bas; + } + } +}; + +} // namespace ods + +#endif // __ODS_ODS_DUAL_ARRAY_DEQUE__