From 50d5d5c09f0a63d2ca43c56ad917e410f579ae4d Mon Sep 17 00:00:00 2001 From: eson <474420502@qq.com> Date: Tue, 31 Mar 2020 23:52:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + .vscode/launch.json | 49 ++++++ .vscode/settings.json | 3 + .vscode/tasks.json | 39 +++++ CMakeLists.txt | 24 +++ gtest/CMakeLists.txt | 17 +++ gtest/vbt_test.cpp | 9 ++ src/main.cpp | 5 + src/vbt/compare.hpp | 21 +++ src/vbt/vbt.hpp | 341 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 511 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 CMakeLists.txt create mode 100644 gtest/CMakeLists.txt create mode 100644 gtest/vbt_test.cpp create mode 100644 src/main.cpp create mode 100644 src/vbt/compare.hpp create mode 100644 src/vbt/vbt.hpp diff --git a/.gitignore b/.gitignore index e8f31b3..84c4960 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,6 @@ dkms.conf # .nfs files are created when an open file is removed but is still being accessed .nfs* +#my +build + diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7293596 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,49 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) main debug", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/build/orderly", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "preLaunchTask": "cmake main debug", + "setupCommands": [ + { + "description": "为 gdb 启用整齐打印", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, + + { + "name": "(gdb) gtest bug", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/gtest/build/vbt_test", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "preLaunchTask": "cmake test debug", + "setupCommands": [ + { + "description": "为 gdb 启用整齐打印", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4fd5570 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "C_Cpp.default.configurationProvider": "vector-of-bool.cmake-tools" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..76b1f55 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,39 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "type": "shell", + "label": "cmake main debug", + "command": "/usr/bin/bash", + "args": [ + "-c", + "cd ${workspaceFolder}/build && cmake .. && make -j4", + ], + "options": { + "cwd": "/bin" + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "shell", + "label": "cmake test debug", + "command": "/usr/bin/bash", + "args": [ + "-c", + "cd ${workspaceFolder}/gtest && mkdir -p build && cd build && cmake .. && make -j4", + ], + "options": { + "cwd": "/bin" + }, + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..999a668 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.5.0) +project(orderly VERSION 0.1.0) + +include(CTest) +enable_testing() + +include(GoogleTest) +include_directories( + ${CMAKE_CURRENT_LIST_DIR}/src + /usr/include + /usr/local/include +) + +link_directories( + /usr/lib/ + /usr/local/lib/ +) + +add_subdirectory(gtest) +add_executable(orderly src/main.cpp) + +set(CPACK_PROJECT_NAME ${PROJECT_NAME}) +set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) +include(CPack) diff --git a/gtest/CMakeLists.txt b/gtest/CMakeLists.txt new file mode 100644 index 0000000..70044e2 --- /dev/null +++ b/gtest/CMakeLists.txt @@ -0,0 +1,17 @@ + + +include_directories( + ${CMAKE_CURRENT_LIST_DIR}/../src +) + +include(GoogleTest) +add_executable(vbt_test vbt_test.cpp) + +target_link_libraries( + vbt_test + gtest + gtest_main + pthread +) + +add_test(vbt_test vbt_test) \ No newline at end of file diff --git a/gtest/vbt_test.cpp b/gtest/vbt_test.cpp new file mode 100644 index 0000000..6186869 --- /dev/null +++ b/gtest/vbt_test.cpp @@ -0,0 +1,9 @@ + +#include +#include "vbt/vbt.hpp" + + +TEST(vbt_test, put) { + VBTree vbt; + vbt.put(0, 0); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..c4a394d --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,5 @@ +#include + +int main(int, char**) { + std::cout << "Hello, world!\n"; +} diff --git a/src/vbt/compare.hpp b/src/vbt/compare.hpp new file mode 100644 index 0000000..2757059 --- /dev/null +++ b/src/vbt/compare.hpp @@ -0,0 +1,21 @@ +#ifndef __COMPARE__ +#define __COMPARE__ + +template +int compare(T v1, T v2) +{ + if (v1 > v2) + { + return 1; + } + else if (v1 < v2) + { + return -1; + } + else + { + return 0; + } +} + +#endif // __COMPARE__ \ No newline at end of file diff --git a/src/vbt/vbt.hpp b/src/vbt/vbt.hpp new file mode 100644 index 0000000..e669327 --- /dev/null +++ b/src/vbt/vbt.hpp @@ -0,0 +1,341 @@ + +#ifndef __VBTREE__ +#define __VBTREE__ + +#include +#include +#include +#include +#include "compare.hpp" + +using namespace std; +using std::cout, std::endl; +using std::tuple, std::make_tuple; + +typedef unsigned long ULONG; + +template +class VBTree +{ +public: + enum CHILDREN {LEFT = 0, RIGHT = 1}; +public: + struct TreeNode + { + TreeNode *children[2]; + TreeNode *parent; + unsigned long size; + TKey key; + TValue value; + + TreeNode() + { + this->children[LEFT] = NULL; + this->children[RIGHT] = NULL; + this->parent = NULL; + this->size = 1; + } + /* data */ + }; + +private: + TreeNode *root; + inline ULONG get_size(TreeNode *cur) + { + if (cur == NULL) + { + return 0; + } + return cur->size; + } + + inline ULONG get_children_sum_size(TreeNode *cur) + { + return this->get_size(cur->children[LEFT]) + this->get_size(cur->children[RIGHT]); + } + + inline tuple get_children_size(TreeNode *cur) + { + return make_tuple(this->get_size(cur->children[LEFT]), this->get_size(cur->children[RIGHT])); + } + + inline void swap_keyvalue(TreeNode *n1, TreeNode *n2) + { + TKey tempkey = n1->key; + TValue tempvalue = n1->value; + + n1->key = n2->key; //交换值达到, 相对位移 + n1->value = n2->value; + + n2->key = tempkey; + n2->value = tempvalue; + } + + template + inline void xxrotate3(TreeNode *cur) { // + TreeNode *movparent = cur->children[left]; + TreeNode *mov = movparent->children[right]; + + this->swap_keyvalue(mov, cur); + + cur->children[right] = mov; + mov->parent = cur; + + cur->children[left] = movparent; + movparent->children[right] = NULL; + + cur->children[right] = mov; + mov->parent = cur; + + cur->children[left]->size = 1; + } + + template + inline void xxrotate(TreeNode *cur) { + TreeNode *movparent = cur->children[left]; + TreeNode *mov = movparent->children[right]; + + this->swap_keyvalue(mov, cur); + + if (mov->children[left] != NULL) + { + movparent->children[right] = mov->children[left]; + movparent->children[right]->parent = movparent; + } + else + { + movparent->children[right] = NULL; + } + + if (mov->children[right] != NULL) + { + mov->children[left] = mov->children[right]; + } + else + { + mov->children[left] = NULL; + } + + if (cur->children[right] != NULL) + { + mov->children[right] = cur->children[right]; + mov->children[right]->parent = mov; + } + else + { + mov->children[right] = NULL; + } + + cur->children[right] = mov; + mov->parent = cur; + + movparent->size = this->get_children_sum_size(movparent) + 1; + mov->size = this->get_children_sum_size(mov) + 1; + cur->size = this->get_children_sum_size(cur) + 1; + } + + template + inline void xrotate3(TreeNode *cur) { + TreeNode *mov = cur->children[left]; + + this->swap_keyvalue(mov, cur); + + cur->children[right] = mov; + + cur->children[left] = mov->children[left]; + cur->children[left]->parent = cur; + + mov->children[left] = NULL; + + mov->size = 1; + } + + template + inline void xrotate(TreeNode *cur) { + // 1 right 0 left + TreeNode *mov = cur->children[left]; + + this->swap_keyvalue(mov, cur); + + // mov->children[l]不可能为nil + mov->children[left]->parent = cur; + + cur->children[left] = mov->children[left]; + + // 解决mov节点孩子转移的问题 + if (mov->children[right] != NULL) + { + mov->children[left] = mov->children[right]; + } + else + { + mov->children[left] = NULL; + } + + if (cur->children[right] != NULL) + { + mov->children[right] = cur->children[right]; + mov->children[right]->parent = mov; + } + else + { + mov->children[right] = NULL; + } + + // 连接转移后的节点 由于mov只是与cur交换值,parent不变 + cur->children[right] = mov; + + mov->size = get_children_sum_size(mov) + 1; + cur->size = get_children_sum_size(cur) + 1; + } + + inline void fix_size(TreeNode *cur, ULONG ls, ULONG rs) + { + if (ls > rs) + { + tuple lllr = this->get_children_size(cur->children[LEFT]); + ULONG llsize = std::get(lllr); + ULONG lrsize = std::get(lllr); + if (lrsize > llsize) + { + this->xxrotate(cur); + } + else + { + this->xrotate(cur); + } + } + else + { + tuple rlrr = this->get_children_size(cur->children[RIGHT]); + ULONG rlsize = std::get(rlrr); + ULONG rrsize = std::get(rlrr); + if (rlsize > rrsize) + { + this->xxrotate(cur); + } + else + { + this->xrotate(cur); + } + } + } + +public: + VBTree() + { + this->root = NULL; + } + + TValue* get(TKey key) + { + for (TreeNode *n = this->root; n != NULL;) + { + int c = Compare(key, n->key); + switch (c) + { + case -1: + n = n->children[LEFT]; + break; + case 1: + n = n->children[RIGHT]; + break; + case 0: + return &n->value; + } + } + return NULL; + } + + void put(TKey key, TValue value) + { + + if (this->root == NULL) + { + TreeNode *node = new TreeNode(); + node->key = key; + node->value = value; + this->root = node; + return; + } + + + for (TreeNode *cur = this->root;;) + { + if (cur->size > 8) + { + unsigned long factor = cur->size >> 3; // 原来是/10 为了简化为位运算/8  + unsigned long ls = cur->children[LEFT]->size; + unsigned long rs = cur->children[RIGHT]->size; + if (rs >= (ls << 1) + factor || ls >= (rs << 1) + factor) // ls rs * 2 + { + this->fix_size(cur, ls, rs); + } + } + + cur->size++; + + int c = Compare(key, cur->key); + if (c < 0) + { + if (cur->children[LEFT] == NULL) + { + TreeNode *node = new TreeNode(); + node->key = key; + node->value = value; + + cur->children[LEFT] = node; + node->parent = cur; + + if (cur->parent != NULL && cur->parent->size == 3) + { + if (cur->parent->children[LEFT] == NULL) + { + this->xxrotate3(cur->parent); + } + else + { + this->xrotate3(cur->parent); + } + } + return; + } + cur = cur->children[LEFT]; + } + else + { + if (cur->children[RIGHT] == NULL) + { + TreeNode *node = new TreeNode(); + node->key = key; + node->value = value; + + cur->children[RIGHT] = node; + node->parent = cur; + + if (cur->parent != NULL && cur->parent->size == 3) + { + if (cur->parent->children[RIGHT] == NULL) + { + this->xxrotate3(cur->parent); + } + else + { + this->xrotate3(cur->parent); + } + } + return; + } + cur = cur->children[RIGHT]; + } + } + + cout << "error" << endl; + return ; + }; + + /* data */ +}; + + +#endif // __VBTREE__ \ No newline at end of file