From 9812f96ed55550140f8fab7f2e6ca99b0196f873 Mon Sep 17 00:00:00 2001 From: SPeak Date: Thu, 11 Jul 2024 14:53:44 +0800 Subject: [PATCH] DoublyLink (#34) * base * book + code + impl * remove impl --- book/src/1_linkedlist.md | 6 +- book/src/SUMMARY.md | 4 +- ...edlist.md => chapter_04_embedded_slist.md} | 2 +- book/src/chapter_06_embedded_dlist.md | 374 ++++++++++++++++++ common/common.hpp | 16 +- common/dslings.lua | 5 + .../exercises/linked-list/EmbeddedList.hpp | 1 - .../tests/embedded-list/embedded-dlist.0.cpp | 25 ++ .../tests/embedded-list/embedded-dlist.1.cpp | 40 ++ .../tests/embedded-list/embedded-dlist.2.cpp | 72 ++++ .../tests/embedded-list/embedded-dlist.3.cpp | 69 ++++ .../tests/embedded-list/embedded-dlist.4.cpp | 83 ++++ dslings/xmake.lua | 22 +- 13 files changed, 711 insertions(+), 8 deletions(-) rename book/src/{chapter_04_embeddedlist.md => chapter_04_embedded_slist.md} (99%) create mode 100644 book/src/chapter_06_embedded_dlist.md create mode 100644 dslings/tests/embedded-list/embedded-dlist.0.cpp create mode 100644 dslings/tests/embedded-list/embedded-dlist.1.cpp create mode 100644 dslings/tests/embedded-list/embedded-dlist.2.cpp create mode 100644 dslings/tests/embedded-list/embedded-dlist.3.cpp create mode 100644 dslings/tests/embedded-list/embedded-dlist.4.cpp diff --git a/book/src/1_linkedlist.md b/book/src/1_linkedlist.md index 3ed42db..735059b 100644 --- a/book/src/1_linkedlist.md +++ b/book/src/1_linkedlist.md @@ -1 +1,5 @@ -# 链表 \ No newline at end of file +# 链表 + +- [嵌入式单链表](chapter_04_embedded_slist.md) +- [单链表](chapter_05_slist.md) +- [嵌入式双链表](chapter_06_embedded_dlist.md) \ No newline at end of file diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 05a3d75..81edeb8 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -12,9 +12,9 @@ - [Array和Vector对比]() - [链表](1_linkedlist.md) - - [嵌入式单链表](chapter_04_embeddedlist.md) + - [嵌入式单链表](chapter_04_embedded_slist.md) - [单链表](chapter_05_slist.md) - - [嵌入式双链表]() + - [嵌入式双链表](chapter_06_embedded_dlist.md) - [双链表]() - [静态链表]() - [几种链表对比]() diff --git a/book/src/chapter_04_embeddedlist.md b/book/src/chapter_04_embedded_slist.md similarity index 99% rename from book/src/chapter_04_embeddedlist.md rename to book/src/chapter_04_embedded_slist.md index 160d6a0..ca3f608 100644 --- a/book/src/chapter_04_embeddedlist.md +++ b/book/src/chapter_04_embedded_slist.md @@ -1,4 +1,4 @@ -# 嵌入式单链表 +# 嵌入式单链表 - SinglyLink **预览** diff --git a/book/src/chapter_06_embedded_dlist.md b/book/src/chapter_06_embedded_dlist.md new file mode 100644 index 0000000..c30728b --- /dev/null +++ b/book/src/chapter_06_embedded_dlist.md @@ -0,0 +1,374 @@ +# 嵌入式双链表 - DoublyLink + +**预览** + +--- + +- 基本介绍 + - 单链表 VS 双链表 +- DoublyLink核心实现 + - 定义和初始化 + - 插入和删除操作 + - 逆序遍历 +- 使用示例 + - 组合式 + - 嵌入式 + - 继承式 +- 总结 + +--- + +前面介绍过了**嵌入式单链表**, 但其并不支持向前查找。本章节就将介绍链表中最常用的双链表对应的"无数据域"的 -- **嵌入式双链表** + +**内存使用对比** + +在双链表中, 每一个节点都比单链表多了一个指向前一个节点的指针`prev`, 所以对应的在存储相同数据量的元素N时, 内存的使用要比单链表多N x 8字节(设:指针占8字节)。但多数时候大家都原因花费这个内存的代价来换取使用的便利 + +```cpp +struct SinglyLink { + struct SinglyLink *next; +}; + +struct DoublyLink { + struct DoublyLink *prev, *next; +}; +``` + +**单链表的局限性** + +双链表引入的这个`prev`指针就是为了解决单链表无法向前查找的问题, 这里我们可以用删除当前节点的操作来演示使用场景 + +- target: 我们需要删除的节点 +- del: 链表删除操作 + +```cpp +SinglyLink::del(prevNodePtr ?, &target); +DoublyLink::del(target.prev, &target); +``` + +通过代码可以直观的看出, 由于**从链表中删除节点需要知道该节点的前一个节点**, 所以从单链中删除target, 而找到target的前一个节点并不能很高效的完成。对于双链表只需要O(1)的复杂度。 + +## DoublyLink核心实现 + +采用节点 + 静态成员函数的方式进行定义DoublyLink + +### 定义和初始化 + +只包含两个指针, 一个指向前驱节点, 一个指向后继节点。节点的初始化就是把这两个指针指向自己。可以把这样的节点视为一个没有数据的链表头结点, 或一个不在链表中的节点 + +```cpp +struct DoublyLink { + struct DoublyLink *prev, *next; + + static void init(struct DoublyLink *target) { + target->prev = target->next = target; + } +}; +``` + +### 插入和删除操作 + +双链表的插入操作, 需要处理三个节点中的4个指针。它们分别是: + +- target的next指针 - 指向prev节点的next +- target的prev指针 - 指向prev节点 +- prev的下一个节点的prev指针 - 指向target +- prev的next指针 - 指向target + +```cpp +struct DoublyLink { + static void insert(DoublyLink *prev, DoublyLink *target) { + target->next = prev->next; + target->prev = prev; + prev->next->prev = target; + prev->next = target; + } + + static void del(DoublyLink *prev, DoublyLink *target) { + prev->next = target->next; + target->next->prev = prev; + } +}; +``` + +双链表的删除操作, 只需要更新删除节点的 + +- 前一个节点的next指针 - 指向target的下一个节点 +- 后一个节点的prev指针 - 指向target的前一个节点 + +> 注: +> 对于双链表的del接口, 其实可以不用显示的传前一个节点的指针prev。但这里为了和单链表的节点格式进行统一保留了prev。等价形式: +> - del(target) +> - del(target->prev, target) + + +### 逆序遍历 + +通过prev指针, 从后向前遍历将变的异常容易。如下的逆序遍历for循环的代码框架几乎和向后遍历一致的 + +```cpp +// Node : linkPtr = malloc(sizeof(Link) + sizeof(Data)) +for (auto linkPtr = head.prev; linkPtr != &head; linkPtr = linkPtr->prev) { + MyData *dataPtr = reinterpret_cast(linkPtr + 1); + // do something +} +``` + +## 使用示例 + +在**嵌入式单链表**章节从设计者视角详细的介绍了常用的使用示例。本章将中从实用角度出发来介绍。通过使用**组合式、嵌入式、继承式**的方式来实现同样一个功能来进行对比 + +### 组合式 + +```cpp +// embedded-dlist.2.cpp - write +// +// 描述: +// 嵌入式双链表 - 组合式 +// +// 目标/要求: +// - 在对应的SHOW_YOUR_CODE代码块实现 逆序遍历 和 链表的释放 +// - 通过所有编译器检测 和 断言 +// + +#include "common/common.hpp" + +#include "exercises/linked-list/EmbeddedList.hpp" + +using d2ds::DefaultAllocator; + +struct MyData { + int id; + char data; +}; + +int main() { + + d2ds::DefaultAllocator::debug() = true; + + d2ds::DoublyLink head; + + d2ds::DoublyLink::init(&head); + + for (int i = 0; i < 10; i++) { + auto linkPtr = ( d2ds::DoublyLink* ) d2ds::DefaultAllocator::malloc(sizeof(d2ds::DoublyLink) + sizeof(MyData)); + d2ds::DoublyLink::init(linkPtr); + auto dataPtr = (MyData *)(linkPtr + 1); + dataPtr->id = i; + dataPtr->data = 'a' + i; + d2ds::DoublyLink::insert(&head, linkPtr); + } + + dstruct::Stack dataStack; + for (auto linkPtr = head.next; linkPtr != &head; linkPtr = linkPtr->next) { + auto dataPtr = reinterpret_cast(linkPtr + 1); + dataStack.push(*dataPtr); + } + + SHOW_YOUR_CODE({ // reverse traverse + for (auto linkPtr = head.prev; linkPtr != &head; linkPtr = linkPtr->prev) { + MyData *dataPtr = reinterpret_cast(linkPtr + 1); + + DONT_CHANGE( + auto myData = dataStack.top(); + d2ds_assert_eq(dataPtr->id, myData.id); + d2ds_assert_eq(dataPtr->data, myData.data); + dataStack.pop(); + ) + } + }) + + d2ds_assert(dataStack.empty()); + + SHOW_YOUR_CODE({ // use DefaultAllocator::free(addr) to release + d2ds::DoublyLink *target = head.next; + while (target != &head) { + d2ds::DoublyLink::del(&head, target); + DefaultAllocator::free(target); + target = head.next; + } + }) + + d2ds_assert(head.next == &head); + + D2DS_WAIT + + return 0; +} +``` + +### 嵌入式 + +```cpp +// embedded-dlist.3.cpp - write +// +// 描述: +// 嵌入式双链表 - 嵌入式 +// +// 目标/要求: +// - 在对应的SHOW_YOUR_CODE代码块实现 逆序遍历 和 链表的释放 +// - 通过所有编译器检测 和 断言 +// + +#include "common/common.hpp" + +#include "exercises/linked-list/EmbeddedList.hpp" + +using d2ds::DefaultAllocator; + +struct MyData { + d2ds::DoublyLink link; + int id; + char data; +}; + +int main() { + + d2ds::DefaultAllocator::debug() = true; + + d2ds::DoublyLink head; + + d2ds::DoublyLink::init(&head); + + for (int i = 0; i < 10; i++) { + auto dataPtr = (MyData *) d2ds::DefaultAllocator::malloc(sizeof(MyData)); + d2ds::DoublyLink::init(&(dataPtr->link)); + dataPtr->id = i; + dataPtr->data = 'a' + i; + d2ds::DoublyLink::insert(&head, &(dataPtr->link)); + } + + dstruct::Stack dataStack; + for (auto linkPtr = head.next; linkPtr != &head; linkPtr = linkPtr->next) { + auto dataPtr = reinterpret_cast(linkPtr); + dataStack.push(*dataPtr); + } + + SHOW_YOUR_CODE({ // reverse traverse + for (auto linkPtr = head.prev; linkPtr != &head; linkPtr = linkPtr->prev) { + MyData *dataPtr = reinterpret_cast(linkPtr); + + DONT_CHANGE( + auto myData = dataStack.top(); + d2ds_assert_eq(dataPtr->id, myData.id); + d2ds_assert_eq(dataPtr->data, myData.data); + dataStack.pop(); + ) + } + }) + + d2ds_assert(dataStack.empty()); + + SHOW_YOUR_CODE({ // use DefaultAllocator::free(addr) to release + d2ds::DoublyLink *target = head.next; + while (target != &head) { + d2ds::DoublyLink::del(&head, target); + DefaultAllocator::free(target); + target = head.next; + } + }) + + d2ds_assert(head.next == &head); + + D2DS_WAIT + + return 0; +} +``` + +### 继承式 + +```cpp +// embedded-dlist.4.cpp - write +// +// 描述: +// 嵌入式双链表 - 继承式 +// +// 目标/要求: +// - 在对应的SHOW_YOUR_CODE代码块实现 逆序遍历 和 链表的释放 +// - 通过所有编译器检测 和 断言 +// + +#include "common/common.hpp" + +#include "exercises/linked-list/EmbeddedList.hpp" + +using d2ds::DefaultAllocator; + +template +struct ENode : d2ds::DoublyLink { + ENode * prev() { + return static_cast(d2ds::DoublyLink::prev); + } + + ENode * next() { + return static_cast(d2ds::DoublyLink::next); + } + + T * data() { + return static_cast(this); + } +}; + +struct MyData : ENode { + int id; + char data; +}; + +int main() { + + d2ds::DefaultAllocator::debug() = true; + + ENode head; + + d2ds::DoublyLink::init(&head); + + for (int i = 0; i < 10; i++) { + auto dataPtr = (MyData *) d2ds::DefaultAllocator::malloc(sizeo(MyData)); + d2ds::DoublyLink::init(dataPtr); + dataPtr->id = i; + dataPtr->data = 'a' + i; + d2ds::DoublyLink::insert(&head, dataPtr); + } + + dstruct::Stack dataStack; + for (auto nodePtr = head.next(); nodePtr != &head; nodePtr = nodePtr->nex()) { + auto dataPtr = nodePtr->data(); + dataStack.push(*dataPtr); + } + + SHOW_YOUR_CODE({ // reverse traverse + for (auto nodePtr = head.prev(); nodePtr != &head; nodePtr = nodePtr->prev()) { + MyData *dataPtr = nodePtr->data(); + + DONT_CHANGE( + auto myData = dataStack.top(); + d2ds_assert_eq(dataPtr->id, myData.id); + d2ds_assert_eq(dataPtr->data, myData.data); + dataStack.pop(); + ) + } + }) + + d2ds_assert(dataStack.empty()); + + SHOW_YOUR_CODE({ // use DefaultAllocator::free(addr) to release + ENode *target = head.next(); + while (target != &head) { + d2ds::DoublyLink::del(&head, target); + DefaultAllocator::free(target); + target = head.next(); + } + }) + + d2ds_assert(head.next() == &head); + + D2DS_WAIT + + return 0; +} +``` + +## 总结 + +本章节是基于**嵌入式单链表**章节继续来介绍链表中最常用的双链表对应的嵌入式双链表的实现和使用示例。显示简单介绍了双链表的引入原因(相对与单链表)。然后, 又以同一个示例展示了嵌入式双链表的不同的使用方式 \ No newline at end of file diff --git a/common/common.hpp b/common/common.hpp index 874adc4..ff5c645 100644 --- a/common/common.hpp +++ b/common/common.hpp @@ -40,17 +40,29 @@ #define D2DS_SELF_ASSIGNMENT_CHECKER if (this == &dsObj) return *this; +#define SHOW_YOUR_CODE(code_block) code_block +#define DONT_CHANGE(code) code; + namespace d2ds { struct DefaultAllocator { + static void * malloc(int bytes) { + return allocate(bytes); + } + + static void free(void *addr) { + deallocate(addr, 0); + } + +public: using Address = unsigned long long; static void * allocate(int bytes) { allocate_counter()++; if (debug()) HONLY_LOGI("DefaultAllocator: try to allocate %d bytes", bytes); - void *memPtr = malloc(bytes); + void *memPtr = ::malloc(bytes); memory_addr_flag_d()[(Address)memPtr] = true; return memPtr; } @@ -65,7 +77,7 @@ struct DefaultAllocator { HONLY_LOGE("double free - %p", addr); } else { memory_addr_flag_d()[(Address)addr] = false; - free(addr); + ::free(addr); } } diff --git a/common/dslings.lua b/common/dslings.lua index bfd852a..ff657cb 100644 --- a/common/dslings.lua +++ b/common/dslings.lua @@ -54,6 +54,11 @@ target_to_code_file = { ["7.slinked-list-iterator-3"] = "dslings/exercises/linked-list/SLinkedList.hpp", ["7.slinked-list-iterator-4"] = "dslings/exercises/linked-list/SLinkedList.hpp", ["7.slinked-list-iterator-5"] = "dslings/exercises/linked-list/SLinkedList.hpp", + ["8.embedded-dlist-0"] = "dslings/exercises/linked-list/EmbeddedList.hpp", + ["8.embedded-dlist-1"] = "dslings/exercises/linked-list/EmbeddedList.hpp", + ["8.embedded-dlist-2"] = "dslings/exercises/linked-list/EmbeddedList.hpp", + ["8.embedded-dlist-3"] = "dslings/exercises/linked-list/EmbeddedList.hpp", + ["8.embedded-dlist-4"] = "dslings/exercises/linked-list/EmbeddedList.hpp", } function clear_screen() diff --git a/dslings/exercises/linked-list/EmbeddedList.hpp b/dslings/exercises/linked-list/EmbeddedList.hpp index bcc6b19..03f596a 100644 --- a/dslings/exercises/linked-list/EmbeddedList.hpp +++ b/dslings/exercises/linked-list/EmbeddedList.hpp @@ -4,7 +4,6 @@ namespace d2ds { // show your code - } #endif \ No newline at end of file diff --git a/dslings/tests/embedded-list/embedded-dlist.0.cpp b/dslings/tests/embedded-list/embedded-dlist.0.cpp new file mode 100644 index 0000000..4dc75c1 --- /dev/null +++ b/dslings/tests/embedded-list/embedded-dlist.0.cpp @@ -0,0 +1,25 @@ +// embedded-dlist.0.cpp - readonly +// +// 描述: +// 定义嵌入式双链表和初始化操作 +// +// 目标/要求: +// - 定义对应的DoublyLink和对应的init操作 +// - 在exercises/linked-list/EmbeddedList.hpp中完成你的代码设计 +// - 通过所有编译器检测 和 断言 +// + +#include "common/common.hpp" + +#include "exercises/linked-list/EmbeddedList.hpp" + +int main() { + + d2ds::DoublyLink dLink; + d2ds::DoublyLink::init(&dLink); + d2ds_assert(dLink.next == dLink.prev); + + D2DS_WAIT + + return 0; +} \ No newline at end of file diff --git a/dslings/tests/embedded-list/embedded-dlist.1.cpp b/dslings/tests/embedded-list/embedded-dlist.1.cpp new file mode 100644 index 0000000..cb76d82 --- /dev/null +++ b/dslings/tests/embedded-list/embedded-dlist.1.cpp @@ -0,0 +1,40 @@ +// embedded-dlist.1.cpp - readonly +// +// 描述: +// 嵌入式双链表的插入和删除操作 +// +// 目标/要求: +// - 在DoublyLink中实现insert和del操作 +// - 在exercises/linked-list/EmbeddedList.hpp中完成你的代码设计 +// - 通过所有编译器检测 和 断言 +// + +#include "common/common.hpp" + +#include "exercises/linked-list/EmbeddedList.hpp" + +int main() { + + d2ds::DoublyLink head; + + d2ds::DoublyLink::init(&head); + + for (int i = 0; i < 10; i++) { + auto linkPtr = new d2ds::DoublyLink(); + d2ds::DoublyLink::insert(&head, linkPtr); + } + + int cnt = 0; + while (head.next != &head) { + cnt++; + auto target = head.next; + d2ds::DoublyLink::del(&head, target); + delete target; + } + + d2ds_assert_eq(cnt, 10); + + D2DS_WAIT + + return 0; +} \ No newline at end of file diff --git a/dslings/tests/embedded-list/embedded-dlist.2.cpp b/dslings/tests/embedded-list/embedded-dlist.2.cpp new file mode 100644 index 0000000..4e89667 --- /dev/null +++ b/dslings/tests/embedded-list/embedded-dlist.2.cpp @@ -0,0 +1,72 @@ +// embedded-dlist.2.cpp - write +// +// 描述: +// 嵌入式双链表 - 组合式 +// +// 目标/要求: +// - 在对应的SHOW_YOUR_CODE代码块实现 逆序遍历 和 链表的释放 +// - 通过所有编译器检测 和 断言 +// + +#include "common/common.hpp" + +#include "exercises/linked-list/EmbeddedList.hpp" + +using d2ds::DefaultAllocator; + +struct MyData { + int id; + char data; +}; + +int main() { + + d2ds::DefaultAllocator::debug() = true; + + d2ds::DoublyLink head; + + d2ds::DoublyLink::init(&head); + + for (int i = 0; i < 10; i++) { + auto linkPtr = ( d2ds::DoublyLink* ) d2ds::DefaultAllocator::malloc(sizeof(d2ds::DoublyLink) + sizeof(MyData)); + d2ds::DoublyLink::init(linkPtr); + auto dataPtr = (MyData *)(linkPtr + 1); + dataPtr->id = i; + dataPtr->data = 'a' + i; + d2ds::DoublyLink::insert(&head, linkPtr); + } + + dstruct::Stack dataStack; + for (auto linkPtr = head.next; linkPtr != &head; linkPtr = linkPtr->next) { + auto dataPtr = reinterpret_cast(linkPtr + 1); + dataStack.push(*dataPtr); + } + + SHOW_YOUR_CODE({ // reverse traverse + for (auto linkPtr = ?; linkPtr != &head; ) { + MyData *dataPtr = ?; + + DONT_CHANGE( + auto myData = dataStack.top(); + d2ds_assert_eq(dataPtr->id, myData.id); + d2ds_assert_eq(dataPtr->data, myData.data); + dataStack.pop(); + ) + } + }) + + d2ds_assert(dataStack.empty()); + + SHOW_YOUR_CODE({ // use DefaultAllocator::free(addr) to release + d2ds::DoublyLink *target = head.next; + while (target != &head) { + DefaultAllocator::free(target); + } + }) + + d2ds_assert(head.next == &head); + + D2DS_WAIT + + return 0; +} \ No newline at end of file diff --git a/dslings/tests/embedded-list/embedded-dlist.3.cpp b/dslings/tests/embedded-list/embedded-dlist.3.cpp new file mode 100644 index 0000000..83af781 --- /dev/null +++ b/dslings/tests/embedded-list/embedded-dlist.3.cpp @@ -0,0 +1,69 @@ +// embedded-dlist.3.cpp - write +// +// 描述: +// 嵌入式双链表 - 嵌入式 +// +// 目标/要求: +// - 在对应的SHOW_YOUR_CODE代码块实现 逆序遍历 和 链表的释放 +// - 通过所有编译器检测 和 断言 +// + +#include "common/common.hpp" + +#include "exercises/linked-list/EmbeddedList.hpp" + +using d2ds::DefaultAllocator; + +struct MyData { + d2ds::DoublyLink link; + int id; + char data; +}; + +int main() { + + d2ds::DefaultAllocator::debug() = true; + + d2ds::DoublyLink head; + + d2ds::DoublyLink::init(&head); + + for (int i = 0; i < 10; i++) { + auto dataPtr = (MyData *) d2ds::DefaultAllocator::malloc(sizeof(MyData)); + d2ds::DoublyLink::init(&(dataPtr->link)); + dataPtr->id = i; + dataPtr->data = 'a' + i; + d2ds::DoublyLink::insert(&head, &(dataPtr->link)); + } + + dstruct::Stack dataStack; + for (auto linkPtr = head.next; linkPtr != &head; linkPtr = linkPtr->next) { + auto dataPtr = reinterpret_cast(linkPtr); + dataStack.push(*dataPtr); + } + + SHOW_YOUR_CODE({ // reverse traverse + for (auto linkPtr = head.prev; linkPtr != &head; linkPtr = linkPtr->prev) { + MyData *dataPtr = ?; + + DONT_CHANGE( + auto myData = dataStack.top(); + d2ds_assert_eq(dataPtr->id, myData.id); + d2ds_assert_eq(dataPtr->data, myData.data); + dataStack.pop(); + ) + } + }) + + d2ds_assert(dataStack.empty()); + + SHOW_YOUR_CODE({ // use DefaultAllocator::free(addr) to release + + }) + + d2ds_assert(head.next == &head); + + D2DS_WAIT + + return 0; +} \ No newline at end of file diff --git a/dslings/tests/embedded-list/embedded-dlist.4.cpp b/dslings/tests/embedded-list/embedded-dlist.4.cpp new file mode 100644 index 0000000..ed8e4e4 --- /dev/null +++ b/dslings/tests/embedded-list/embedded-dlist.4.cpp @@ -0,0 +1,83 @@ +// embedded-dlist.4.cpp - write +// +// 描述: +// 嵌入式双链表 - 继承式 +// +// 目标/要求: +// - 在对应的SHOW_YOUR_CODE代码块实现 逆序遍历 和 链表的释放 +// - 通过所有编译器检测 和 断言 +// + +#include "common/common.hpp" + +#include "exercises/linked-list/EmbeddedList.hpp" + +using d2ds::DefaultAllocator; + +template +struct ENode : d2ds::DoublyLink { + ENode * prev() { + return static_cast(d2ds::DoublyLink::prev); + } + + ENode * next() { + return static_cast(d2ds::DoublyLink::next); + } + + T * data() { + return static_cast(this); + } +}; + +struct MyData : ENode { + int id; + char data; +}; + +int main() { + + d2ds::DefaultAllocator::debug() = true; + + ENode head; + + d2ds::DoublyLink::init(&head); + + for (int i = 0; i < 10; i++) { + auto dataPtr = (MyData *) d2ds::DefaultAllocator::malloc(sizeof(MyData)); + d2ds::DoublyLink::init(dataPtr); + dataPtr->id = i; + dataPtr->data = 'a' + i; + d2ds::DoublyLink::insert(&head, dataPtr); + } + + dstruct::Stack dataStack; + for (auto nodePtr = head.next(); nodePtr != &head; nodePtr = nodePtr->next()) { + auto dataPtr = nodePtr->data(); + dataStack.push(*dataPtr); + } + + SHOW_YOUR_CODE({ // reverse traverse + for () { + MyData *dataPtr = ?; + + DONT_CHANGE( + auto myData = dataStack.top(); + d2ds_assert_eq(dataPtr->id, myData.id); + d2ds_assert_eq(dataPtr->data, myData.data); + dataStack.pop(); + ) + } + }) + + d2ds_assert(dataStack.empty()); + + SHOW_YOUR_CODE({ // use DefaultAllocator::free(addr) to release + + }) + + d2ds_assert(head.next() == &head); + + D2DS_WAIT + + return 0; +} \ No newline at end of file diff --git a/dslings/xmake.lua b/dslings/xmake.lua index b7a7bd4..7f6adad 100644 --- a/dslings/xmake.lua +++ b/dslings/xmake.lua @@ -192,4 +192,24 @@ target("7.slinked-list-iterator-4") target("7.slinked-list-iterator-5") set_kind("binary") - add_files("tests/slinked-list/slist.it.5.cpp") \ No newline at end of file + add_files("tests/slinked-list/slist.it.5.cpp") + +target("8.embedded-dlist-0") + set_kind("binary") + add_files("tests/embedded-list/embedded-dlist.0.cpp") + +target("8.embedded-dlist-1") + set_kind("binary") + add_files("tests/embedded-list/embedded-dlist.1.cpp") + +target("8.embedded-dlist-2") + set_kind("binary") + add_files("tests/embedded-list/embedded-dlist.2.cpp") + +target("8.embedded-dlist-3") + set_kind("binary") + add_files("tests/embedded-list/embedded-dlist.3.cpp") + +target("8.embedded-dlist-4") + set_kind("binary") + add_files("tests/embedded-list/embedded-dlist.4.cpp") \ No newline at end of file