From 8b0122556cd77c2c69e2a0c766f2201b80db50bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Fri, 18 Nov 2022 22:18:21 +0300 Subject: [PATCH 01/20] fix readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ac390f9..5f26b6a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # techopark_cpp_hw Репозиторий для сдачи домашних работ по С++ в Технопарке + +**STL-совместимый контейнер** From 2e221d34dab4e19040b947533141a83caeee09f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Fri, 18 Nov 2022 23:17:46 +0300 Subject: [PATCH 02/20] avl tree --- .clang-format | 8 ++ .github/workflows/main.yml | 49 ++++++++ .gitignore | 2 + CMakeLists.txt | 37 ++++++ CPPLINT.cfg | 10 ++ Dockerfile | 14 +++ Makefile | 55 +++++++++ linters/run.sh | 49 ++++++++ main.cpp | 29 +++++ set_lib/CMakeLists.txt | 34 ++++++ set_lib/include/set.h | 49 ++++++++ set_lib/include/set_definition.h | 189 +++++++++++++++++++++++++++++++ set_lib/src/set.cpp | 2 + tests/CMakeLists.txt | 19 ++++ tests/test_set.cpp | 7 ++ 15 files changed, 553 insertions(+) create mode 100644 .clang-format create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CPPLINT.cfg create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 linters/run.sh create mode 100644 main.cpp create mode 100644 set_lib/CMakeLists.txt create mode 100644 set_lib/include/set.h create mode 100644 set_lib/include/set_definition.h create mode 100644 set_lib/src/set.cpp create mode 100644 tests/CMakeLists.txt create mode 100644 tests/test_set.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..18bd48c --- /dev/null +++ b/.clang-format @@ -0,0 +1,8 @@ +BasedOnStyle: Microsoft +IndentWidth: 4 +UseTab: Always +AccessModifierOffset: 0 +AccessModifierOffset: -4 +# IndentAccessModifiers: false +# does not work +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..cd35929 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,49 @@ +on: push + +jobs: + check: + runs-on: ubuntu-latest + container: mikhail2001/young_devs_image + steps: + - uses: actions/checkout@v2 + - name: GO LINTER CHECK + run: make check || exit 0 + build: + runs-on: ubuntu-latest + container: mikhail2001/young_devs_image + steps: + - uses: actions/checkout@v2 + - name: GO BUILD + run: make build + - name: Upload artifacts (EXECUTABLE FILE) + uses: actions/upload-artifact@v2 + with: + name: executable-file + path: build/fib + test: + runs-on: ubuntu-latest + container: mikhail2001/young_devs_image + steps: + - uses: actions/checkout@v2 + - run: make build TEST_OPT=ON + - run: make run + - run: make test + - name: GO TEST COVERAGE + run: make coverage + - name: Upload artifacts (COVERAGE REPORT) + uses: actions/upload-artifact@v2 + with: + name: coverage-report + path: build/report + - name: GO VALGRIND TESTS + run: make valgrind_tests + - name: GO VALGRIND TARGET + run: make valgrind_target + - name: GO SANITIZER + run: | + make build SANITIZE_OPT=ON + make run + - name: GO SCAN-BUILD + run: | + make build + make scan_build diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..046c078 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/build +/.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7662943 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.0.0) +project(main) + +set(CMAKE_CXX_STANDARD 17) + +find_package(Threads REQUIRED) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + +option(TEST_OPT "build test version" OFF) +option(DEBUG_OPT "build debug version" ON) +option(SANITIZE_OPT "build with flags -fsanitize" OFF) + +add_subdirectory(set_lib) + +add_executable(${PROJECT_NAME} main.cpp) + +if(TEST_OPT) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) +endif() + +if(DEBUG_OPT) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g -fPIC -O0" ) +endif() + +if(SANITIZE_OPT) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined" ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined") +endif() + + +target_include_directories(${PROJECT_NAME} PUBLIC ${SET_LIB_INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} PRIVATE ${SET_LIB_LIBRARIES}) + +if (TEST_OPT) + enable_testing() + add_subdirectory(tests) +endif() diff --git a/CPPLINT.cfg b/CPPLINT.cfg new file mode 100644 index 0000000..6dfc624 --- /dev/null +++ b/CPPLINT.cfg @@ -0,0 +1,10 @@ +headers=h +linelength=110 +filter=-whitespace/tab +filter=-runtime/int +filter=-legal/copyright +filter=-build/header_guard +filter=-build/include_subdir +filter=-build/include +filter=-readability/casting +filter=-whitespace/braces \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9d24918 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM ubuntu:latest +RUN apt update -y && \ + apt install -y wget g++ make binutils cmake cppcheck clang-tidy python3-pip libc6-dbg cmake libgtest-dev lcov clang-tools vim +RUN apt install -y libboost-dev libboost-all-dev +RUN apt install -y clang-format +RUN apt install -y git curl +RUN pip install cpplint +RUN wget https://sourceware.org/pub/valgrind/valgrind-3.18.1.tar.bz2 && \ + tar xfv valgrind-3.18.1.tar.bz2 && \ + cd valgrind-3.18.1 && \ + ./autogen.sh && \ + ./configure && \ + make && \ + make install diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9f44590 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +BUILD_DIR = build +TESTS_DIR = tests +LIB_DIR = set_lib + +# project(xxx) on CMakeLists +TESTS_EXE = test_set +TARGET_EXE = main + +PATH_LINTERS_SCRIPT = linters/run.sh + +TEST_OPT = OFF +DEBUG_OPT = ON +SANITIZE_OPT = OFF + +.PHONY: check build test clean run coverage + +# Изменения в CMakeLists требует make build +# make build = cmake && cmake --build +build: clean + mkdir ${BUILD_DIR} + cd ${BUILD_DIR} && cmake .. -DTEST_OPT=${TEST_OPT} -DDEBUG_OPT=${DEBUG_OPT} -DSANITIZE_OPT=${SANITIZE_OPT} && $(MAKE) --no-print-directory + +clean: + (rm -r ${BUILD_DIR} 2>/dev/null) || exit 0 + +# инкрементальная сборка и запуск исполняемого файла +run: + cd ${BUILD_DIR} && $(MAKE) --no-print-directory + ./${BUILD_DIR}/${TARGET_EXE} + +# запуск исполняемого файла с тестированием +test: + ./${BUILD_DIR}/${TESTS_DIR}/${TESTS_EXE} + +# проверка исходного кода +check: + chmod u+x ${PATH_LINTERS_SCRIPT} && ./${PATH_LINTERS_SCRIPT} + +coverage: + cd ${BUILD_DIR} && lcov -t "testing_${LIB_DIR}" -o coverage.info -c -d ${LIB_DIR} && genhtml -o report coverage.info + +valgrind_tests: + valgrind --tool=memcheck --leak-check=yes --error-exitcode=1 ./${BUILD_DIR}/${TESTS_DIR}/${TESTS_EXE} + +valgrind_target: + valgrind --tool=memcheck --leak-check=yes --error-exitcode=1 ./${BUILD_DIR}/${TARGET_EXE} + +scan_build: + cd ${BUILD_DIR} && scan-build $(MAKE) --no-print-directory + +formating: + clang-format -i -style=file main.cpp ${LIB_DIR}/include/*.h ${LIB_DIR}/src/*.cpp ${TESTS_DIR}/*.cpp + + +# clang-format -i -style="{BasedOnStyle: Microsoft, IndentWidth: 4, UseTab: Always, AccessModifierOffset: 0}" main.cpp ${LIB_DIR}/include/*.h ${LIB_DIR}/src/*.cpp ${TESTS_DIR}/*.cpp diff --git a/linters/run.sh b/linters/run.sh new file mode 100644 index 0000000..310f9b4 --- /dev/null +++ b/linters/run.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +set -o pipefail + +SRC_PATHS="main.cpp set_lib/src/*.cpp" +INCLUDE_PATHS="set_lib/include/*.h" +TESTS_PATHS="tests/*.cpp" + +INCLUDE_DIRECTORIES="set_lib/include" + +function print_header() { + echo -e "\n***** ${1} *****" +} + +function check_log() { + LOG=$( { ${1}; } 2>&1 ) + STATUS=$? + echo "$LOG" + if echo "$LOG" | grep -q -E "${2}" + then + exit 1 + fi + + if [ $STATUS -ne 0 ] + then + exit $STATUS + fi +} + +# ********** cppcheck ********** +print_header "RUN cppcheck" +check_log "cppcheck ${SRC_PATHS} ${INCLUDE_PATHS} ${TESTS_PATHS} --enable=all --inconclusive --error-exitcode=1 -I${INCLUDE_DIRECTORIES} --suppress=missingIncludeSystem" "\(information\)" + +# # ********** clang-tidy ********** +print_header "RUN clang-tidy" +check_log "clang-tidy ${SRC_PATHS} ${TESTS_PATHS} -warnings-as-errors=* -extra-arg=-std=c++17 -- -I${INCLUDE_DIRECTORIES} -x c++" "Error (?:reading|while processing)" + + +# # ********** cpplint ********** +print_header "RUN cpplint" +check_log "cpplint --extensions=cpp ${SRC_PATHS} ${TESTS_PATHS}" "Can't open for reading" +check_log "cpplint --extensions=h ${INCLUDE_PATHS}" "Can't open for reading" + + +# # ********** clang-format ********** +print_header "RUN clang-format" +diff <(clang-format --style=Microsoft ${SRC_PATHS} ${INCLUDE_PATHS} ${TESTS_PATHS}) <(cat ${SRC_PATHS} ${INCLUDE_PATHS} ${TESTS_PATHS}) || exit 1 + +print_header "SUCCESS" \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..bb65e6a --- /dev/null +++ b/main.cpp @@ -0,0 +1,29 @@ +#include "set.h" + +int main(int argc, const char * argv[]) { + Set set; + + char op; + std::string data; + while (std::cin >> op >> data) + { + switch (op) + { + case '+': + { + set.Insert(data); + break; + } + case '-': + { + set.Erase(data); + break; + } + case '?': + { + std::cout << (set.Has(data) ? "YES" : "NO") << std::endl; + } + } + } + return 0; +} \ No newline at end of file diff --git a/set_lib/CMakeLists.txt b/set_lib/CMakeLists.txt new file mode 100644 index 0000000..ec89a52 --- /dev/null +++ b/set_lib/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.0.0) +project(set_lib) + +set(CMAKE_CXX_STANDARD 17) +# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror") +find_package(Threads REQUIRED) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + +if(TEST_OPT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fPIC -O0") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) +elseif(DEBUG_OPT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fPIC -O0") +else() + # релиз-версия + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -O3") +endif() + +if(SANITIZE_OPT) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined" ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined") +endif() + +file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) +file(GLOB INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_library(${PROJECT_NAME} ${SOURCES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIRS}) + +message("SOURCES = ${SOURCES}") +message("INCLUDE_DIRS = ${INCLUDE_DIRS}") + +set(SET_LIB_LIBRARIES ${PROJECT_NAME} PARENT_SCOPE) +set(SET_LIB_INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE) diff --git a/set_lib/include/set.h b/set_lib/include/set.h new file mode 100644 index 0000000..a416002 --- /dev/null +++ b/set_lib/include/set.h @@ -0,0 +1,49 @@ +#pragma once +#include + +template +class Set +{ + struct Node + { + Node(const T &data) + : data(data), height(1), left(nullptr), right(nullptr) + { + } + + T data; + size_t height; + Node* left; + Node* right; + }; + +public: + Set(); + ~Set(); + void Insert(const T &data); + bool Has(const T &data) const; + void Erase(const T &data); + +private: + Node* m_root; + + void destroyTree(Node *node); + + Node* eraseInternal(Node *node, const T &data); + Node* insertInternal(Node *node, const T &data); + Node* removeMin(Node *node); + Node* findMin(Node *node); + + Node* rotateLeft(Node *node); + Node* rotateRight(Node *node); + + size_t getHeight(Node *node); + void fixHeight(Node *node); + + int getBalance(Node *node); + Node* doBalance(Node *node); + +}; + +#include "set_definition.h" + diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h new file mode 100644 index 0000000..79b7ffd --- /dev/null +++ b/set_lib/include/set_definition.h @@ -0,0 +1,189 @@ +#pragma once + +#include "set.h" + +template +Set::Set() : m_root(nullptr) +{ +} + +template +Set::~Set() +{ + destroyTree(m_root); +} + +template +void Set::Insert(const T &data) +{ + m_root = insertInternal(m_root, data); +} + +template +bool Set::Has(const T &data) const +{ + Node *tmp = m_root; + while (tmp) + { + if (tmp->data == data) + { + return true; + } + else if (tmp->data < data) + { + tmp = tmp->right; + } + else + { + tmp = tmp->left; + } + } + return false; +} + +template +void Set::Erase(const T &data) +{ + m_root = eraseInternal(m_root, data); +} + +template +void Set::destroyTree(Node *node) +{ + if (node) + { + destroyTree(node->left); + destroyTree(node->right); + delete node; + } +} + +template +typename Set::Node* Set::eraseInternal(Node *node, const T &data) +{ + if (!node) + return nullptr; + if (node->data < data) + { + node->right = eraseInternal(node->right, data); + } + else if (node->data > data) + { + node->left = eraseInternal(node->left, data); + } + else + { + Node *left = node->left; + Node *right = node->right; + + delete node; + + if (!right) + return left; + + Node *min = findMin(right); + min->right = removeMin(right); + min->left = left; + + return doBalance(min); + } + return doBalance(node); +} + +template +typename Set::Node* Set::findMin(Node *node) +{ + while (node->left) + node = node->left; + return node; +} + +template +typename Set::Node* Set::removeMin(Node *node) +{ + if (!node->left) + return node->right; + node->left = removeMin(node->left); + return doBalance(node); +} + +template +typename Set::Node* Set::insertInternal(Node *node, const T &data) +{ + if (!node) + return new Node(data); + if (node->data <= data) + { + node->right = insertInternal(node->right, data); + } + else + { + node->left = insertInternal(node->left, data); + } + return doBalance(node); +} + +template +size_t Set::getHeight(Node *node) +{ + return node ? node->height : 0; +} + +template +void Set::fixHeight(Node *node) +{ + node->height = std::max(getHeight(node->left), getHeight(node->right)) + 1; +} + +template +typename Set::Node* Set::rotateLeft(Node *node) +{ + Node *tmp = node->right; + node->right = tmp->left; + tmp->left = node; + fixHeight(node); + fixHeight(tmp); + return tmp; +} + +template +typename Set::Node* Set::rotateRight(Node *node) +{ + Node *tmp = node->left; + node->left = tmp->right; + tmp->right = node; + fixHeight(node); + fixHeight(tmp); + return tmp; +} + +template +int Set::getBalance(Node *node) +{ + return getHeight(node->right) - getHeight(node->left); +} + +template +typename Set::Node* Set::doBalance(Node *node) +{ + fixHeight(node); + + switch (getBalance(node)) + { + case 2: + { + if (getBalance(node->right) < 0) + node->right = rotateRight(node->right); + return rotateLeft(node); + } + case -2: + { + if (getBalance(node->left) > 0) + node->left = rotateLeft(node->left); + return rotateRight(node); + } + default: + return node; + } +} + diff --git a/set_lib/src/set.cpp b/set_lib/src/set.cpp new file mode 100644 index 0000000..baa38ab --- /dev/null +++ b/set_lib/src/set.cpp @@ -0,0 +1,2 @@ +#include "set.h" + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..29ecc96 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0.0) +project(test_set) + +set(CMAKE_CXX_STANDARD 17) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) + + +file(GLOB SOURCES *.cpp) + +find_package(GTest REQUIRED) + +add_executable(${PROJECT_NAME} ${SOURCES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${SET_LIB_INCLUDE_DIRS}) + +target_link_libraries(${PROJECT_NAME} ${SET_LIB_LIBRARIES} GTest::GTest gtest_main) + +gtest_discover_tests(${PROJECT_NAME}) diff --git a/tests/test_set.cpp b/tests/test_set.cpp new file mode 100644 index 0000000..40610ef --- /dev/null +++ b/tests/test_set.cpp @@ -0,0 +1,7 @@ +#include + + +TEST(Fib, TestBasics) +{ + EXPECT_TRUE(true); +} \ No newline at end of file From f4c102cf54a6bd0d581c6054508cfb1127855a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 19 Nov 2022 10:46:52 +0300 Subject: [PATCH 03/20] smart ptr, one simple test, comparator --- .gitignore | 1 + main.cpp | 2 +- set_lib/include/set.h | 36 ++++---- set_lib/include/set_definition.h | 139 +++++++++++++++++-------------- tests/test_set.cpp | 43 +++++++++- 5 files changed, 140 insertions(+), 81 deletions(-) diff --git a/.gitignore b/.gitignore index 046c078..a1afa60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /build /.vscode +test.cpp diff --git a/main.cpp b/main.cpp index bb65e6a..2687b02 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,7 @@ #include "set.h" int main(int argc, const char * argv[]) { - Set set; + Set> set; char op; std::string data; diff --git a/set_lib/include/set.h b/set_lib/include/set.h index a416002..354fa72 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -1,7 +1,8 @@ #pragma once #include +#include -template +template > class Set { struct Node @@ -13,8 +14,9 @@ class Set T data; size_t height; - Node* left; - Node* right; + std::shared_ptr left; + std::shared_ptr right; + std::shared_ptr parent; }; public: @@ -25,23 +27,25 @@ class Set void Erase(const T &data); private: - Node* m_root; + std::shared_ptr m_root; + Comparator m_cmp; - void destroyTree(Node *node); - - Node* eraseInternal(Node *node, const T &data); - Node* insertInternal(Node *node, const T &data); - Node* removeMin(Node *node); - Node* findMin(Node *node); + std::shared_ptr eraseInternal(std::shared_ptr node, const T &data); + std::shared_ptr insertInternal(std::shared_ptr node, const T &data); + + std::shared_ptr detachReplacement(std::shared_ptr node); + std::shared_ptr findReplacement(std::shared_ptr node) const; - Node* rotateLeft(Node *node); - Node* rotateRight(Node *node); + std::shared_ptr rotateLeft(std::shared_ptr node); + std::shared_ptr rotateRight(std::shared_ptr node); - size_t getHeight(Node *node); - void fixHeight(Node *node); + size_t getHeight(std::shared_ptr node) const; + void fixHeight(std::shared_ptr node); + + int getBalance(std::shared_ptr node) const; + std::shared_ptr doBalance(std::shared_ptr node); - int getBalance(Node *node); - Node* doBalance(Node *node); + std::shared_ptr Next(std::shared_ptr node) const; }; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index 79b7ffd..eba5507 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -1,35 +1,39 @@ #pragma once +#include #include "set.h" -template -Set::Set() : m_root(nullptr) +template +Set::Set() : m_root(nullptr) { } -template -Set::~Set() +template +Set::~Set() { - destroyTree(m_root); } -template -void Set::Insert(const T &data) +template +void Set::Insert(const T &data) { + if (Has(data)) + { + return; + } m_root = insertInternal(m_root, data); } -template -bool Set::Has(const T &data) const +template +bool Set::Has(const T &data) const { - Node *tmp = m_root; + std::shared_ptr tmp = m_root; while (tmp) { if (tmp->data == data) { return true; } - else if (tmp->data < data) + else if (m_cmp(tmp->data, data)) { tmp = tmp->right; } @@ -41,104 +45,103 @@ bool Set::Has(const T &data) const return false; } -template -void Set::Erase(const T &data) +template +void Set::Erase(const T &data) { m_root = eraseInternal(m_root, data); } -template -void Set::destroyTree(Node *node) -{ - if (node) - { - destroyTree(node->left); - destroyTree(node->right); - delete node; - } -} - -template -typename Set::Node* Set::eraseInternal(Node *node, const T &data) +template +std::shared_ptr::Node> Set::eraseInternal(std::shared_ptr node, const T &data) { if (!node) + { return nullptr; - if (node->data < data) + } + if (m_cmp(node->data, data)) { node->right = eraseInternal(node->right, data); } - else if (node->data > data) + else if (m_cmp(data, node->data)) { node->left = eraseInternal(node->left, data); } else { - Node *left = node->left; - Node *right = node->right; - - delete node; + std::shared_ptr left = node->left; + std::shared_ptr right = node->right; if (!right) + { return left; + } - Node *min = findMin(right); - min->right = removeMin(right); - min->left = left; + std::shared_ptr replace = findReplacement(right); + replace->right = detachReplacement(right); + replace->left = left; - return doBalance(min); + return doBalance(replace); } return doBalance(node); } -template -typename Set::Node* Set::findMin(Node *node) +template +std::shared_ptr::Node> Set::findReplacement(std::shared_ptr node) const { while (node->left) + { node = node->left; + } return node; } -template -typename Set::Node* Set::removeMin(Node *node) +template +std::shared_ptr::Node> Set::detachReplacement(std::shared_ptr node) { if (!node->left) + { return node->right; - node->left = removeMin(node->left); + } + node->left = detachReplacement(node->left); return doBalance(node); } -template -typename Set::Node* Set::insertInternal(Node *node, const T &data) +template +std::shared_ptr::Node> Set::insertInternal(std::shared_ptr node, const T &data) { if (!node) - return new Node(data); - if (node->data <= data) + { + return std::make_shared(data); + } + if (m_cmp(data, node->data)) { - node->right = insertInternal(node->right, data); + node->left = insertInternal(node->left, data); + // node->left->parent = node; } - else + else if (m_cmp(node->data, data)) { - node->left = insertInternal(node->left, data); + node->right = insertInternal(node->right, data); + // node->right->parent = node; } return doBalance(node); } -template -size_t Set::getHeight(Node *node) +template +size_t Set::getHeight(std::shared_ptr node) const { return node ? node->height : 0; } -template -void Set::fixHeight(Node *node) +template +void Set::fixHeight(std::shared_ptr node) { node->height = std::max(getHeight(node->left), getHeight(node->right)) + 1; } -template -typename Set::Node* Set::rotateLeft(Node *node) +template +std::shared_ptr::Node> Set::rotateLeft(std::shared_ptr node) { - Node *tmp = node->right; + std::shared_ptr tmp = node->right; node->right = tmp->left; tmp->left = node; fixHeight(node); @@ -146,10 +149,10 @@ typename Set::Node* Set::rotateLeft(Node *node) return tmp; } -template -typename Set::Node* Set::rotateRight(Node *node) +template +std::shared_ptr::Node> Set::rotateRight(std::shared_ptr node) { - Node *tmp = node->left; + std::shared_ptr tmp = node->left; node->left = tmp->right; tmp->right = node; fixHeight(node); @@ -157,14 +160,14 @@ typename Set::Node* Set::rotateRight(Node *node) return tmp; } -template -int Set::getBalance(Node *node) +template +int Set::getBalance(std::shared_ptr node) const { return getHeight(node->right) - getHeight(node->left); } -template -typename Set::Node* Set::doBalance(Node *node) +template +std::shared_ptr::Node> Set::doBalance(std::shared_ptr node) { fixHeight(node); @@ -173,17 +176,29 @@ typename Set::Node* Set::doBalance(Node *node) case 2: { if (getBalance(node->right) < 0) + { node->right = rotateRight(node->right); + } return rotateLeft(node); } case -2: { if (getBalance(node->left) > 0) + { node->left = rotateLeft(node->left); + } return rotateRight(node); } default: + { return node; + } } } +template +std::shared_ptr::Node> Set::Next(std::shared_ptr node) const +{ + +} + diff --git a/tests/test_set.cpp b/tests/test_set.cpp index 40610ef..dcfc94b 100644 --- a/tests/test_set.cpp +++ b/tests/test_set.cpp @@ -1,7 +1,46 @@ #include +#include +#include "set.h" +template +void TestInsertErase(Set &set, std::istream &in) +{ + char op; + T data; + while (in >> op >> data) + { + switch (op) + { + case '+': + { + set.Insert(data); + break; + } + case '-': + { + set.Erase(data); + break; + } + } + } +} -TEST(Fib, TestBasics) +TEST(AvlTree, TestBasicsFunctional) { - EXPECT_TRUE(true); + Set> set; + // fill 1..9, remove odd + std::string strTest = "+ 1 + 1 + 2 + 2 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 - 2 - 4 - 6 - 8 + -20 + 20"; + std::istringstream stream(strTest); + TestInsertErase(set, stream); + EXPECT_TRUE (set.Has(1)); + EXPECT_FALSE(set.Has(2)); + EXPECT_TRUE (set.Has(3)); + EXPECT_FALSE(set.Has(4)); + EXPECT_TRUE (set.Has(5)); + EXPECT_FALSE(set.Has(6)); + EXPECT_TRUE (set.Has(7)); + EXPECT_FALSE(set.Has(8)); + EXPECT_TRUE (set.Has(9)); + EXPECT_TRUE (set.Has(-20)); + EXPECT_TRUE (set.Has(20)); } \ No newline at end of file From 557ef85eae918c3f753450179ccbbfdc5ad3060e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 19 Nov 2022 13:21:25 +0300 Subject: [PATCH 04/20] parent link, next, prev --- main.cpp | 122 +++++++++++++++++++++----- set_lib/include/iterator.h | 5 ++ set_lib/include/set.h | 27 +++++- set_lib/include/set_definition.h | 141 +++++++++++++++++++++++++++++-- 4 files changed, 267 insertions(+), 28 deletions(-) create mode 100644 set_lib/include/iterator.h diff --git a/main.cpp b/main.cpp index 2687b02..e20cd05 100644 --- a/main.cpp +++ b/main.cpp @@ -1,29 +1,113 @@ #include "set.h" -int main(int argc, const char * argv[]) { - Set> set; - - char op; - std::string data; - while (std::cin >> op >> data) +void lolFunc(Set &set) +{ + auto it1 = set.end(); + // std::cout << "lolFunc it1 = " << it1 << std::endl; + if (it1) + { + std::cout << "it1 " << it1->data << "\n"; + } + auto it2 = set.PrevInternal(it1); + // std::cout << "lolFunc it2 = " << it2 << std::endl; + if (it2) { - switch (op) + std::cout << "it2 " << it2->data << "\n"; + auto it3 = set.PrevInternal(it2); + if (it3) { - case '+': - { - set.Insert(data); - break; - } - case '-': + std::cout << "it3 " << it3->data << "\n"; + auto it4 = set.PrevInternal(it3); + if (it4) { - set.Erase(data); - break; - } - case '?': - { - std::cout << (set.Has(data) ? "YES" : "NO") << std::endl; + std::cout << "it4 " << it4->data << "\n"; + auto it5 = set.PrevInternal(it4); + if (it5) + { + std::cout << "it5 " << it5->data << "\n"; + auto it6 = set.PrevInternal(it5); + if (it6) + { + std::cout << "it6 " << it6->data << "\n"; + } + } } } } +} + +int main(int argc, const char * argv[]) { + Set set; + set.Insert(7); + set.Insert(8); + set.Insert(9); + set.Insert(10); + set.Insert(11); + set.Insert(12); + set.Erase(10); + + for (auto it = set.begin(); it != set.end(); it = set.NextInternal(it)) + { + std::cout << it->data << " "; + } + + // set.Erase(8); + // puts("----------"); + // lolFunc(set); + + // puts("----------"); + // set.Erase(10); + // lolFunc(set); + + // puts("----------"); + // set.Erase(11); + // lolFunc(set); + + // puts("----------"); + // set.Erase(7); + // lolFunc(set); + + + // puts("----------"); + // set.Erase(9); + // lolFunc(set); + + // puts("----------"); + // std::cout << "до 12" << std::endl; + // set.Erase(12); + // std::cout << "после 12" << std::endl; + // lolFunc(set); + + // puts("----------"); + // std::cout << "до ----" << std::endl; + // std::cout.flush(); + // set.Erase(11); + // std::cout << "после ---" << std::endl; + // std::cout.flush(); + + // lolFunc(set); + + // char op; + // int data; + // while (std::cin >> op >> data) + // { + // switch (op) + // { + // case '+': + // { + // set.Insert(data); + // break; + // } + // case '-': + // { + // set.Erase(data); + // break; + // } + // case '?': + // { + // std::cout << (set.Has(data) ? "YES" : "NO") << std::endl; + // } + // } + // } return 0; } \ No newline at end of file diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h new file mode 100644 index 0000000..81cb87a --- /dev/null +++ b/set_lib/include/iterator.h @@ -0,0 +1,5 @@ +template +class Iterator +{ + +}; \ No newline at end of file diff --git a/set_lib/include/set.h b/set_lib/include/set.h index 354fa72..ef58f25 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -1,14 +1,17 @@ #pragma once + #include #include +#include "iterator.h" + template > class Set { struct Node { Node(const T &data) - : data(data), height(1), left(nullptr), right(nullptr) + : data(data), height(1), left(nullptr), right(nullptr), parent(nullptr) { } @@ -20,15 +23,35 @@ class Set }; public: + + using key_type = T; + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = T&; + using const_reference = const T&; + using iterator = Iterator; + // using const_iterator = + // using reverse_iterator = + // using const_reverse_iterator = + + + Set(); ~Set(); void Insert(const T &data); bool Has(const T &data) const; void Erase(const T &data); + std::shared_ptr begin() const; + std::shared_ptr end() const; + + std::shared_ptr NextInternal(std::shared_ptr node) const; + std::shared_ptr PrevInternal(std::shared_ptr node) const; private: std::shared_ptr m_root; Comparator m_cmp; + friend class Iterator; std::shared_ptr eraseInternal(std::shared_ptr node, const T &data); std::shared_ptr insertInternal(std::shared_ptr node, const T &data); @@ -44,8 +67,6 @@ class Set int getBalance(std::shared_ptr node) const; std::shared_ptr doBalance(std::shared_ptr node); - - std::shared_ptr Next(std::shared_ptr node) const; }; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index eba5507..4275b2d 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -61,10 +61,18 @@ std::shared_ptr::Node> Set::eraseInte if (m_cmp(node->data, data)) { node->right = eraseInternal(node->right, data); + if (node->right) + { + node->right->parent = node; + } } else if (m_cmp(data, node->data)) { node->left = eraseInternal(node->left, data); + if (node->left) + { + node->right->parent = node; + } } else { @@ -78,7 +86,16 @@ std::shared_ptr::Node> Set::eraseInte std::shared_ptr replace = findReplacement(right); replace->right = detachReplacement(right); + if (replace->right) + { + replace->right->parent = replace; + } replace->left = left; + if (replace->left) + { + replace->left->parent = replace; + } + replace->parent = node->parent; // на выходе из рекурсии редактируем parent return doBalance(replace); } @@ -103,6 +120,10 @@ std::shared_ptr::Node> Set::detachRep return node->right; } node->left = detachReplacement(node->left); + if (node->left) + { + node->left->parent = node; + } return doBalance(node); } @@ -116,13 +137,30 @@ std::shared_ptr::Node> Set::insertInt if (m_cmp(data, node->data)) { node->left = insertInternal(node->left, data); - // node->left->parent = node; + // nullptr не возвращается, т.к. вставка обязательна + node->left->parent = node; } else if (m_cmp(node->data, data)) { node->right = insertInternal(node->right, data); - // node->right->parent = node; + node->right->parent = node; } + // if (node->left) + // { + // std::cout << "node->left->data : " << node->left->data<< "\n"; + // std::cout << "node->left->parent : " << node->left->parent << "\n"; + // std::cout << "node->left->parent->data : " << node->left->parent->data << "\n"; + // } + // if (node->right) + // { + // std::cout << "node->right->data : " << node->right->data<< "\n"; + // std::cout << "node->right->parent : " << node->right->parent << "\n"; + // std::cout << "node->right->parent->data : " << node->right->parent->data << "\n"; + // } + // std::cout << "node : " << node->data << "\n"; + // std::cout << "left : " << node->left << "\n"; + // std::cout << "right : " << node->right << "\n"; + // std::cout << "paren : " << node->parent << "\n"; return doBalance(node); } @@ -143,7 +181,13 @@ std::shared_ptr::Node> Set::rotateLef { std::shared_ptr tmp = node->right; node->right = tmp->left; + if (tmp->left) + { + tmp->left->parent = node; + } tmp->left = node; + tmp->parent = node->parent; + node->parent = tmp; fixHeight(node); fixHeight(tmp); return tmp; @@ -152,9 +196,18 @@ std::shared_ptr::Node> Set::rotateLef template std::shared_ptr::Node> Set::rotateRight(std::shared_ptr node) { + // node = a + // tmp = node->left = b std::shared_ptr tmp = node->left; - node->left = tmp->right; - tmp->right = node; + node->left = tmp->right; // теперь a->left = C + if (tmp->right) + { + tmp->right->parent = node; + } + tmp->right = node; // теперь b->right = a + tmp->parent = node->parent; + node->parent = tmp; + fixHeight(node); fixHeight(tmp); return tmp; @@ -197,8 +250,84 @@ std::shared_ptr::Node> Set::doBalance } template -std::shared_ptr::Node> Set::Next(std::shared_ptr node) const +std::shared_ptr::Node> Set::NextInternal(std::shared_ptr node) const { - + if (!node) + { + return nullptr; + } + if (node->right) + { + node = node->right; + while (node->left) + { + node = node->left; + } + return node; + } + else + { + std::shared_ptr needed_parent = node->parent; + while (needed_parent && needed_parent->left != node) + { + node = needed_parent; + needed_parent = node->parent; + } + return needed_parent; + } +} + +template +std::shared_ptr::Node> Set::PrevInternal(std::shared_ptr node) const +{ + if (node == end()) + { + std::shared_ptr node = m_root; + while (node->right) + { + node = node->right; + } + return node; + } + if (node->left) + { + node = node->left; + while (node->right) + { + node = node->right; + } + return node; + } + else + { + std::shared_ptr needed_parent = node->parent; + while (needed_parent && needed_parent->right != node) + { + node = needed_parent; + needed_parent = node->parent; + } + return needed_parent; + } +} + +template +std::shared_ptr::Node> Set::begin() const +{ + if (!m_root) + { + return nullptr; + } + std::shared_ptr node = m_root; + while (node->left) + { + node = node->left; + } + return node; +} + +template +std::shared_ptr::Node> Set::end() const +{ + return nullptr; } From b149256b02bf486dcc6123314a01eb546279288e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 19 Nov 2022 17:04:04 +0300 Subject: [PATCH 05/20] merory leak --- Makefile | 2 +- main.cpp | 32 ++++++- set_lib/include/iterator.h | 2 +- set_lib/include/set.h | 4 +- set_lib/include/set_definition.h | 155 +++++++++++++++++++++++++++++++ 5 files changed, 191 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 9f44590..e87074e 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ valgrind_tests: valgrind --tool=memcheck --leak-check=yes --error-exitcode=1 ./${BUILD_DIR}/${TESTS_DIR}/${TESTS_EXE} valgrind_target: - valgrind --tool=memcheck --leak-check=yes --error-exitcode=1 ./${BUILD_DIR}/${TARGET_EXE} + valgrind --tool=memcheck -s --leak-check=yes --error-exitcode=1 ./${BUILD_DIR}/${TARGET_EXE} scan_build: cd ${BUILD_DIR} && scan-build $(MAKE) --no-print-directory diff --git a/main.cpp b/main.cpp index e20cd05..38b090c 100644 --- a/main.cpp +++ b/main.cpp @@ -44,9 +44,39 @@ int main(int argc, const char * argv[]) { set.Insert(10); set.Insert(11); set.Insert(12); + set.Insert(13); + set.Insert(14); + set.Insert(15); + set.Insert(16); + set.Insert(17); + set.Insert(18); + set.Insert(19); + set.Insert(20); + + // for (auto it = set.begin(); it != set.end(); it = set.NextInternal(it)) + // { + // std::cout << it->data << " "; + // } + + for (auto it = set.begin(); it != set.end(); it = it->Next()) + { + std::cout << it->data << " "; + } + set.Erase(10); + std::cout << "\n"; + + for (auto it = set.begin(); it != set.end(); it = it->Next()) + { + std::cout << it->data << " "; + } + + set.Erase(7); + set.Erase(12); + set.Erase(8); + std::cout << "\n"; - for (auto it = set.begin(); it != set.end(); it = set.NextInternal(it)) + for (auto it = set.begin(); it != set.end(); it = it->Next()) { std::cout << it->data << " "; } diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index 81cb87a..94e6db8 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -1,5 +1,5 @@ template class Iterator { - + }; \ No newline at end of file diff --git a/set_lib/include/set.h b/set_lib/include/set.h index ef58f25..c4a4802 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -11,9 +11,11 @@ class Set struct Node { Node(const T &data) - : data(data), height(1), left(nullptr), right(nullptr), parent(nullptr) + : data(data), height(1) { } + std::shared_ptr Next(); + // std::shared_ptr Prev(); T data; size_t height; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index 4275b2d..e1a7e1d 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -331,3 +331,158 @@ std::shared_ptr::Node> Set::end() con return nullptr; } +// template +// void Set::Node::Next() +// { +// if (right) +// { +// while (left) +// { +// Node *this_node = left.get(); +// this = this_node; +// // right = left->right; +// // left = left->left; +// // parent.reset(this); +// } +// } +// else +// { +// while (parent && parent->left.get() != this) +// { +// Node *this_node = parent.get(); +// this = this_node; +// // this = parent.get(); +// } +// Node *this_node = parent.get(); +// this = this_node; +// // this = parent.get(); +// } +// } + +// template +// void Set::Node::Next() +// { +// if (right) +// { +// while (left) +// { +// // this = left.get(); +// right = left->right; +// left = left->left; +// parent.reset(this); +// } +// } +// else +// { +// while (parent && parent->left.get() != this) +// { +// left = parent->left; +// right = parent->right; +// parent = parent->parent; +// // this = parent.get(); +// } +// if (parent) +// { +// left = parent->left; +// right = parent->right; +// parent = parent->parent; +// } +// else +// { +// left = right = parent = nullptr; +// } +// } +// } + +// template +// std::shared_ptr::Node> Set::Node::Next() +// { +// Node *node = this; +// if (node->right) +// { +// node = node->right.get(); +// while (node->left) +// { +// node = node->left.get(); +// } +// return std::make_shared(*node); +// // return std::shared_ptr(node); +// } +// else +// { +// std::shared_ptr needed_parent = node->parent; +// while (needed_parent && needed_parent->left.get() != node) +// { +// node = needed_parent.get(); +// needed_parent = needed_parent->parent; +// } +// return needed_parent; +// } +// } + +template +std::shared_ptr::Node> Set::Node::Next() +{ + std::shared_ptr node; + if (right) + { + node = right; + // if (node->right) + // { + // node = node->right.get(); + while (node->left) + { + node = node->left; + } + return node; + // return std::make_shared(*node); + // return std::shared_ptr(node); + } + else + { + if (!parent) + { + return nullptr; + } + else + { + node = parent; + if (node->left.get() == this) + { + return node; + } + } + // std::shared_ptr child = node->parent; + std::shared_ptr needed_parent = node->parent; + while (needed_parent && needed_parent->left != node) + { + node = needed_parent; + needed_parent = needed_parent->parent; + } + return needed_parent; + } +} + +// template +// void Set::Node::Prev() const +// { +// if (left) +// { +// while (right) +// { +// this = right.get(); +// // right = left->right; +// // left = left->left; +// // parent.reset(this); +// } +// } +// else +// { +// while (parent && parent->right.get() != this) +// { +// this = parent.get(); +// } +// this = parent.get(); +// } +// } + From 37fa3f42372e5e2b89ecdd2d02cbaa3b112ef226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 19 Nov 2022 17:25:57 +0300 Subject: [PATCH 06/20] merory leak --- set_lib/include/iterator.h | 6 +- set_lib/include/set.h | 8 +- set_lib/include/set_definition.h | 235 ++++++------------------------- 3 files changed, 51 insertions(+), 198 deletions(-) diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index 94e6db8..b925ab1 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -1,5 +1,9 @@ +#include "set.h" + template class Iterator { - + +private: + std::shared_ptr::Node> node; }; \ No newline at end of file diff --git a/set_lib/include/set.h b/set_lib/include/set.h index c4a4802..e4ecc89 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -15,13 +15,14 @@ class Set { } std::shared_ptr Next(); - // std::shared_ptr Prev(); + std::shared_ptr Prev(); T data; size_t height; std::shared_ptr left; std::shared_ptr right; std::shared_ptr parent; + friend class Iterator; }; public: @@ -47,13 +48,10 @@ class Set std::shared_ptr begin() const; std::shared_ptr end() const; - std::shared_ptr NextInternal(std::shared_ptr node) const; - std::shared_ptr PrevInternal(std::shared_ptr node) const; - private: std::shared_ptr m_root; Comparator m_cmp; - friend class Iterator; + // friend class Iterator; std::shared_ptr eraseInternal(std::shared_ptr node, const T &data); std::shared_ptr insertInternal(std::shared_ptr node, const T &data); diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index e1a7e1d..d9aa944 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include "set.h" @@ -145,22 +146,7 @@ std::shared_ptr::Node> Set::insertInt node->right = insertInternal(node->right, data); node->right->parent = node; } - // if (node->left) - // { - // std::cout << "node->left->data : " << node->left->data<< "\n"; - // std::cout << "node->left->parent : " << node->left->parent << "\n"; - // std::cout << "node->left->parent->data : " << node->left->parent->data << "\n"; - // } - // if (node->right) - // { - // std::cout << "node->right->data : " << node->right->data<< "\n"; - // std::cout << "node->right->parent : " << node->right->parent << "\n"; - // std::cout << "node->right->parent->data : " << node->right->parent->data << "\n"; - // } - // std::cout << "node : " << node->data << "\n"; - // std::cout << "left : " << node->left << "\n"; - // std::cout << "right : " << node->right << "\n"; - // std::cout << "paren : " << node->parent << "\n"; + return doBalance(node); } @@ -249,66 +235,6 @@ std::shared_ptr::Node> Set::doBalance } } -template -std::shared_ptr::Node> Set::NextInternal(std::shared_ptr node) const -{ - if (!node) - { - return nullptr; - } - if (node->right) - { - node = node->right; - while (node->left) - { - node = node->left; - } - return node; - } - else - { - std::shared_ptr needed_parent = node->parent; - while (needed_parent && needed_parent->left != node) - { - node = needed_parent; - needed_parent = node->parent; - } - return needed_parent; - } -} - -template -std::shared_ptr::Node> Set::PrevInternal(std::shared_ptr node) const -{ - if (node == end()) - { - std::shared_ptr node = m_root; - while (node->right) - { - node = node->right; - } - return node; - } - if (node->left) - { - node = node->left; - while (node->right) - { - node = node->right; - } - return node; - } - else - { - std::shared_ptr needed_parent = node->parent; - while (needed_parent && needed_parent->right != node) - { - node = needed_parent; - needed_parent = node->parent; - } - return needed_parent; - } -} template std::shared_ptr::Node> Set::begin() const @@ -331,115 +257,24 @@ std::shared_ptr::Node> Set::end() con return nullptr; } -// template -// void Set::Node::Next() -// { -// if (right) -// { -// while (left) -// { -// Node *this_node = left.get(); -// this = this_node; -// // right = left->right; -// // left = left->left; -// // parent.reset(this); -// } -// } -// else -// { -// while (parent && parent->left.get() != this) -// { -// Node *this_node = parent.get(); -// this = this_node; -// // this = parent.get(); -// } -// Node *this_node = parent.get(); -// this = this_node; -// // this = parent.get(); -// } -// } - -// template -// void Set::Node::Next() -// { -// if (right) -// { -// while (left) -// { -// // this = left.get(); -// right = left->right; -// left = left->left; -// parent.reset(this); -// } -// } -// else -// { -// while (parent && parent->left.get() != this) -// { -// left = parent->left; -// right = parent->right; -// parent = parent->parent; -// // this = parent.get(); -// } -// if (parent) -// { -// left = parent->left; -// right = parent->right; -// parent = parent->parent; -// } -// else -// { -// left = right = parent = nullptr; -// } -// } -// } - -// template -// std::shared_ptr::Node> Set::Node::Next() -// { -// Node *node = this; -// if (node->right) -// { -// node = node->right.get(); -// while (node->left) -// { -// node = node->left.get(); -// } -// return std::make_shared(*node); -// // return std::shared_ptr(node); -// } -// else -// { -// std::shared_ptr needed_parent = node->parent; -// while (needed_parent && needed_parent->left.get() != node) -// { -// node = needed_parent.get(); -// needed_parent = needed_parent->parent; -// } -// return needed_parent; -// } -// } template std::shared_ptr::Node> Set::Node::Next() { std::shared_ptr node; + // вправо и влево до упора if (right) { node = right; - // if (node->right) - // { - // node = node->right.get(); while (node->left) { node = node->left; } return node; - // return std::make_shared(*node); - // return std::shared_ptr(node); } else { + // вверх до того родителя, у которого левым потоком являемся мы if (!parent) { return nullptr; @@ -452,7 +287,6 @@ std::shared_ptr::Node> Set::Node::Nex return node; } } - // std::shared_ptr child = node->parent; std::shared_ptr needed_parent = node->parent; while (needed_parent && needed_parent->left != node) { @@ -463,26 +297,43 @@ std::shared_ptr::Node> Set::Node::Nex } } -// template -// void Set::Node::Prev() const -// { -// if (left) -// { -// while (right) -// { -// this = right.get(); -// // right = left->right; -// // left = left->left; -// // parent.reset(this); -// } -// } -// else -// { -// while (parent && parent->right.get() != this) -// { -// this = parent.get(); -// } -// this = parent.get(); -// } -// } +template +std::shared_ptr::Node> Set::Node::Prev() +{ + std::shared_ptr node; + // влево и вправо до упора + if (left) + { + node = left; + while (node->right) + { + node = node->right; + } + return node; + } + else + { + // вверх до того родителя, у которого правым потоком являемся мы + if (!parent) + { + return nullptr; + } + else + { + node = parent; + if (node->right.get() == this) + { + return node; + } + } + std::shared_ptr needed_parent = node->parent; + while (needed_parent && needed_parent->right != node) + { + node = needed_parent; + needed_parent = needed_parent->parent; + } + return needed_parent; + } +} + From 6116112e82cdba524fb360c3384963869b53fb93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 19 Nov 2022 21:56:01 +0300 Subject: [PATCH 07/20] mini refactor --- main.cpp | 142 ++++---------------------- set_lib/include/iterator.h | 37 ++++++- set_lib/include/iterator_definition.h | 63 ++++++++++++ set_lib/include/set.h | 65 ++++++------ set_lib/include/set_definition.h | 49 ++++++--- 5 files changed, 189 insertions(+), 167 deletions(-) create mode 100644 set_lib/include/iterator_definition.h diff --git a/main.cpp b/main.cpp index 38b090c..4e7c120 100644 --- a/main.cpp +++ b/main.cpp @@ -1,143 +1,43 @@ #include "set.h" +#include "iterator.h" -void lolFunc(Set &set) +int main(int argc, const char * argv[]) { - auto it1 = set.end(); - // std::cout << "lolFunc it1 = " << it1 << std::endl; - if (it1) - { - std::cout << "it1 " << it1->data << "\n"; - } - auto it2 = set.PrevInternal(it1); - // std::cout << "lolFunc it2 = " << it2 << std::endl; - if (it2) - { - std::cout << "it2 " << it2->data << "\n"; - auto it3 = set.PrevInternal(it2); - if (it3) - { - std::cout << "it3 " << it3->data << "\n"; - auto it4 = set.PrevInternal(it3); - if (it4) - { - std::cout << "it4 " << it4->data << "\n"; - auto it5 = set.PrevInternal(it4); - if (it5) - { - std::cout << "it5 " << it5->data << "\n"; - auto it6 = set.PrevInternal(it5); - if (it6) - { - std::cout << "it6 " << it6->data << "\n"; - } - } - } - } - } -} - -int main(int argc, const char * argv[]) { Set set; set.Insert(7); set.Insert(8); set.Insert(9); set.Insert(10); set.Insert(11); - set.Insert(12); - set.Insert(13); - set.Insert(14); - set.Insert(15); - set.Insert(16); - set.Insert(17); - set.Insert(18); - set.Insert(19); - set.Insert(20); - // for (auto it = set.begin(); it != set.end(); it = set.NextInternal(it)) - // { - // std::cout << it->data << " "; - // } - for (auto it = set.begin(); it != set.end(); it = it->Next()) - { - std::cout << it->data << " "; - } - - set.Erase(10); - std::cout << "\n"; - for (auto it = set.begin(); it != set.end(); it = it->Next()) + for (auto elem : set) { - std::cout << it->data << " "; + std::cout << elem << " "; } + std::cout << "size = " << set.size() << "\n"; + set.Erase(7); - set.Erase(12); - set.Erase(8); - std::cout << "\n"; + set.Erase(11); - for (auto it = set.begin(); it != set.end(); it = it->Next()) + std::cout << "size = " << set.size() << "\n"; + + std::cout << "\n"; + for (auto it = set.begin(); it != set.end(); it++) { - std::cout << it->data << " "; + std::cout << *it << " "; } - // set.Erase(8); - // puts("----------"); - // lolFunc(set); - - // puts("----------"); - // set.Erase(10); - // lolFunc(set); - - // puts("----------"); - // set.Erase(11); - // lolFunc(set); - - // puts("----------"); - // set.Erase(7); - // lolFunc(set); - - - // puts("----------"); - // set.Erase(9); - // lolFunc(set); - - // puts("----------"); - // std::cout << "до 12" << std::endl; - // set.Erase(12); - // std::cout << "после 12" << std::endl; - // lolFunc(set); - - // puts("----------"); - // std::cout << "до ----" << std::endl; - // std::cout.flush(); - // set.Erase(11); - // std::cout << "после ---" << std::endl; - // std::cout.flush(); - - // lolFunc(set); - - // char op; - // int data; - // while (std::cin >> op >> data) - // { - // switch (op) - // { - // case '+': - // { - // set.Insert(data); - // break; - // } - // case '-': - // { - // set.Erase(data); - // break; - // } - // case '?': - // { - // std::cout << (set.Has(data) ? "YES" : "NO") << std::endl; - // } - // } - // } + puts("\n\n0"); + auto start = --set.end(); + puts("1"); + auto end = --set.begin(); + puts("2"); + for (; start != end; start--) + { + std::cout << *start << " "; + } return 0; } \ No newline at end of file diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index b925ab1..4b8de55 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -1,9 +1,40 @@ #include "set.h" +#pragma once -template +template class Iterator { +public: + using key_type = T; + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using key_compare = Comparator; + using value_compare = Comparator; + using reference = T&; + using const_reference = const T&; + using pointer = T*; + using const_pointer = const T*; + using iterator_category = std::bidirectional_iterator_tag; + Iterator() = default; + Iterator(std::shared_ptr::Node> node); + Iterator(const Iterator &) = default; + + Iterator& operator=(const Iterator &) = default; + + Iterator& operator++(); + Iterator operator++(int); + Iterator& operator--(); + Iterator operator--(int); + + const_reference operator*(); + const_pointer operator->(); + + bool operator==(const Iterator &); + bool operator!=(const Iterator &); private: - std::shared_ptr::Node> node; -}; \ No newline at end of file + std::shared_ptr::Node> node; +}; + +#include "iterator_definition.h" \ No newline at end of file diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h new file mode 100644 index 0000000..4b00111 --- /dev/null +++ b/set_lib/include/iterator_definition.h @@ -0,0 +1,63 @@ +#include "iterator.h" +#pragma once + + +template +Iterator::Iterator(std::shared_ptr::Node> node) : node(node) +{ +} + +template +Iterator& Iterator::operator++() +{ + node = node->Next(); + return *this; +} + +template +Iterator Iterator::operator++(int) +{ + Iterator tmp(*this); + operator++(); + return tmp; +} + +template +Iterator& Iterator::operator--() +{ + node = node->Prev(); + return *this; +} + +template +Iterator Iterator::operator--(int) +{ + Iterator tmp(*this); + operator--(); + return tmp; +} + +template +const T& Iterator::operator*() +{ + return node->data; +} + +template +const T* Iterator::operator->() +{ + return &(node->data); +} + +template +bool Iterator::operator==(const Iterator &other) +{ + return node == other.node; +} + +template +bool Iterator::operator!=(const Iterator &other) +{ + return !(*this == other); +} + diff --git a/set_lib/include/set.h b/set_lib/include/set.h index e4ecc89..57d3286 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -3,58 +3,61 @@ #include #include -#include "iterator.h" +enum class IS_END {NO = 0, YES = 1}; + +template +class Iterator; template > class Set { +public: + using key_type = T; + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using key_compare = Comparator; + using value_compare = Comparator; + using reference = T&; + using const_reference = const T&; + using iterator = Iterator; +private: struct Node { - Node(const T &data) - : data(data), height(1) + Node(const T &data, IS_END isend = IS_END::NO) + : data(data), height(1), isEnd(isEnd) { } std::shared_ptr Next(); std::shared_ptr Prev(); - - T data; - size_t height; + + T data; + size_t height; std::shared_ptr left; std::shared_ptr right; std::shared_ptr parent; - friend class Iterator; + IS_END isEnd; }; - public: - - using key_type = T; - using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using reference = T&; - using const_reference = const T&; - using iterator = Iterator; - // using const_iterator = - // using reverse_iterator = - // using const_reverse_iterator = - - - Set(); ~Set(); - void Insert(const T &data); - bool Has(const T &data) const; - void Erase(const T &data); - std::shared_ptr begin() const; - std::shared_ptr end() const; + size_type size() const; + bool empty() const; + void Insert(const_reference); + bool Has(const_reference) const; + void Erase(const_reference); + iterator begin() const; + iterator end() const; private: + friend class Iterator; + static const std::shared_ptr m_nodeEnd; std::shared_ptr m_root; Comparator m_cmp; - // friend class Iterator; - - std::shared_ptr eraseInternal(std::shared_ptr node, const T &data); - std::shared_ptr insertInternal(std::shared_ptr node, const T &data); + size_type m_size = 0; + + std::shared_ptr eraseInternal(std::shared_ptr node, const_reference data); + std::shared_ptr insertInternal(std::shared_ptr node, const_reference data); std::shared_ptr detachReplacement(std::shared_ptr node); std::shared_ptr findReplacement(std::shared_ptr node) const; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index d9aa944..134cdd9 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -4,6 +4,9 @@ #include "set.h" +template +const typename Set::std::template shared_ptr::Node> m_nodeEnd = std::make_shared::Node>(0, IS_END::YES); + template Set::Set() : m_root(nullptr) { @@ -21,6 +24,7 @@ void Set::Insert(const T &data) { return; } + ++m_size; m_root = insertInternal(m_root, data); } @@ -49,6 +53,10 @@ bool Set::Has(const T &data) const template void Set::Erase(const T &data) { + if (Has(data)) + { + --m_size; + } m_root = eraseInternal(m_root, data); } @@ -96,7 +104,8 @@ std::shared_ptr::Node> Set::eraseInte { replace->left->parent = replace; } - replace->parent = node->parent; // на выходе из рекурсии редактируем parent + // на выходе из рекурсии редактируем parent + replace->parent = node->parent; return doBalance(replace); } @@ -237,24 +246,26 @@ std::shared_ptr::Node> Set::doBalance template -std::shared_ptr::Node> Set::begin() const +Iterator Set::begin() const { if (!m_root) { - return nullptr; + return Iterator(m_nodeEnd); } + // можно оптимизировать + // при вставке обновлять минимальный (максимальный) элемент std::shared_ptr node = m_root; while (node->left) { node = node->left; } - return node; + return Iterator(node); } template -std::shared_ptr::Node> Set::end() const +Iterator Set::end() const { - return nullptr; + return Iterator(m_nodeEnd); } @@ -277,7 +288,7 @@ std::shared_ptr::Node> Set::Node::Nex // вверх до того родителя, у которого левым потоком являемся мы if (!parent) { - return nullptr; + return m_nodeEnd; } else { @@ -293,15 +304,17 @@ std::shared_ptr::Node> Set::Node::Nex node = needed_parent; needed_parent = needed_parent->parent; } - return needed_parent; + return needed_parent ? needed_parent : m_nodeEnd; } } + + template std::shared_ptr::Node> Set::Node::Prev() { std::shared_ptr node; - // влево и вправо до упора + // вправо и влево до упора if (left) { node = left; @@ -313,10 +326,10 @@ std::shared_ptr::Node> Set::Node::Pre } else { - // вверх до того родителя, у которого правым потоком являемся мы + // вверх до того родителя, у которого левым потоком являемся мы if (!parent) { - return nullptr; + return m_nodeEnd; } else { @@ -332,8 +345,20 @@ std::shared_ptr::Node> Set::Node::Pre node = needed_parent; needed_parent = needed_parent->parent; } - return needed_parent; + return needed_parent ? needed_parent : m_nodeEnd; } } +template +std::size_t Set::size() const +{ + return m_size; +} + +template +bool Set::empty() const +{ + return m_size == 0; +} + From e016d46008fa80ade00e9d8cdcbbd2c725118fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 19 Nov 2022 23:08:04 +0300 Subject: [PATCH 08/20] clear stupid solutions --- main.cpp | 18 +++++++++--------- set_lib/include/set.h | 8 ++------ set_lib/include/set_definition.h | 15 ++++++--------- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/main.cpp b/main.cpp index 4e7c120..9d46d90 100644 --- a/main.cpp +++ b/main.cpp @@ -30,14 +30,14 @@ int main(int argc, const char * argv[]) std::cout << *it << " "; } - puts("\n\n0"); - auto start = --set.end(); - puts("1"); - auto end = --set.begin(); - puts("2"); - for (; start != end; start--) - { - std::cout << *start << " "; - } + // puts("\n\n0"); + // auto start = --set.end(); + // puts("1"); + // auto end = --set.begin(); + // puts("2"); + // for (; start != end; start--) + // { + // std::cout << *start << " "; + // } return 0; } \ No newline at end of file diff --git a/set_lib/include/set.h b/set_lib/include/set.h index 57d3286..7c64638 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -3,8 +3,6 @@ #include #include -enum class IS_END {NO = 0, YES = 1}; - template class Iterator; @@ -24,8 +22,8 @@ class Set private: struct Node { - Node(const T &data, IS_END isend = IS_END::NO) - : data(data), height(1), isEnd(isEnd) + Node(const T &data) + : data(data), height(1) { } std::shared_ptr Next(); @@ -36,7 +34,6 @@ class Set std::shared_ptr left; std::shared_ptr right; std::shared_ptr parent; - IS_END isEnd; }; public: Set(); @@ -51,7 +48,6 @@ class Set private: friend class Iterator; - static const std::shared_ptr m_nodeEnd; std::shared_ptr m_root; Comparator m_cmp; size_type m_size = 0; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index 134cdd9..b0bd080 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -4,9 +4,6 @@ #include "set.h" -template -const typename Set::std::template shared_ptr::Node> m_nodeEnd = std::make_shared::Node>(0, IS_END::YES); - template Set::Set() : m_root(nullptr) { @@ -250,7 +247,7 @@ Iterator Set::begin() const { if (!m_root) { - return Iterator(m_nodeEnd); + return Iterator(nullptr); } // можно оптимизировать // при вставке обновлять минимальный (максимальный) элемент @@ -265,7 +262,7 @@ Iterator Set::begin() const template Iterator Set::end() const { - return Iterator(m_nodeEnd); + return Iterator(nullptr); } @@ -288,7 +285,7 @@ std::shared_ptr::Node> Set::Node::Nex // вверх до того родителя, у которого левым потоком являемся мы if (!parent) { - return m_nodeEnd; + return nullptr; } else { @@ -304,7 +301,7 @@ std::shared_ptr::Node> Set::Node::Nex node = needed_parent; needed_parent = needed_parent->parent; } - return needed_parent ? needed_parent : m_nodeEnd; + return needed_parent; } } @@ -329,7 +326,7 @@ std::shared_ptr::Node> Set::Node::Pre // вверх до того родителя, у которого левым потоком являемся мы if (!parent) { - return m_nodeEnd; + return nullptr; } else { @@ -345,7 +342,7 @@ std::shared_ptr::Node> Set::Node::Pre node = needed_parent; needed_parent = needed_parent->parent; } - return needed_parent ? needed_parent : m_nodeEnd; + return needed_parent; } } From 1479c4c4f0993f14ea732c42b7704162cd434c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 19 Nov 2022 23:16:26 +0300 Subject: [PATCH 09/20] ready to work! --- main.cpp | 26 ++--- set_lib/include/iterator.h | 10 +- set_lib/include/iterator_definition.h | 44 ++++---- set_lib/include/set.h | 19 ++-- set_lib/include/set_definition.h | 150 +++++++++++--------------- 5 files changed, 115 insertions(+), 134 deletions(-) diff --git a/main.cpp b/main.cpp index 9d46d90..93bf126 100644 --- a/main.cpp +++ b/main.cpp @@ -12,23 +12,23 @@ int main(int argc, const char * argv[]) - for (auto elem : set) - { - std::cout << elem << " "; - } + // for (auto elem : set) + // { + // std::cout << elem << " "; + // } - std::cout << "size = " << set.size() << "\n"; + // std::cout << "size = " << set.size() << "\n"; - set.Erase(7); - set.Erase(11); + // set.Erase(7); + // set.Erase(11); - std::cout << "size = " << set.size() << "\n"; + // std::cout << "size = " << set.size() << "\n"; - std::cout << "\n"; - for (auto it = set.begin(); it != set.end(); it++) - { - std::cout << *it << " "; - } + // std::cout << "\n"; + // for (auto it = set.begin(); it != set.end(); it++) + // { + // std::cout << *it << " "; + // } // puts("\n\n0"); // auto start = --set.end(); diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index 4b8de55..ec000b8 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -1,7 +1,7 @@ #include "set.h" #pragma once -template +template class Iterator { public: @@ -9,8 +9,8 @@ class Iterator using value_type = T; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using key_compare = Comparator; - using value_compare = Comparator; + using key_compare = Cmp; + using value_compare = Cmp; using reference = T&; using const_reference = const T&; using pointer = T*; @@ -18,7 +18,7 @@ class Iterator using iterator_category = std::bidirectional_iterator_tag; Iterator() = default; - Iterator(std::shared_ptr::Node> node); + Iterator(std::shared_ptr::Node> node); Iterator(const Iterator &) = default; Iterator& operator=(const Iterator &) = default; @@ -34,7 +34,7 @@ class Iterator bool operator==(const Iterator &); bool operator!=(const Iterator &); private: - std::shared_ptr::Node> node; + std::shared_ptr::Node> node; }; #include "iterator_definition.h" \ No newline at end of file diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h index 4b00111..5d95cee 100644 --- a/set_lib/include/iterator_definition.h +++ b/set_lib/include/iterator_definition.h @@ -2,61 +2,61 @@ #pragma once -template -Iterator::Iterator(std::shared_ptr::Node> node) : node(node) +template +Iterator::Iterator(std::shared_ptr::Node> node) : node(node) { } -template -Iterator& Iterator::operator++() +template +Iterator& Iterator::operator++() { - node = node->Next(); + // node = node->Next(); return *this; } -template -Iterator Iterator::operator++(int) +template +Iterator Iterator::operator++(int) { - Iterator tmp(*this); + Iterator tmp(*this); operator++(); return tmp; } -template -Iterator& Iterator::operator--() +template +Iterator& Iterator::operator--() { - node = node->Prev(); + // node = node->Prev(); return *this; } -template -Iterator Iterator::operator--(int) +template +Iterator Iterator::operator--(int) { - Iterator tmp(*this); + Iterator tmp(*this); operator--(); return tmp; } -template -const T& Iterator::operator*() +template +const T& Iterator::operator*() { return node->data; } -template -const T* Iterator::operator->() +template +const T* Iterator::operator->() { return &(node->data); } -template -bool Iterator::operator==(const Iterator &other) +template +bool Iterator::operator==(const Iterator &other) { return node == other.node; } -template -bool Iterator::operator!=(const Iterator &other) +template +bool Iterator::operator!=(const Iterator &other) { return !(*this == other); } diff --git a/set_lib/include/set.h b/set_lib/include/set.h index 7c64638..5ee20ff 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -3,10 +3,10 @@ #include #include -template +template class Iterator; -template > +template > class Set { public: @@ -14,11 +14,11 @@ class Set using value_type = T; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using key_compare = Comparator; - using value_compare = Comparator; + using key_compare = Cmp; + using value_compare = Cmp; using reference = T&; using const_reference = const T&; - using iterator = Iterator; + using iterator = Iterator; private: struct Node { @@ -26,8 +26,6 @@ class Set : data(data), height(1) { } - std::shared_ptr Next(); - std::shared_ptr Prev(); T data; size_t height; @@ -47,9 +45,9 @@ class Set iterator end() const; private: - friend class Iterator; + friend class Iterator; std::shared_ptr m_root; - Comparator m_cmp; + Cmp m_cmp; size_type m_size = 0; std::shared_ptr eraseInternal(std::shared_ptr node, const_reference data); @@ -66,6 +64,9 @@ class Set int getBalance(std::shared_ptr node) const; std::shared_ptr doBalance(std::shared_ptr node); + + std::shared_ptr NextInternal(std::shared_ptr node) const; + std::shared_ptr PrevInternal(std::shared_ptr node) const; }; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index b0bd080..7627289 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -4,18 +4,18 @@ #include "set.h" -template -Set::Set() : m_root(nullptr) +template +Set::Set() : m_root(nullptr) { } -template -Set::~Set() +template +Set::~Set() { } -template -void Set::Insert(const T &data) +template +void Set::Insert(const T &data) { if (Has(data)) { @@ -25,8 +25,8 @@ void Set::Insert(const T &data) m_root = insertInternal(m_root, data); } -template -bool Set::Has(const T &data) const +template +bool Set::Has(const T &data) const { std::shared_ptr tmp = m_root; while (tmp) @@ -47,8 +47,8 @@ bool Set::Has(const T &data) const return false; } -template -void Set::Erase(const T &data) +template +void Set::Erase(const T &data) { if (Has(data)) { @@ -57,8 +57,8 @@ void Set::Erase(const T &data) m_root = eraseInternal(m_root, data); } -template -std::shared_ptr::Node> Set::eraseInternal(std::shared_ptr node, const T &data) +template +std::shared_ptr::Node> Set::eraseInternal(std::shared_ptr node, const T &data) { if (!node) { @@ -109,8 +109,8 @@ std::shared_ptr::Node> Set::eraseInte return doBalance(node); } -template -std::shared_ptr::Node> Set::findReplacement(std::shared_ptr node) const +template +std::shared_ptr::Node> Set::findReplacement(std::shared_ptr node) const { while (node->left) { @@ -119,8 +119,8 @@ std::shared_ptr::Node> Set::findRepla return node; } -template -std::shared_ptr::Node> Set::detachReplacement(std::shared_ptr node) +template +std::shared_ptr::Node> Set::detachReplacement(std::shared_ptr node) { if (!node->left) { @@ -134,8 +134,8 @@ std::shared_ptr::Node> Set::detachRep return doBalance(node); } -template -std::shared_ptr::Node> Set::insertInternal(std::shared_ptr node, const T &data) +template +std::shared_ptr::Node> Set::insertInternal(std::shared_ptr node, const T &data) { if (!node) { @@ -156,20 +156,20 @@ std::shared_ptr::Node> Set::insertInt return doBalance(node); } -template -size_t Set::getHeight(std::shared_ptr node) const +template +size_t Set::getHeight(std::shared_ptr node) const { return node ? node->height : 0; } -template -void Set::fixHeight(std::shared_ptr node) +template +void Set::fixHeight(std::shared_ptr node) { node->height = std::max(getHeight(node->left), getHeight(node->right)) + 1; } -template -std::shared_ptr::Node> Set::rotateLeft(std::shared_ptr node) +template +std::shared_ptr::Node> Set::rotateLeft(std::shared_ptr node) { std::shared_ptr tmp = node->right; node->right = tmp->left; @@ -185,8 +185,8 @@ std::shared_ptr::Node> Set::rotateLef return tmp; } -template -std::shared_ptr::Node> Set::rotateRight(std::shared_ptr node) +template +std::shared_ptr::Node> Set::rotateRight(std::shared_ptr node) { // node = a // tmp = node->left = b @@ -205,14 +205,14 @@ std::shared_ptr::Node> Set::rotateRig return tmp; } -template -int Set::getBalance(std::shared_ptr node) const +template +int Set::getBalance(std::shared_ptr node) const { return getHeight(node->right) - getHeight(node->left); } -template -std::shared_ptr::Node> Set::doBalance(std::shared_ptr node) +template +std::shared_ptr::Node> Set::doBalance(std::shared_ptr node) { fixHeight(node); @@ -242,12 +242,12 @@ std::shared_ptr::Node> Set::doBalance } -template -Iterator Set::begin() const +template +Iterator Set::begin() const { if (!m_root) { - return Iterator(nullptr); + return Iterator(nullptr); } // можно оптимизировать // при вставке обновлять минимальный (максимальный) элемент @@ -256,24 +256,25 @@ Iterator Set::begin() const { node = node->left; } - return Iterator(node); + return Iterator(node); } -template -Iterator Set::end() const +template +Iterator Set::end() const { - return Iterator(nullptr); + return Iterator(nullptr); } - -template -std::shared_ptr::Node> Set::Node::Next() +template +std::shared_ptr::Node> Set::NextInternal(std::shared_ptr node) const { - std::shared_ptr node; - // вправо и влево до упора - if (right) + if (!node) { - node = right; + return nullptr; + } + if (node->right) + { + node = node->right; while (node->left) { node = node->left; @@ -282,78 +283,57 @@ std::shared_ptr::Node> Set::Node::Nex } else { - // вверх до того родителя, у которого левым потоком являемся мы - if (!parent) - { - return nullptr; - } - else - { - node = parent; - if (node->left.get() == this) - { - return node; - } - } std::shared_ptr needed_parent = node->parent; while (needed_parent && needed_parent->left != node) { node = needed_parent; - needed_parent = needed_parent->parent; + needed_parent = node->parent; } return needed_parent; } -} - - +} -template -std::shared_ptr::Node> Set::Node::Prev() +template +std::shared_ptr::Node> Set::PrevInternal(std::shared_ptr node) const { - std::shared_ptr node; - // вправо и влево до упора - if (left) + if (node == end()) { - node = left; + std::shared_ptr node = m_root; while (node->right) { node = node->right; } return node; } - else + if (node->left) { - // вверх до того родителя, у которого левым потоком являемся мы - if (!parent) - { - return nullptr; - } - else + node = node->left; + while (node->right) { - node = parent; - if (node->right.get() == this) - { - return node; - } + node = node->right; } + return node; + } + else + { std::shared_ptr needed_parent = node->parent; while (needed_parent && needed_parent->right != node) { node = needed_parent; - needed_parent = needed_parent->parent; + needed_parent = node->parent; } return needed_parent; } -} +} -template -std::size_t Set::size() const +template +std::size_t Set::size() const { return m_size; } -template -bool Set::empty() const +template +bool Set::empty() const { return m_size == 0; } From 614b5b1bc06cd9417b048b9f5aa8ca1e53796a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sun, 20 Nov 2022 00:37:28 +0300 Subject: [PATCH 10/20] global refactor, add list --- main.cpp | 48 +++++++++-- set_lib/include/iterator_definition.h | 20 ++++- set_lib/include/set.h | 39 ++++++--- set_lib/include/set_definition.h | 114 +++++++++++++++++++++----- tests/test_set.cpp | 22 ++++- 5 files changed, 200 insertions(+), 43 deletions(-) diff --git a/main.cpp b/main.cpp index 93bf126..bd20bbb 100644 --- a/main.cpp +++ b/main.cpp @@ -1,14 +1,52 @@ #include "set.h" #include "iterator.h" +/* +1. HAS -> FIND +2. FILL LIST AFTER INSERT AND ERASE +3. ITERATOR CHECK LIST + +*/ + + int main(int argc, const char * argv[]) { Set set; - set.Insert(7); - set.Insert(8); - set.Insert(9); - set.Insert(10); - set.Insert(11); + set.insert(70); + set.insert(90 ); + set.insert(110); + set.insert(3); + set.insert(130); + set.insert(80 ); + set.insert(120); + set.insert(100); + set.insert(-7); + + // set.erase(7); + // set.erase(8); + set.erase(70); + // set.erase(13); + set.erase(100); + // set.erase(11); + + // auto it = set.lower_bound(-8); + + for (auto elem : set) + { + std::cout << elem << " "; + } + puts(""); + + for (auto it = set.begin(); it != set.end(); it++) + { + std::cout << *it << " "; + } + puts(""); + + // std::cout << set.find(8)->data << "\n"; + // std::cout << set.find(11)->data << "\n"; + // std::cout << set.find(12)->data << "\n"; + // std::cout << set.find(123) << "\n"; diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h index 5d95cee..e2cdd3b 100644 --- a/set_lib/include/iterator_definition.h +++ b/set_lib/include/iterator_definition.h @@ -1,3 +1,5 @@ +#include + #include "iterator.h" #pragma once @@ -10,7 +12,10 @@ Iterator::Iterator(std::shared_ptr::Node> node) : n template Iterator& Iterator::operator++() { - // node = node->Next(); + if (node) + { + node = node->next; + } return *this; } @@ -25,7 +30,10 @@ Iterator Iterator::operator++(int) template Iterator& Iterator::operator--() { - // node = node->Prev(); + if (node) + { + node = node->prev; + } return *this; } @@ -40,12 +48,20 @@ Iterator Iterator::operator--(int) template const T& Iterator::operator*() { + if (!node) + { + throw std::runtime_error("operator*() to nullptr"); + } return node->data; } template const T* Iterator::operator->() { + if (!node) + { + throw std::runtime_error("operator->() to nullptr"); + } return &(node->data); } diff --git a/set_lib/include/set.h b/set_lib/include/set.h index 5ee20ff..a25b56e 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -29,27 +29,40 @@ class Set T data; size_t height; + // для АВЛ-дерева std::shared_ptr left; std::shared_ptr right; std::shared_ptr parent; + // для двусвязного спика + std::shared_ptr next; + std::shared_ptr prev; }; public: Set(); ~Set(); - size_type size() const; - bool empty() const; - void Insert(const_reference); - bool Has(const_reference) const; - void Erase(const_reference); - iterator begin() const; - iterator end() const; + size_type size() const; + bool empty() const; + // проверяет наличие прежде чем insertInternal + void insert(const_reference data); + // проверяет наличие прежде чем eraseInternal + iterator find(const_reference data) const; + iterator lower_bound(const_reference data) const; + void erase(const_reference data); + iterator begin() const; + iterator end() const; private: friend class Iterator; + // корень дерева std::shared_ptr m_root; - Cmp m_cmp; + // узлы двусвязного списка + std::shared_ptr m_first; + std::shared_ptr m_last; + Cmp m_cmp; size_type m_size = 0; + std::shared_ptr findInternal(const_reference data) const; + std::shared_ptr lower_boundInternal(const_reference data) const; std::shared_ptr eraseInternal(std::shared_ptr node, const_reference data); std::shared_ptr insertInternal(std::shared_ptr node, const_reference data); @@ -59,14 +72,14 @@ class Set std::shared_ptr rotateLeft(std::shared_ptr node); std::shared_ptr rotateRight(std::shared_ptr node); - size_t getHeight(std::shared_ptr node) const; - void fixHeight(std::shared_ptr node); + size_t getHeight(std::shared_ptr node) const; + void fixHeight(std::shared_ptr node); - int getBalance(std::shared_ptr node) const; + int getBalance(std::shared_ptr node) const; std::shared_ptr doBalance(std::shared_ptr node); - std::shared_ptr NextInternal(std::shared_ptr node) const; - std::shared_ptr PrevInternal(std::shared_ptr node) const; + std::shared_ptr nextInternal(std::shared_ptr node) const; + std::shared_ptr prevInternal(std::shared_ptr node) const; }; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index 7627289..cb4dc18 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -15,46 +15,109 @@ Set::~Set() } template -void Set::Insert(const T &data) +void Set::insert(const T &data) { - if (Has(data)) + if (findInternal(data) != nullptr) { return; } ++m_size; m_root = insertInternal(m_root, data); + auto it = findInternal(data); + it->prev = prevInternal(it); + if (it->prev) + { + it->prev->next = it; + } + it->next = nextInternal(it); + if (it->next) + { + it->next->prev = it; + } } template -bool Set::Has(const T &data) const +Iterator Set::find(const T &data) const +{ + auto ptr = findInternal(data); + return ptr ? Iterator(ptr) : end(); +} + +template +Iterator Set::lower_bound(const T &data) const +{ + auto ptr = lower_boundInternal(data); + return ptr ? Iterator(ptr) : end(); +} + +template +std::shared_ptr::Node> Set::findInternal(const T &data) const { - std::shared_ptr tmp = m_root; - while (tmp) + std::shared_ptr node = m_root; + while (node) { - if (tmp->data == data) + if (node->data == data) { - return true; + return node; } - else if (m_cmp(tmp->data, data)) + else if (m_cmp(node->data, data)) { - tmp = tmp->right; + node = node->right; } else { - tmp = tmp->left; + node = node->left; } } - return false; + return nullptr; } - + template -void Set::Erase(const T &data) +std::shared_ptr::Node> Set::lower_boundInternal(const T &data) const { - if (Has(data)) + std::shared_ptr node = m_root; + std::shared_ptr result = nullptr; + while (node) + { + if (m_cmp(node->data, data)) + { + node = node->right; + } + else + { + result = node; + node = node->left; + } + } + return result; +} + +template +void Set::erase(const T &data) +{ + auto it = findInternal(data); + if (it != nullptr) { + // отдельная функция - удалить из списка + auto prevNode = prevInternal(it); + auto nextNode = nextInternal(it); + if (prevNode == nullptr) + { + nextNode->prev = nullptr; + } + if (nextNode == nullptr) + { + prevNode->next = nullptr; + } + if (prevNode && nextNode) + { + prevNode->next = nextNode; + nextNode->prev = prevNode; + } + // prevNode->next = nextNode; --m_size; + m_root = eraseInternal(m_root, data); } - m_root = eraseInternal(m_root, data); } template @@ -247,10 +310,10 @@ Iterator Set::begin() const { if (!m_root) { - return Iterator(nullptr); + return end(); } // можно оптимизировать - // при вставке обновлять минимальный (максимальный) элемент + // при вставке (insert) обновлять минимальный (максимальный) элемент std::shared_ptr node = m_root; while (node->left) { @@ -266,11 +329,17 @@ Iterator Set::end() const } template -std::shared_ptr::Node> Set::NextInternal(std::shared_ptr node) const +std::shared_ptr::Node> Set::nextInternal(std::shared_ptr node) const { - if (!node) + // findMin() ? + if (node == nullptr) { - return nullptr; + std::shared_ptr node = m_root; + while (node->left) + { + node = node->left; + } + return node; } if (node->right) { @@ -294,9 +363,10 @@ std::shared_ptr::Node> Set::NextInternal(std::share } template -std::shared_ptr::Node> Set::PrevInternal(std::shared_ptr node) const +std::shared_ptr::Node> Set::prevInternal(std::shared_ptr node) const { - if (node == end()) + // findMax() ? + if (node == nullptr) { std::shared_ptr node = m_root; while (node->right) diff --git a/tests/test_set.cpp b/tests/test_set.cpp index dcfc94b..243f8d9 100644 --- a/tests/test_set.cpp +++ b/tests/test_set.cpp @@ -43,4 +43,24 @@ TEST(AvlTree, TestBasicsFunctional) EXPECT_TRUE (set.Has(9)); EXPECT_TRUE (set.Has(-20)); EXPECT_TRUE (set.Has(20)); -} \ No newline at end of file +} + + // Set set; + // set.insert(7); + // set.insert(9); + // set.insert(11); + // set.insert(13); + // set.insert(8); + // set.insert(12); + // set.insert(10); + + // set.erase(7); + // set.erase(10); + // set.erase(13); + + // auto it = set.find(8); + // for (; it != nullptr; it = it->next) + // { + // std::cout << it->data << " "; + // } + // puts(""); \ No newline at end of file From ccfffe6a88d40fd316f5e15a55fad676347cd8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sun, 20 Nov 2022 02:19:49 +0300 Subject: [PATCH 11/20] ctor, copy ctor, assign operator --- main.cpp | 42 ++++++++++++++++------- set_lib/CMakeLists.txt | 2 +- set_lib/include/iterator.h | 14 ++++---- set_lib/include/set.h | 12 ++++++- set_lib/include/set_definition.h | 58 +++++++++++++++++++++++++++++++- tests/CMakeLists.txt | 2 +- 6 files changed, 106 insertions(+), 24 deletions(-) diff --git a/main.cpp b/main.cpp index bd20bbb..e54a066 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,6 @@ #include "set.h" #include "iterator.h" +#include /* 1. HAS -> FIND @@ -11,27 +12,42 @@ int main(int argc, const char * argv[]) { - Set set; - set.insert(70); - set.insert(90 ); - set.insert(110); - set.insert(3); - set.insert(130); - set.insert(80 ); - set.insert(120); - set.insert(100); - set.insert(-7); + // Set set; + // set.insert(70); + // set.insert(90 ); + // set.insert(110); + // set.insert(3); + // set.insert(130); + // set.insert(80 ); + // set.insert(120); + // set.insert(100); + // set.insert(-7); // set.erase(7); // set.erase(8); - set.erase(70); + // set.erase(70); // set.erase(13); - set.erase(100); + // set.erase(100); // set.erase(11); // auto it = set.lower_bound(-8); - for (auto elem : set) + // std::vector vec = {1, 5, 3, 7, 34, 88}; + // Set set(vec.begin(), vec.end()); + Set set = {1, 5, 3, 7, 34, 88}; + Set set2 = {465, 12, 6, 4}; + + Set set3 = set; + set = set2; + set2 = set3; + // Set> set2(set); + + set.erase(1); + set.erase(5); + set.erase(6); + set.erase(7); + + for (auto elem : set2) { std::cout << elem << " "; } diff --git a/set_lib/CMakeLists.txt b/set_lib/CMakeLists.txt index ec89a52..311d70f 100644 --- a/set_lib/CMakeLists.txt +++ b/set_lib/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.0.0) project(set_lib) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror") find_package(Threads REQUIRED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index ec000b8..ed306c4 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -21,18 +21,18 @@ class Iterator Iterator(std::shared_ptr::Node> node); Iterator(const Iterator &) = default; - Iterator& operator=(const Iterator &) = default; + Iterator& operator=(const Iterator &) = default; - Iterator& operator++(); - Iterator operator++(int); - Iterator& operator--(); - Iterator operator--(int); + Iterator& operator++(); + Iterator operator++(int); + Iterator& operator--(); + Iterator operator--(int); const_reference operator*(); const_pointer operator->(); - bool operator==(const Iterator &); - bool operator!=(const Iterator &); + bool operator==(const Iterator &); + bool operator!=(const Iterator &); private: std::shared_ptr::Node> node; }; diff --git a/set_lib/include/set.h b/set_lib/include/set.h index a25b56e..67f4970 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -2,6 +2,7 @@ #include #include +#include template class Iterator; @@ -38,7 +39,14 @@ class Set std::shared_ptr prev; }; public: - Set(); + Set(Cmp cmp = Cmp{}); + template ::value_type, T>::value>::type> + Set(InputIt first, InputIt last, Cmp cmp = Cmp{}); + Set(std::initializer_list const &init_list); + template + Set(Set const &other); + Set(Set const &other); + Set &operator=(Set other); ~Set(); size_type size() const; bool empty() const; @@ -80,6 +88,8 @@ class Set std::shared_ptr nextInternal(std::shared_ptr node) const; std::shared_ptr prevInternal(std::shared_ptr node) const; + + void Swap(Set &other); }; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index cb4dc18..f562fe4 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -5,10 +5,66 @@ #include "set.h" template -Set::Set() : m_root(nullptr) +Set::Set(Cmp cmp) : m_cmp(cmp), m_root(nullptr) { } +template +template +Set::Set(InputIt first, InputIt last, Cmp cmp) : m_cmp(cmp) +{ + for (; first != last; ++first) + { + insert(*first); + } +} + +template +Set::Set(std::initializer_list const &init_list) +{ + for (auto && elem : init_list) + { + insert(elem); + } +} + +template +template +Set::Set(Set const &other) +{ + for (auto elem : other) + { + insert(elem); + } +} + + +template +Set::Set(Set const &other) +{ + for (auto elem : other) + { + insert(elem); + } +} + +template +Set& Set::operator=(Set other) +{ + Swap(other); + return *this; +} + +template +void Set::Swap(Set &other) +{ + std::swap(m_root, other.m_root); + std::swap(m_first, other.m_first); + std::swap(m_last, other.m_last); + std::swap(m_cmp, other.m_cmp); + std::swap(m_size, other.m_size); +} + template Set::~Set() { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 29ecc96..74cd59d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.0.0) project(test_set) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) From d9bdd21b3e03b63694b6d7fa3353e90932dc117a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sun, 20 Nov 2022 23:35:38 +0300 Subject: [PATCH 12/20] tests, *(--set.end()) --- .github/workflows/main.yml | 52 ++++---- main.cpp | 83 +----------- set_lib/include/iterator.h | 8 +- set_lib/include/iterator_definition.h | 18 ++- set_lib/include/set.h | 36 ++++- set_lib/include/set_definition.h | 141 +++++++++++--------- tests/test_set.cpp | 183 +++++++++++++++++++++----- 7 files changed, 311 insertions(+), 210 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cd35929..94c4b24 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,13 +1,13 @@ on: push jobs: - check: - runs-on: ubuntu-latest - container: mikhail2001/young_devs_image - steps: - - uses: actions/checkout@v2 - - name: GO LINTER CHECK - run: make check || exit 0 + # check: + # runs-on: ubuntu-latest + # container: mikhail2001/young_devs_image + # steps: + # - uses: actions/checkout@v2 + # - name: GO LINTER CHECK + # run: make check || exit 0 build: runs-on: ubuntu-latest container: mikhail2001/young_devs_image @@ -28,22 +28,22 @@ jobs: - run: make build TEST_OPT=ON - run: make run - run: make test - - name: GO TEST COVERAGE - run: make coverage - - name: Upload artifacts (COVERAGE REPORT) - uses: actions/upload-artifact@v2 - with: - name: coverage-report - path: build/report - - name: GO VALGRIND TESTS - run: make valgrind_tests - - name: GO VALGRIND TARGET - run: make valgrind_target - - name: GO SANITIZER - run: | - make build SANITIZE_OPT=ON - make run - - name: GO SCAN-BUILD - run: | - make build - make scan_build + # - name: GO TEST COVERAGE + # run: make coverage + # - name: Upload artifacts (COVERAGE REPORT) + # uses: actions/upload-artifact@v2 + # with: + # name: coverage-report + # path: build/report + # - name: GO VALGRIND TESTS + # run: make valgrind_tests + # - name: GO VALGRIND TARGET + # run: make valgrind_target + # - name: GO SANITIZER + # run: | + # make build SANITIZE_OPT=ON + # make run + # - name: GO SCAN-BUILD + # run: | + # make build + # make scan_build diff --git a/main.cpp b/main.cpp index e54a066..16e82fd 100644 --- a/main.cpp +++ b/main.cpp @@ -3,95 +3,26 @@ #include /* -1. HAS -> FIND -2. FILL LIST AFTER INSERT AND ERASE -3. ITERATOR CHECK LIST - + Задачи + - Маркерный Node - указатель на узел после последнего + - Сделали +- + - Маркерный Node - указатель на узел перед первым (для реверсивного итератра) + - Не сделали */ int main(int argc, const char * argv[]) { - // Set set; - // set.insert(70); - // set.insert(90 ); - // set.insert(110); - // set.insert(3); - // set.insert(130); - // set.insert(80 ); - // set.insert(120); - // set.insert(100); - // set.insert(-7); - - // set.erase(7); - // set.erase(8); - // set.erase(70); - // set.erase(13); - // set.erase(100); - // set.erase(11); - - // auto it = set.lower_bound(-8); - - // std::vector vec = {1, 5, 3, 7, 34, 88}; - // Set set(vec.begin(), vec.end()); - Set set = {1, 5, 3, 7, 34, 88}; - Set set2 = {465, 12, 6, 4}; - - Set set3 = set; - set = set2; - set2 = set3; - // Set> set2(set); + Set set = {1, 5, 3, 7, 34, 88, 23}; set.erase(1); set.erase(5); set.erase(6); set.erase(7); - for (auto elem : set2) + for (auto elem : set) { std::cout << elem << " "; } - puts(""); - - for (auto it = set.begin(); it != set.end(); it++) - { - std::cout << *it << " "; - } - puts(""); - - // std::cout << set.find(8)->data << "\n"; - // std::cout << set.find(11)->data << "\n"; - // std::cout << set.find(12)->data << "\n"; - // std::cout << set.find(123) << "\n"; - - - - // for (auto elem : set) - // { - // std::cout << elem << " "; - // } - - // std::cout << "size = " << set.size() << "\n"; - - // set.Erase(7); - // set.Erase(11); - - // std::cout << "size = " << set.size() << "\n"; - - // std::cout << "\n"; - // for (auto it = set.begin(); it != set.end(); it++) - // { - // std::cout << *it << " "; - // } - - // puts("\n\n0"); - // auto start = --set.end(); - // puts("1"); - // auto end = --set.begin(); - // puts("2"); - // for (; start != end; start--) - // { - // std::cout << *start << " "; - // } return 0; } \ No newline at end of file diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index ed306c4..fec5f40 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -17,8 +17,11 @@ class Iterator using const_pointer = const T*; using iterator_category = std::bidirectional_iterator_tag; - Iterator() = default; - Iterator(std::shared_ptr::Node> node); + /* + - Принимаем root, чтобы можно было добраться до last, если содержим ноду-маркер с is_end = Y + - Наверное, можно в качестве маркера сделать Node с указателями такими же, как у root, но с is_end = Y + */ + Iterator(std::shared_ptr::Node> node, std::shared_ptr::Node> root); Iterator(const Iterator &) = default; Iterator& operator=(const Iterator &) = default; @@ -35,6 +38,7 @@ class Iterator bool operator!=(const Iterator &); private: std::shared_ptr::Node> node; + std::shared_ptr::Node> root; }; #include "iterator_definition.h" \ No newline at end of file diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h index e2cdd3b..5e7d008 100644 --- a/set_lib/include/iterator_definition.h +++ b/set_lib/include/iterator_definition.h @@ -5,17 +5,21 @@ template -Iterator::Iterator(std::shared_ptr::Node> node) : node(node) +Iterator::Iterator(std::shared_ptr::Node> node, std::shared_ptr::Node> root) : node(node), root(root) { } template Iterator& Iterator::operator++() { - if (node) + if (node->next) { node = node->next; } + else + { + node = std::make_shared::Node>(0, Y); + } return *this; } @@ -30,10 +34,14 @@ Iterator Iterator::operator++(int) template Iterator& Iterator::operator--() { - if (node) + if (node->is_end == N) { node = node->prev; } + else + { + node = Set::getRightMost(root); + } return *this; } @@ -68,6 +76,10 @@ const T* Iterator::operator->() template bool Iterator::operator==(const Iterator &other) { + if (node->is_end == Y && other.node->is_end == Y) + { + return true; + } return node == other.node; } diff --git a/set_lib/include/set.h b/set_lib/include/set.h index 67f4970..8ad0b5f 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -3,6 +3,9 @@ #include #include #include +#include + +enum IS_END {N = 0, Y = 1}; template class Iterator; @@ -23,8 +26,8 @@ class Set private: struct Node { - Node(const T &data) - : data(data), height(1) + Node(const T &data, IS_END is_end = N) + : data(data), height(1), is_end(is_end) { } @@ -37,6 +40,7 @@ class Set // для двусвязного спика std::shared_ptr next; std::shared_ptr prev; + IS_END is_end; }; public: Set(Cmp cmp = Cmp{}); @@ -58,17 +62,25 @@ class Set void erase(const_reference data); iterator begin() const; iterator end() const; - + bool operator==(Set const &other) const; + bool operator!=(Set const &other) const; private: + std::shared_ptr m_node_end; + std::shared_ptr m_node_beg; friend class Iterator; // корень дерева std::shared_ptr m_root; // узлы двусвязного списка std::shared_ptr m_first; + std::optional m_first_value = std::nullopt; std::shared_ptr m_last; + std::optional m_last_value = std::nullopt; + Cmp m_cmp; size_type m_size = 0; + void setNodeEnd(); + std::shared_ptr findInternal(const_reference data) const; std::shared_ptr lower_boundInternal(const_reference data) const; std::shared_ptr eraseInternal(std::shared_ptr node, const_reference data); @@ -90,6 +102,24 @@ class Set std::shared_ptr prevInternal(std::shared_ptr node) const; void Swap(Set &other); + + static std::shared_ptr getLeftMost(std::shared_ptr node) + { + while (node->left) + { + node = node->left; + } + return node; + } + static std::shared_ptr getRightMost(std::shared_ptr node) + { + while (node->right) + { + node = node->right; + } + return node; + } + }; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index f562fe4..afda48c 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -7,6 +7,7 @@ template Set::Set(Cmp cmp) : m_cmp(cmp), m_root(nullptr) { + setNodeEnd(); } template @@ -17,6 +18,7 @@ Set::Set(InputIt first, InputIt last, Cmp cmp) : m_cmp(cmp) { insert(*first); } + setNodeEnd(); } template @@ -26,6 +28,7 @@ Set::Set(std::initializer_list const &init_list) { insert(elem); } + setNodeEnd(); } template @@ -36,6 +39,7 @@ Set::Set(Set const &other) { insert(elem); } + setNodeEnd(); } @@ -46,6 +50,7 @@ Set::Set(Set const &other) { insert(elem); } + setNodeEnd(); } template @@ -79,16 +84,29 @@ void Set::insert(const T &data) } ++m_size; m_root = insertInternal(m_root, data); - auto it = findInternal(data); - it->prev = prevInternal(it); - if (it->prev) + auto ptr = findInternal(data); + // обновление m_first + if (!m_first_value || m_cmp(ptr->data, *m_first_value)) { - it->prev->next = it; + m_first = ptr; + m_first_value = ptr->data; } - it->next = nextInternal(it); - if (it->next) + // обновление m_last + if (!m_last_value || m_cmp(*m_last_value, ptr->data)) { - it->next->prev = it; + m_last = ptr; + m_last_value = ptr->data; + } + // установка prev и next + ptr->prev = prevInternal(ptr); + if (ptr->prev) + { + ptr->prev->next = ptr; + } + ptr->next = nextInternal(ptr); + if (ptr->next) + { + ptr->next->prev = ptr; } } @@ -96,14 +114,14 @@ template Iterator Set::find(const T &data) const { auto ptr = findInternal(data); - return ptr ? Iterator(ptr) : end(); + return ptr ? Iterator(ptr, m_root) : end(); } template Iterator Set::lower_bound(const T &data) const { auto ptr = lower_boundInternal(data); - return ptr ? Iterator(ptr) : end(); + return ptr ? Iterator(ptr, m_root) : end(); } template @@ -151,26 +169,28 @@ std::shared_ptr::Node> Set::lower_boundInternal(con template void Set::erase(const T &data) { - auto it = findInternal(data); - if (it != nullptr) + auto ptr = findInternal(data); + if (ptr != nullptr) { // отдельная функция - удалить из списка - auto prevNode = prevInternal(it); - auto nextNode = nextInternal(it); - if (prevNode == nullptr) - { - nextNode->prev = nullptr; - } - if (nextNode == nullptr) + auto prevNode = prevInternal(ptr); + auto nextNode = nextInternal(ptr); + if ( !(prevNode == nullptr && nextNode == nullptr) ) { - prevNode->next = nullptr; + if (prevNode == nullptr) + { + nextNode->prev = nullptr; + } + if (nextNode == nullptr) + { + prevNode->next = nullptr; + } + if (prevNode && nextNode) + { + prevNode->next = nextNode; + nextNode->prev = prevNode; + } } - if (prevNode && nextNode) - { - prevNode->next = nextNode; - nextNode->prev = prevNode; - } - // prevNode->next = nextNode; --m_size; m_root = eraseInternal(m_root, data); } @@ -368,43 +388,22 @@ Iterator Set::begin() const { return end(); } - // можно оптимизировать - // при вставке (insert) обновлять минимальный (максимальный) элемент - std::shared_ptr node = m_root; - while (node->left) - { - node = node->left; - } - return Iterator(node); + return Iterator(m_first, m_root); } template Iterator Set::end() const { - return Iterator(nullptr); + return Iterator(m_node_end, m_root); } template std::shared_ptr::Node> Set::nextInternal(std::shared_ptr node) const { - // findMin() ? - if (node == nullptr) - { - std::shared_ptr node = m_root; - while (node->left) - { - node = node->left; - } - return node; - } if (node->right) { node = node->right; - while (node->left) - { - node = node->left; - } - return node; + return getLeftMost(node); } else { @@ -421,24 +420,10 @@ std::shared_ptr::Node> Set::nextInternal(std::share template std::shared_ptr::Node> Set::prevInternal(std::shared_ptr node) const { - // findMax() ? - if (node == nullptr) - { - std::shared_ptr node = m_root; - while (node->right) - { - node = node->right; - } - return node; - } if (node->left) { node = node->left; - while (node->right) - { - node = node->right; - } - return node; + return getRightMost(node); } else { @@ -464,4 +449,32 @@ bool Set::empty() const return m_size == 0; } +template +bool Set::operator==(Set const &other) const +{ + auto itOther = other.begin(); + for (auto it = begin(); it != end(); ++it) + { + if (*itOther != *it) + { + return false; + } + itOther++; + } + return true; +} + +template +bool Set::operator!=(Set const &other) const +{ + return !(*this == other); +} + + + +template +void Set::setNodeEnd() +{ + m_node_end = std::make_shared(0, Y); +} diff --git a/tests/test_set.cpp b/tests/test_set.cpp index 243f8d9..c44ddf5 100644 --- a/tests/test_set.cpp +++ b/tests/test_set.cpp @@ -1,6 +1,9 @@ #include #include +#include +#include #include "set.h" +#include "iterator.h" template void TestInsertErase(Set &set, std::istream &in) @@ -13,54 +16,162 @@ void TestInsertErase(Set &set, std::istream &in) { case '+': { - set.Insert(data); + set.insert(data); break; } case '-': { - set.Erase(data); + set.erase(data); break; } } } } -TEST(AvlTree, TestBasicsFunctional) +TEST(TestBasicsFunctional, Test_Insert_Erase_Find_LowerBound) { - Set> set; - // fill 1..9, remove odd - std::string strTest = "+ 1 + 1 + 2 + 2 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 - 2 - 4 - 6 - 8 + -20 + 20"; + Set set; + EXPECT_EQ(set.size(), 0); + EXPECT_TRUE(set.empty()); + + // fill 1..9, -20, 20 + // remove odd + std::string strTest = "+ 1 + 1 + 2 + 2 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 - 2 - 4 - 6 - 8 -8 -8 + -20 + 20"; std::istringstream stream(strTest); TestInsertErase(set, stream); - EXPECT_TRUE (set.Has(1)); - EXPECT_FALSE(set.Has(2)); - EXPECT_TRUE (set.Has(3)); - EXPECT_FALSE(set.Has(4)); - EXPECT_TRUE (set.Has(5)); - EXPECT_FALSE(set.Has(6)); - EXPECT_TRUE (set.Has(7)); - EXPECT_FALSE(set.Has(8)); - EXPECT_TRUE (set.Has(9)); - EXPECT_TRUE (set.Has(-20)); - EXPECT_TRUE (set.Has(20)); + + EXPECT_EQ(set.size(), 7); + EXPECT_TRUE(!set.empty()); + + EXPECT_EQ(*(set.find(1)), 1); + EXPECT_EQ(*(set.find(3)), 3); + EXPECT_EQ(*(set.find(5)), 5); + EXPECT_EQ(*(set.find(7)), 7); + EXPECT_EQ(*(set.find(9)), 9); + EXPECT_EQ(*(set.find(-20)), -20); + EXPECT_EQ(*(set.find(20)), 20); + + EXPECT_EQ(*(set.lower_bound(2)), 3); + EXPECT_EQ(*(set.lower_bound(9)), 9); + EXPECT_EQ(*(set.lower_bound(-100)), -20); + + // EXPECT_EQ: отсутствие оператора == ... + EXPECT_TRUE(set.find(2) == set.end()); + EXPECT_TRUE(set.find(4) == set.end()); + EXPECT_TRUE(set.find(6) == set.end()); + EXPECT_TRUE(set.find(8) == set.end()); + + set.erase(12345); + for (auto elem : {1, 3, 5, 7, 9, -20}) + { + set.erase(elem); + } + EXPECT_EQ(set.size(), 1); + set.erase(20); + EXPECT_EQ(set.size(), 0); + set.erase(20); + set.erase(2001); +} + +TEST(TestBasicsFunctional, Test_Increment_Decrement_Begin_End) +{ + Set set; + EXPECT_TRUE(set.begin() == set.end()); + set = {10, 20, 30, 40, 50, 60, 70, 80, 90}; + Set::iterator it = set.find(40); + EXPECT_TRUE(it != set.end()); + EXPECT_EQ(*it, 40); + EXPECT_EQ(*(--it), 30); + EXPECT_EQ(*(it++), 30); + EXPECT_EQ(*(it), 40); + EXPECT_EQ(*(++it), 50); + EXPECT_TRUE(it == set.find(50)); + EXPECT_TRUE(it != set.find(70)); + EXPECT_EQ(*set.begin(), 10); + EXPECT_EQ(*(++set.begin()), 20); + // РАБОТАЕТ!!! + EXPECT_EQ(*(--set.end()), 90); +} + +TEST(TestBasicsFunctional, Test_Ctor_CopyCtor_AssignOperator) +{ + Set set1 = {1, 2, 3, 4, 5}; + Set set2(set1.begin(), set1.end()); + EXPECT_EQ(set1, set2); + set2.erase(4); + EXPECT_NE(set1, set2); + + set2 = set1; + EXPECT_EQ(set1, set2); + + auto it1 = set1.find(2); + auto it2 = set1.find(5); + Set set3(it1, it2); + EXPECT_EQ(set3.size(), 3); + auto it = set3.begin(); + for (auto elem : {2, 3, 4}) + { + EXPECT_EQ(*it, elem); + ++it; + } +} + +TEST(TestBasicsFunctional, Test_Compatibility_with_STL_Next_Advance_Prev) +{ + // for range выше + Set set = {1, 2, 3, 4, 5}; + Set::iterator it = set.begin(); + std::advance(it, 3); + EXPECT_EQ(*it, 4); + auto it2 = std::next(it); + EXPECT_EQ(*it2, 5); + it2 = std::prev(it, 2); + EXPECT_EQ(*it2, 2); +} + +TEST(TestBasicsFunctional, Test_Compatibility_with_STL_Vector) +{ + std::vector vec = {1, 2, 3, 4, 5}; + Set set(vec.begin(), vec.end()); + auto it = set.begin(); + for (auto &&elem : vec) + { + EXPECT_EQ(*it, elem); + ++it; + } + + int count = std::count_if(set.begin(), set.end(), [](int data) + { + return data % 2 == 0; + }); + EXPECT_EQ(count, 2); + + // CORRECT ERROR: no matching function for call to ‘Set::insert(Set::iterator&, const value_type&)’ + + std::vector vec2; + std::copy(set.begin(), set.end(), std::back_inserter(vec2)); + size_t index = 0; + for (auto &&elem : set) + { + EXPECT_EQ(elem, vec2[index]); + index++; + } + + + /* + + CORRECT ERROR: no matching function for call to ‘Set::insert(Set::iterator&, const value_type&)’ + Set set2 = {-2, -1, 0, 6}; + std::copy(set.begin(), set.end(), std::inserter(set2, set2.begin())); + */ + /* + нельзя, т.к. итератор константный + auto square = [](int &data) + { + data * data; + }; + std::for_each(set.begin(), set.end(), square); + + */ } - // Set set; - // set.insert(7); - // set.insert(9); - // set.insert(11); - // set.insert(13); - // set.insert(8); - // set.insert(12); - // set.insert(10); - - // set.erase(7); - // set.erase(10); - // set.erase(13); - - // auto it = set.find(8); - // for (; it != nullptr; it = it->next) - // { - // std::cout << it->data << " "; - // } - // puts(""); \ No newline at end of file From d0a05486b16aee388574b69b72c86e1e842c8cf0 Mon Sep 17 00:00:00 2001 From: mikhail_myadelets Date: Mon, 21 Nov 2022 14:21:51 +0300 Subject: [PATCH 13/20] add after_end, before_begin in Iterator --- main.cpp | 51 ++++++++++++++++++++++----- set_lib/include/iterator.h | 11 ++++-- set_lib/include/iterator_definition.h | 36 ++++++++++++------- set_lib/include/set.h | 10 +++--- set_lib/include/set_definition.h | 20 +++-------- 5 files changed, 82 insertions(+), 46 deletions(-) diff --git a/main.cpp b/main.cpp index 16e82fd..60facff 100644 --- a/main.cpp +++ b/main.cpp @@ -10,19 +10,52 @@ - Не сделали */ +using std::cout; +using std::endl; + +template +void eq(T left, T right) +{ + if (left == right) + { + std::cout << "equal\n"; + return; + } + std::cout << "not equal\n"; + return; +} int main(int argc, const char * argv[]) { Set set = {1, 5, 3, 7, 34, 88, 23}; - set.erase(1); - set.erase(5); - set.erase(6); - set.erase(7); + auto it = set.begin(); + + --it; + + ++it; - for (auto elem : set) - { - std::cout << elem << " "; - } - return 0; + cout << *it << endl; + + auto it2 = set.end(); + + it2--; + cout << *it2 << endl; + it2++; + it2++; + it2++; + + it2--; + cout << *it2 << endl; + + // set.erase(1); + // set.erase(5); + // set.erase(6); + // set.erase(7); + + // for (auto elem : set) + // { + // std::cout << elem << " "; + // } + // return 0; } \ No newline at end of file diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index fec5f40..ca4e081 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -1,6 +1,8 @@ -#include "set.h" #pragma once +#include "set.h" + + template class Iterator { @@ -21,8 +23,9 @@ class Iterator - Принимаем root, чтобы можно было добраться до last, если содержим ноду-маркер с is_end = Y - Наверное, можно в качестве маркера сделать Node с указателями такими же, как у root, но с is_end = Y */ - Iterator(std::shared_ptr::Node> node, std::shared_ptr::Node> root); - Iterator(const Iterator &) = default; + Iterator(std::shared_ptr::Node> node, + std::shared_ptr::Node> root, + bool after_end = false, bool before_begin = false); Iterator& operator=(const Iterator &) = default; @@ -39,6 +42,8 @@ class Iterator private: std::shared_ptr::Node> node; std::shared_ptr::Node> root; + bool before_begin = false; + bool after_end = false; }; #include "iterator_definition.h" \ No newline at end of file diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h index 5e7d008..7726712 100644 --- a/set_lib/include/iterator_definition.h +++ b/set_lib/include/iterator_definition.h @@ -1,25 +1,34 @@ +#pragma once + #include #include "iterator.h" -#pragma once + template -Iterator::Iterator(std::shared_ptr::Node> node, std::shared_ptr::Node> root) : node(node), root(root) +Iterator::Iterator(std::shared_ptr::Node> node, std::shared_ptr::Node> root, bool after_end, bool before_begin) +: node(node), root(root), before_begin(before_begin), after_end(after_end) { } template Iterator& Iterator::operator++() { - if (node->next) + if (node) { node = node->next; + if (!node) + { + after_end = true; + } } - else + else if (before_begin) { - node = std::make_shared::Node>(0, Y); + node = Set::getLeftMost(root); + before_begin = false; } + // after_end return *this; } @@ -34,14 +43,21 @@ Iterator Iterator::operator++(int) template Iterator& Iterator::operator--() { - if (node->is_end == N) + if (node) { node = node->prev; + if (!node) + { + before_begin = true; + } } - else + else if (after_end) { + // можно взять m_last from class Set, но Iterator не имеет ссылки на контейнер node = Set::getRightMost(root); - } + after_end = false; + } + // before_begin-- return *this; } @@ -76,10 +92,6 @@ const T* Iterator::operator->() template bool Iterator::operator==(const Iterator &other) { - if (node->is_end == Y && other.node->is_end == Y) - { - return true; - } return node == other.node; } diff --git a/set_lib/include/set.h b/set_lib/include/set.h index 8ad0b5f..59b18ba 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -5,7 +5,6 @@ #include #include -enum IS_END {N = 0, Y = 1}; template class Iterator; @@ -26,8 +25,8 @@ class Set private: struct Node { - Node(const T &data, IS_END is_end = N) - : data(data), height(1), is_end(is_end) + Node(const T &data) + : data(data), height(1) { } @@ -40,7 +39,6 @@ class Set // для двусвязного спика std::shared_ptr next; std::shared_ptr prev; - IS_END is_end; }; public: Set(Cmp cmp = Cmp{}); @@ -65,8 +63,8 @@ class Set bool operator==(Set const &other) const; bool operator!=(Set const &other) const; private: - std::shared_ptr m_node_end; - std::shared_ptr m_node_beg; + // std::shared_ptr m_node_end; + // std::shared_ptr m_node_beg; friend class Iterator; // корень дерева std::shared_ptr m_root; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index afda48c..6d26282 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -1,4 +1,5 @@ #pragma once + #include #include @@ -7,7 +8,6 @@ template Set::Set(Cmp cmp) : m_cmp(cmp), m_root(nullptr) { - setNodeEnd(); } template @@ -18,7 +18,6 @@ Set::Set(InputIt first, InputIt last, Cmp cmp) : m_cmp(cmp) { insert(*first); } - setNodeEnd(); } template @@ -28,7 +27,6 @@ Set::Set(std::initializer_list const &init_list) { insert(elem); } - setNodeEnd(); } template @@ -39,7 +37,6 @@ Set::Set(Set const &other) { insert(elem); } - setNodeEnd(); } @@ -50,7 +47,6 @@ Set::Set(Set const &other) { insert(elem); } - setNodeEnd(); } template @@ -387,14 +383,14 @@ Iterator Set::begin() const if (!m_root) { return end(); - } - return Iterator(m_first, m_root); + +} return Iterator(m_first, m_root); } template Iterator Set::end() const { - return Iterator(m_node_end, m_root); + return Iterator(nullptr, m_root, true); } template @@ -470,11 +466,3 @@ bool Set::operator!=(Set const &other) const return !(*this == other); } - - -template -void Set::setNodeEnd() -{ - m_node_end = std::make_shared(0, Y); -} - From 3213925de9dbd598ae63095c18fa5f0681f37589 Mon Sep 17 00:00:00 2001 From: mikhail_myadelets Date: Mon, 21 Nov 2022 16:18:24 +0300 Subject: [PATCH 14/20] row pointers, destructor --- main.cpp | 41 +++++++++------- set_lib/include/iterator.h | 8 ++-- set_lib/include/iterator_definition.h | 2 +- set_lib/include/set.h | 54 ++++++++++----------- set_lib/include/set_definition.h | 68 +++++++++++++++------------ 5 files changed, 95 insertions(+), 78 deletions(-) diff --git a/main.cpp b/main.cpp index 60facff..5918ed4 100644 --- a/main.cpp +++ b/main.cpp @@ -28,30 +28,39 @@ void eq(T left, T right) int main(int argc, const char * argv[]) { Set set = {1, 5, 3, 7, 34, 88, 23}; + for (auto elem : set) + { + std::cout << elem << std::endl; + } - auto it = set.begin(); + // auto it = set.begin(); - --it; + // --it; - ++it; + // ++it; + + // cout << *it << endl; - cout << *it << endl; + // auto it2 = set.end(); - auto it2 = set.end(); + // it2--; + // cout << *it2 << endl; + // it2++; + // it2++; + // it2++; - it2--; - cout << *it2 << endl; - it2++; - it2++; - it2++; + // it2--; + // cout << *it2 << endl; - it2--; - cout << *it2 << endl; + set.erase(1); + set.erase(5); + set.erase(6); + set.erase(7); - // set.erase(1); - // set.erase(5); - // set.erase(6); - // set.erase(7); + for (auto elem : set) + { + std::cout << elem << std::endl; + } // for (auto elem : set) // { diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index ca4e081..0f38692 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -23,8 +23,8 @@ class Iterator - Принимаем root, чтобы можно было добраться до last, если содержим ноду-маркер с is_end = Y - Наверное, можно в качестве маркера сделать Node с указателями такими же, как у root, но с is_end = Y */ - Iterator(std::shared_ptr::Node> node, - std::shared_ptr::Node> root, + Iterator(typename Set::Node* node, + typename Set::Node* root, bool after_end = false, bool before_begin = false); Iterator& operator=(const Iterator &) = default; @@ -40,8 +40,8 @@ class Iterator bool operator==(const Iterator &); bool operator!=(const Iterator &); private: - std::shared_ptr::Node> node; - std::shared_ptr::Node> root; + typename Set::Node* node; + typename Set::Node* root; bool before_begin = false; bool after_end = false; }; diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h index 7726712..887e2f4 100644 --- a/set_lib/include/iterator_definition.h +++ b/set_lib/include/iterator_definition.h @@ -7,7 +7,7 @@ template -Iterator::Iterator(std::shared_ptr::Node> node, std::shared_ptr::Node> root, bool after_end, bool before_begin) +Iterator::Iterator(typename Set::Node* node, typename Set::Node* root, bool after_end, bool before_begin) : node(node), root(root), before_begin(before_begin), after_end(after_end) { } diff --git a/set_lib/include/set.h b/set_lib/include/set.h index 59b18ba..a754585 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -26,19 +26,19 @@ class Set struct Node { Node(const T &data) - : data(data), height(1) + : data(data), height(1), left(nullptr), right(nullptr), parent(nullptr), next(nullptr), prev(nullptr) { } T data; size_t height; // для АВЛ-дерева - std::shared_ptr left; - std::shared_ptr right; - std::shared_ptr parent; + Node* left; + Node* right; + Node* parent; // для двусвязного спика - std::shared_ptr next; - std::shared_ptr prev; + Node* next; + Node* prev; }; public: Set(Cmp cmp = Cmp{}); @@ -63,15 +63,15 @@ class Set bool operator==(Set const &other) const; bool operator!=(Set const &other) const; private: - // std::shared_ptr m_node_end; - // std::shared_ptr m_node_beg; + // Node* m_node_end; + // Node* m_node_beg; friend class Iterator; // корень дерева - std::shared_ptr m_root; + Node* m_root = nullptr; // узлы двусвязного списка - std::shared_ptr m_first; + Node* m_first = nullptr; std::optional m_first_value = std::nullopt; - std::shared_ptr m_last; + Node* m_last = nullptr; std::optional m_last_value = std::nullopt; Cmp m_cmp; @@ -79,29 +79,29 @@ class Set void setNodeEnd(); - std::shared_ptr findInternal(const_reference data) const; - std::shared_ptr lower_boundInternal(const_reference data) const; - std::shared_ptr eraseInternal(std::shared_ptr node, const_reference data); - std::shared_ptr insertInternal(std::shared_ptr node, const_reference data); + Node* findInternal(const_reference data) const; + Node* lower_boundInternal(const_reference data) const; + Node* eraseInternal(Node* node, const_reference data); + Node* insertInternal(Node* node, const_reference data); - std::shared_ptr detachReplacement(std::shared_ptr node); - std::shared_ptr findReplacement(std::shared_ptr node) const; + Node* detachReplacement(Node* node); + Node* findReplacement(Node* node) const; - std::shared_ptr rotateLeft(std::shared_ptr node); - std::shared_ptr rotateRight(std::shared_ptr node); + Node* rotateLeft(Node* node); + Node* rotateRight(Node* node); - size_t getHeight(std::shared_ptr node) const; - void fixHeight(std::shared_ptr node); + size_t getHeight(Node* node) const; + void fixHeight(Node* node); - int getBalance(std::shared_ptr node) const; - std::shared_ptr doBalance(std::shared_ptr node); + int getBalance(Node* node) const; + Node* doBalance(Node* node); - std::shared_ptr nextInternal(std::shared_ptr node) const; - std::shared_ptr prevInternal(std::shared_ptr node) const; + Node* nextInternal(Node* node) const; + Node* prevInternal(Node* node) const; void Swap(Set &other); - static std::shared_ptr getLeftMost(std::shared_ptr node) + static Node* getLeftMost(Node* node) { while (node->left) { @@ -109,7 +109,7 @@ class Set } return node; } - static std::shared_ptr getRightMost(std::shared_ptr node) + static Node* getRightMost(Node* node) { while (node->right) { diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index 6d26282..328b7c6 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -49,6 +49,18 @@ Set::Set(Set const &other) } } +template +Set::~Set() +{ + Node *node = m_first; + while (node) + { + Node *tmp = node; + delete tmp; + node = node->next; + } +} + template Set& Set::operator=(Set other) { @@ -66,11 +78,6 @@ void Set::Swap(Set &other) std::swap(m_size, other.m_size); } -template -Set::~Set() -{ -} - template void Set::insert(const T &data) { @@ -121,9 +128,9 @@ Iterator Set::lower_bound(const T &data) const } template -std::shared_ptr::Node> Set::findInternal(const T &data) const +typename Set::Node* Set::findInternal(const T &data) const { - std::shared_ptr node = m_root; + Node* node = m_root; while (node) { if (node->data == data) @@ -143,10 +150,10 @@ std::shared_ptr::Node> Set::findInternal(const T &d } template -std::shared_ptr::Node> Set::lower_boundInternal(const T &data) const +typename Set::Node* Set::lower_boundInternal(const T &data) const { - std::shared_ptr node = m_root; - std::shared_ptr result = nullptr; + Node* node = m_root; + Node* result = nullptr; while (node) { if (m_cmp(node->data, data)) @@ -193,7 +200,7 @@ void Set::erase(const T &data) } template -std::shared_ptr::Node> Set::eraseInternal(std::shared_ptr node, const T &data) +typename Set::Node* Set::eraseInternal(Node* node, const T &data) { if (!node) { @@ -217,15 +224,15 @@ std::shared_ptr::Node> Set::eraseInternal(std::shar } else { - std::shared_ptr left = node->left; - std::shared_ptr right = node->right; + Node* left = node->left; + Node* right = node->right; if (!right) { return left; } - std::shared_ptr replace = findReplacement(right); + Node* replace = findReplacement(right); replace->right = detachReplacement(right); if (replace->right) { @@ -238,6 +245,7 @@ std::shared_ptr::Node> Set::eraseInternal(std::shar } // на выходе из рекурсии редактируем parent replace->parent = node->parent; + delete node; return doBalance(replace); } @@ -245,7 +253,7 @@ std::shared_ptr::Node> Set::eraseInternal(std::shar } template -std::shared_ptr::Node> Set::findReplacement(std::shared_ptr node) const +typename Set::Node* Set::findReplacement(Node* node) const { while (node->left) { @@ -255,7 +263,7 @@ std::shared_ptr::Node> Set::findReplacement(std::sh } template -std::shared_ptr::Node> Set::detachReplacement(std::shared_ptr node) +typename Set::Node* Set::detachReplacement(Node* node) { if (!node->left) { @@ -270,11 +278,11 @@ std::shared_ptr::Node> Set::detachReplacement(std:: } template -std::shared_ptr::Node> Set::insertInternal(std::shared_ptr node, const T &data) +typename Set::Node* Set::insertInternal(Node* node, const T &data) { if (!node) { - return std::make_shared(data); + return new Node(data); } if (m_cmp(data, node->data)) { @@ -292,21 +300,21 @@ std::shared_ptr::Node> Set::insertInternal(std::sha } template -size_t Set::getHeight(std::shared_ptr node) const +size_t Set::getHeight(Node* node) const { return node ? node->height : 0; } template -void Set::fixHeight(std::shared_ptr node) +void Set::fixHeight(Node* node) { node->height = std::max(getHeight(node->left), getHeight(node->right)) + 1; } template -std::shared_ptr::Node> Set::rotateLeft(std::shared_ptr node) +typename Set::Node* Set::rotateLeft(Node* node) { - std::shared_ptr tmp = node->right; + Node* tmp = node->right; node->right = tmp->left; if (tmp->left) { @@ -321,11 +329,11 @@ std::shared_ptr::Node> Set::rotateLeft(std::shared_ } template -std::shared_ptr::Node> Set::rotateRight(std::shared_ptr node) +typename Set::Node* Set::rotateRight(Node* node) { // node = a // tmp = node->left = b - std::shared_ptr tmp = node->left; + Node* tmp = node->left; node->left = tmp->right; // теперь a->left = C if (tmp->right) { @@ -341,13 +349,13 @@ std::shared_ptr::Node> Set::rotateRight(std::shared } template -int Set::getBalance(std::shared_ptr node) const +int Set::getBalance(Node* node) const { return getHeight(node->right) - getHeight(node->left); } template -std::shared_ptr::Node> Set::doBalance(std::shared_ptr node) +typename Set::Node* Set::doBalance(Node* node) { fixHeight(node); @@ -394,7 +402,7 @@ Iterator Set::end() const } template -std::shared_ptr::Node> Set::nextInternal(std::shared_ptr node) const +typename Set::Node* Set::nextInternal(Node* node) const { if (node->right) { @@ -403,7 +411,7 @@ std::shared_ptr::Node> Set::nextInternal(std::share } else { - std::shared_ptr needed_parent = node->parent; + Node* needed_parent = node->parent; while (needed_parent && needed_parent->left != node) { node = needed_parent; @@ -414,7 +422,7 @@ std::shared_ptr::Node> Set::nextInternal(std::share } template -std::shared_ptr::Node> Set::prevInternal(std::shared_ptr node) const +typename Set::Node* Set::prevInternal(Node* node) const { if (node->left) { @@ -423,7 +431,7 @@ std::shared_ptr::Node> Set::prevInternal(std::share } else { - std::shared_ptr needed_parent = node->parent; + Node* needed_parent = node->parent; while (needed_parent && needed_parent->right != node) { node = needed_parent; From 947a33a3922f5441f23bb893bcccad5b93f40f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Tue, 22 Nov 2022 01:17:26 +0300 Subject: [PATCH 15/20] fix memory leak, tests alexey --- CMakeLists.txt | 3 +- Makefile | 4 +- main.cpp | 43 ------ set_lib/CMakeLists.txt | 10 +- set_lib/include/iterator.h | 5 +- set_lib/include/iterator_definition.h | 2 - set_lib/include/set.h | 25 ++- set_lib/include/set_definition.h | 53 ++++++- tests/test_cases_alexey_halaidzhy.cpp | 214 ++++++++++++++++++++++++++ tests/test_set.cpp | 19 +++ 10 files changed, 313 insertions(+), 65 deletions(-) create mode 100644 tests/test_cases_alexey_halaidzhy.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7662943..28e115e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,11 +15,12 @@ add_subdirectory(set_lib) add_executable(${PROJECT_NAME} main.cpp) if(TEST_OPT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fPIC -O0") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) endif() if(DEBUG_OPT) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g -fPIC -O0" ) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g2 -fPIC -O0") endif() if(SANITIZE_OPT) diff --git a/Makefile b/Makefile index e87074e..4bc803c 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ coverage: cd ${BUILD_DIR} && lcov -t "testing_${LIB_DIR}" -o coverage.info -c -d ${LIB_DIR} && genhtml -o report coverage.info valgrind_tests: - valgrind --tool=memcheck --leak-check=yes --error-exitcode=1 ./${BUILD_DIR}/${TESTS_DIR}/${TESTS_EXE} + valgrind --tool=memcheck --leak-check=yes ./${BUILD_DIR}/${TESTS_DIR}/${TESTS_EXE} valgrind_target: valgrind --tool=memcheck -s --leak-check=yes --error-exitcode=1 ./${BUILD_DIR}/${TARGET_EXE} @@ -51,5 +51,3 @@ scan_build: formating: clang-format -i -style=file main.cpp ${LIB_DIR}/include/*.h ${LIB_DIR}/src/*.cpp ${TESTS_DIR}/*.cpp - -# clang-format -i -style="{BasedOnStyle: Microsoft, IndentWidth: 4, UseTab: Always, AccessModifierOffset: 0}" main.cpp ${LIB_DIR}/include/*.h ${LIB_DIR}/src/*.cpp ${TESTS_DIR}/*.cpp diff --git a/main.cpp b/main.cpp index 5918ed4..1900348 100644 --- a/main.cpp +++ b/main.cpp @@ -2,14 +2,6 @@ #include "iterator.h" #include -/* - Задачи - - Маркерный Node - указатель на узел после последнего - - Сделали +- - - Маркерный Node - указатель на узел перед первым (для реверсивного итератра) - - Не сделали -*/ - using std::cout; using std::endl; @@ -32,39 +24,4 @@ int main(int argc, const char * argv[]) { std::cout << elem << std::endl; } - - // auto it = set.begin(); - - // --it; - - // ++it; - - // cout << *it << endl; - - // auto it2 = set.end(); - - // it2--; - // cout << *it2 << endl; - // it2++; - // it2++; - // it2++; - - // it2--; - // cout << *it2 << endl; - - set.erase(1); - set.erase(5); - set.erase(6); - set.erase(7); - - for (auto elem : set) - { - std::cout << elem << std::endl; - } - - // for (auto elem : set) - // { - // std::cout << elem << " "; - // } - // return 0; } \ No newline at end of file diff --git a/set_lib/CMakeLists.txt b/set_lib/CMakeLists.txt index 311d70f..5d3c0a4 100644 --- a/set_lib/CMakeLists.txt +++ b/set_lib/CMakeLists.txt @@ -9,9 +9,13 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") if(TEST_OPT) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -fPIC -O0") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) -elseif(DEBUG_OPT) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fPIC -O0") -else() +endif() + +if(DEBUG_OPT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g2 -fPIC -O0") +endif() + +if(NOT DEBUG_OPT AND NOT TEST_OPT) # релиз-версия set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -O3") endif() diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index 0f38692..d678c05 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -19,13 +19,10 @@ class Iterator using const_pointer = const T*; using iterator_category = std::bidirectional_iterator_tag; - /* - - Принимаем root, чтобы можно было добраться до last, если содержим ноду-маркер с is_end = Y - - Наверное, можно в качестве маркера сделать Node с указателями такими же, как у root, но с is_end = Y - */ Iterator(typename Set::Node* node, typename Set::Node* root, bool after_end = false, bool before_begin = false); + Iterator() = default; Iterator& operator=(const Iterator &) = default; diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h index 887e2f4..21ff1de 100644 --- a/set_lib/include/iterator_definition.h +++ b/set_lib/include/iterator_definition.h @@ -4,8 +4,6 @@ #include "iterator.h" - - template Iterator::Iterator(typename Set::Node* node, typename Set::Node* root, bool after_end, bool before_begin) : node(node), root(root), before_begin(before_begin), after_end(after_end) diff --git a/set_lib/include/set.h b/set_lib/include/set.h index a754585..1fee7d3 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -29,6 +29,10 @@ class Set : data(data), height(1), left(nullptr), right(nullptr), parent(nullptr), next(nullptr), prev(nullptr) { } + ~Node() + { + left = right = parent = next = prev = nullptr; + } T data; size_t height; @@ -41,6 +45,7 @@ class Set Node* prev; }; public: + void show(); Set(Cmp cmp = Cmp{}); template ::value_type, T>::value>::type> Set(InputIt first, InputIt last, Cmp cmp = Cmp{}); @@ -52,19 +57,20 @@ class Set ~Set(); size_type size() const; bool empty() const; - // проверяет наличие прежде чем insertInternal + void insert(const_reference data); - // проверяет наличие прежде чем eraseInternal + void erase(const_reference data); + iterator find(const_reference data) const; iterator lower_bound(const_reference data) const; - void erase(const_reference data); + + iterator begin() const; iterator end() const; + bool operator==(Set const &other) const; bool operator!=(Set const &other) const; private: - // Node* m_node_end; - // Node* m_node_beg; friend class Iterator; // корень дерева Node* m_root = nullptr; @@ -103,6 +109,10 @@ class Set static Node* getLeftMost(Node* node) { + if (!node) + { + return nullptr; + } while (node->left) { node = node->left; @@ -111,6 +121,10 @@ class Set } static Node* getRightMost(Node* node) { + if (!node) + { + return nullptr; + } while (node->right) { node = node->right; @@ -118,6 +132,7 @@ class Set return node; } + }; diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index 328b7c6..0c37af1 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -55,12 +55,13 @@ Set::~Set() Node *node = m_first; while (node) { - Node *tmp = node; - delete tmp; - node = node->next; + Node *tmp = node->next; + delete node; + node = tmp; } } + template Set& Set::operator=(Set other) { @@ -133,7 +134,7 @@ typename Set::Node* Set::findInternal(const T &data) const Node* node = m_root; while (node) { - if (node->data == data) + if (!m_cmp(node->data, data) && !m_cmp(data, node->data)) { return node; } @@ -178,6 +179,7 @@ void Set::erase(const T &data) // отдельная функция - удалить из списка auto prevNode = prevInternal(ptr); auto nextNode = nextInternal(ptr); + // извлекаем из списка if ( !(prevNode == nullptr && nextNode == nullptr) ) { if (prevNode == nullptr) @@ -195,7 +197,9 @@ void Set::erase(const T &data) } } --m_size; + // извлекаем из дерева и удаляем m_root = eraseInternal(m_root, data); + m_first = getLeftMost(m_root); } } @@ -229,6 +233,7 @@ typename Set::Node* Set::eraseInternal(Node* node, const T &data if (!right) { + delete node; return left; } @@ -255,6 +260,10 @@ typename Set::Node* Set::eraseInternal(Node* node, const T &data template typename Set::Node* Set::findReplacement(Node* node) const { + if (!node) + { + return nullptr; + } while (node->left) { node = node->left; @@ -265,6 +274,10 @@ typename Set::Node* Set::findReplacement(Node* node) const template typename Set::Node* Set::detachReplacement(Node* node) { + if (!node) + { + return nullptr; + } if (!node->left) { return node->right; @@ -314,6 +327,10 @@ void Set::fixHeight(Node* node) template typename Set::Node* Set::rotateLeft(Node* node) { + if (!node) + { + return nullptr; + } Node* tmp = node->right; node->right = tmp->left; if (tmp->left) @@ -331,6 +348,10 @@ typename Set::Node* Set::rotateLeft(Node* node) template typename Set::Node* Set::rotateRight(Node* node) { + if (!node) + { + return nullptr; + } // node = a // tmp = node->left = b Node* tmp = node->left; @@ -357,6 +378,10 @@ int Set::getBalance(Node* node) const template typename Set::Node* Set::doBalance(Node* node) { + if (!node) + { + return nullptr; + } fixHeight(node); switch (getBalance(node)) @@ -404,6 +429,10 @@ Iterator Set::end() const template typename Set::Node* Set::nextInternal(Node* node) const { + if (!node) + { + return nullptr; + } if (node->right) { node = node->right; @@ -424,6 +453,10 @@ typename Set::Node* Set::nextInternal(Node* node) const template typename Set::Node* Set::prevInternal(Node* node) const { + if (!node) + { + return nullptr; + } if (node->left) { node = node->left; @@ -474,3 +507,15 @@ bool Set::operator!=(Set const &other) const return !(*this == other); } + +template +void Set::show() +{ + Node *node = m_first; + while (node) + { + std::cout << node->data << " "; + node = node->next; + } + std::cout << std::endl; +} diff --git a/tests/test_cases_alexey_halaidzhy.cpp b/tests/test_cases_alexey_halaidzhy.cpp new file mode 100644 index 0000000..f0d2ed5 --- /dev/null +++ b/tests/test_cases_alexey_halaidzhy.cpp @@ -0,0 +1,214 @@ +#include "set.h" +#include "iterator.h" +#include +#include +#include + +void fail(const char *message) { + std::cerr << "Fail:\n"; + std::cerr << message << "\n"; + std::cout << "-1 bad output\n"; // to get WA + exit(0); +} + +void check_constness() { + std::cerr << "check constness... "; + const Set s{-4, 5, 3, 0, 7}; + if (s.find(3) == s.end()) + fail("3 not found, incorrect find"); + if (*s.lower_bound(2) != 3 || s.lower_bound(8) != s.end() || *s.lower_bound(-2) != 0) + fail("incorrect lower_bound"); + if (s.empty()) + fail("incorrect empty"); + if (s.size() != 5) + fail("incorrect size"); + auto first = s.begin(); + Set::iterator last = s.end(); + if (*first != -4 || *(--last) != 7) + fail("incorrect begin or end"); + std::cerr << "ok!\n"; +} + +/* check if class correctly implements + * copy constructor and = operator */ +void check_copy_correctness() { + std::cerr << "check copy... "; + int elems[] = {3, 3, -1, 6, 0, 0, 17, -5, 4, 2}; + Set s1(elems, elems + 10); + std::set set_elems(elems, elems + 10); + Set s2 = s1; + s2.insert(5); + s2.insert(18); + s2.insert(-2); + auto s1_it = s1.begin(), s2_it = s2.begin(); + auto s_it = set_elems.begin(); + while (s1_it != s1.end() || s2_it != s2.end() || s_it != set_elems.end()) { + if (*s2_it == 5 || *s2_it == 18 || *s2_it == -2) { + ++s2_it; + continue; + } + if (*s1_it != *s2_it || *s1_it != *s_it || *s2_it != *s_it) + fail("fail after copy construction and insertions"); + ++s1_it, ++s2_it, ++s_it; + } + + s1 = s2; + s2.insert(19); + auto cur_end = s2.end(); + cur_end--; + s1_it = s1.begin(), s2_it = s2.begin(); + while (s1_it != s1.end() || s2_it != cur_end) { + if (*s1_it != *s2_it) + fail("wrong = operator"); + ++s1_it, ++s2_it; + } + + + s1 = s1 = s2; + s1_it = s1.begin(), s2_it = s2.begin(); + while (s1_it != s1.end() || s2_it != s2.end()) { + if (*s1_it != *s2_it) + fail("wrong = operator"); + ++s1_it, ++s2_it; + } + std::cerr << "ok!\n"; +} + +/* check if class correctly handles empty set */ +void check_empty() { + std::cerr << "check empty set handling... "; + Set s; + if (!s.empty()) + fail("wrong empty"); + auto begin = s.begin(), end = s.end(); + if (begin != end) + fail("incorrect handling empty set"); + std::string elem("abacaba"); + s.insert(elem); + if (*s.lower_bound("aac") != elem) + fail("wrong lower_bound"); + Set empty; + Set s2{"opa"}; + s2 = empty; + if (s2.size()) + fail("incorrect size"); + Set s3(s2); + if (!s3.empty()) + fail("incorrect empty"); + std::cerr << "ok!\n"; +} + +/* check if class correctly works with iterators */ +void check_iterators() { + std::cerr << "check iterators... "; + Set > s{{-3, 5}, {5, 5}, {-4, 1}, {-4, 4}, {0, 1}, {3, 0}}; + if (s.begin()->second != 1 || (++s.begin())->first != -4) + fail("wrong begin()"); + Set >::iterator cur = s.end(); + Set small{1}; + Set::iterator it; + it = small.begin(); + if (*it != 1) + fail("incorrect begin"); + auto begin = s.begin(); + begin++; + cur--; + if (begin == cur) + fail("wrong == for iterators"); + while (begin != cur) { + ++begin; + --cur; + } + if (*begin != *cur) + fail("wrong Iterators"); + std::cerr << "ok!\n"; +} + +struct StrangeInt { + int x; + static int counter; + StrangeInt() { + ++counter; + } + StrangeInt(int x): x(x) { + ++counter; + } + StrangeInt(const StrangeInt& rs): x(rs.x) { + ++counter; + } + bool operator <(const StrangeInt& rs) const { + return x < rs.x; + } + + static void init() { + counter = 0; + } + + ~StrangeInt() { + --counter; + } + + friend std::ostream& operator <<(std::ostream& out, const StrangeInt& x) { + out << x.x; + return out; + } +}; +int StrangeInt::counter; + +/* check if class uses only < for elements comparing */ +void check_operator_less() { + std::cerr << "check operator <... "; + + Set s{-5, -3, -6, 13, 7, 1000, 963}; + auto it = s.lower_bound(999); + ++it; + if (it != s.end()) + fail("wrong ++ for iterator"); + std::cerr << "ok!\n"; +} + +/* check if class correctly implements destructor */ +void check_destructor() { + std::cerr << "check destructor... "; + StrangeInt::init(); + { + Set s{5, 4, 3, 2, 1, 0}; + if (s.size() != 6) + fail("wrong size"); + } + if (StrangeInt::counter) + fail("wrong destructor (or constructors)"); + { + Set s{-3, 3, -2, 2, -1, 1}; + Set s1(s); + s1.insert(0); + Set s2(s1); + if (s1.find(0) == s1.end()) + fail("wrong find"); + s1 = s; + if (s1.find(0) != s1.end()) + fail("wrong find"); + } + if (StrangeInt::counter) + fail("wrong destructor (or constructors)"); + std::cerr << "ok!\n"; +} + +/* check erase for correctness */ +void check_erase() { + std::cerr << "check erase... "; + Set s{"abacaba", "hello", "p"}; + s.erase("miss"); + s.erase("hello"); + if (s.size() != 2) + fail("Bad size"); + s.erase("p"); + if (*s.begin() != "abacaba") + fail("Bad begin"); + s.erase("1"); + s.erase("abacaba"); + s.erase("012"); + if (!s.empty()) + fail("Bad empty"); + std::cerr << "ok!\n"; +} diff --git a/tests/test_set.cpp b/tests/test_set.cpp index c44ddf5..aabcbca 100644 --- a/tests/test_set.cpp +++ b/tests/test_set.cpp @@ -175,3 +175,22 @@ TEST(TestBasicsFunctional, Test_Compatibility_with_STL_Vector) */ } +extern void check_constness(); +extern void check_copy_correctness(); +extern void check_empty(); +extern void check_iterators(); +extern void check_operator_less(); +extern void check_destructor(); +extern void check_erase(); + +TEST(TestBasicsFunctional, Test_Alexey_Halaidzhy) +{ + // в тест кейсах exit(0) при ошибках, поэтому фейл будет отображен + check_constness(); + check_copy_correctness(); + check_empty(); + check_iterators(); + check_operator_less(); + check_destructor(); + check_erase(); +} From 51ffbb2b101d0f1fd296b844bfc1c77996f378aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Tue, 22 Nov 2022 01:20:07 +0300 Subject: [PATCH 16/20] fix ci --- .github/workflows/main.yml | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 94c4b24..022f1ac 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,22 +28,22 @@ jobs: - run: make build TEST_OPT=ON - run: make run - run: make test - # - name: GO TEST COVERAGE - # run: make coverage - # - name: Upload artifacts (COVERAGE REPORT) - # uses: actions/upload-artifact@v2 - # with: - # name: coverage-report - # path: build/report - # - name: GO VALGRIND TESTS - # run: make valgrind_tests - # - name: GO VALGRIND TARGET - # run: make valgrind_target - # - name: GO SANITIZER - # run: | - # make build SANITIZE_OPT=ON - # make run - # - name: GO SCAN-BUILD - # run: | - # make build - # make scan_build + - name: GO TEST COVERAGE + run: make coverage + - name: Upload artifacts (COVERAGE REPORT) + uses: actions/upload-artifact@v2 + with: + name: coverage-report + path: build/report + - name: GO VALGRIND TESTS + run: make valgrind_tests + - name: GO VALGRIND TARGET + run: make valgrind_target + - name: GO SANITIZER + run: | + make build SANITIZE_OPT=ON + make run + - name: GO SCAN-BUILD + run: | + make build + make scan_build From 22b86d8d00f490cb9b40af5b9f8c319d6c61b292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Wed, 23 Nov 2022 21:46:13 +0300 Subject: [PATCH 17/20] fix comments --- .github/workflows/main.yml | 15 ++++++++------- Makefile | 2 +- main.cpp | 12 ------------ set_lib/CMakeLists.txt | 6 +++++- set_lib/include/iterator.h | 1 + set_lib/include/iterator_definition.h | 4 ++-- set_lib/include/set_definition.h | 2 +- set_lib/src/set.cpp | 3 +-- tests/CMakeLists.txt | 2 +- 9 files changed, 20 insertions(+), 27 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 022f1ac..935cb53 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,13 +28,14 @@ jobs: - run: make build TEST_OPT=ON - run: make run - run: make test - - name: GO TEST COVERAGE - run: make coverage - - name: Upload artifacts (COVERAGE REPORT) - uses: actions/upload-artifact@v2 - with: - name: coverage-report - path: build/report + # *** НЕТ CPP для тестирования *** + # - name: GO TEST COVERAGE + # run: make coverage + # - name: Upload artifacts (COVERAGE REPORT) + # uses: actions/upload-artifact@v2 + # with: + # name: coverage-report + # path: build/report - name: GO VALGRIND TESTS run: make valgrind_tests - name: GO VALGRIND TARGET diff --git a/Makefile b/Makefile index 4bc803c..886813f 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ TARGET_EXE = main PATH_LINTERS_SCRIPT = linters/run.sh TEST_OPT = OFF -DEBUG_OPT = ON +DEBUG_OPT = OFF SANITIZE_OPT = OFF .PHONY: check build test clean run coverage diff --git a/main.cpp b/main.cpp index 1900348..514d10b 100644 --- a/main.cpp +++ b/main.cpp @@ -5,18 +5,6 @@ using std::cout; using std::endl; -template -void eq(T left, T right) -{ - if (left == right) - { - std::cout << "equal\n"; - return; - } - std::cout << "not equal\n"; - return; -} - int main(int argc, const char * argv[]) { Set set = {1, 5, 3, 7, 34, 88, 23}; diff --git a/set_lib/CMakeLists.txt b/set_lib/CMakeLists.txt index 5d3c0a4..990fa14 100644 --- a/set_lib/CMakeLists.txt +++ b/set_lib/CMakeLists.txt @@ -1,8 +1,9 @@ cmake_minimum_required(VERSION 3.0.0) project(set_lib) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 17) # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror") + find_package(Threads REQUIRED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") @@ -11,6 +12,9 @@ if(TEST_OPT) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) endif() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) + if(DEBUG_OPT) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g2 -fPIC -O0") endif() diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index d678c05..0a620b2 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -39,6 +39,7 @@ class Iterator private: typename Set::Node* node; typename Set::Node* root; + // признаки местоположения итератора перед началом и после конца bool before_begin = false; bool after_end = false; }; diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h index 21ff1de..8eafc42 100644 --- a/set_lib/include/iterator_definition.h +++ b/set_lib/include/iterator_definition.h @@ -26,7 +26,7 @@ Iterator& Iterator::operator++() node = Set::getLeftMost(root); before_begin = false; } - // after_end + // after_end++ = after_end return *this; } @@ -55,7 +55,7 @@ Iterator& Iterator::operator--() node = Set::getRightMost(root); after_end = false; } - // before_begin-- + // before_begin-- = before_begin return *this; } diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.h index 0c37af1..e7cad3f 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.h @@ -52,6 +52,7 @@ Set::Set(Set const &other) template Set::~Set() { + // итерируемся по списку Node *node = m_first; while (node) { @@ -176,7 +177,6 @@ void Set::erase(const T &data) auto ptr = findInternal(data); if (ptr != nullptr) { - // отдельная функция - удалить из списка auto prevNode = prevInternal(ptr); auto nextNode = nextInternal(ptr); // извлекаем из списка diff --git a/set_lib/src/set.cpp b/set_lib/src/set.cpp index baa38ab..2007440 100644 --- a/set_lib/src/set.cpp +++ b/set_lib/src/set.cpp @@ -1,2 +1 @@ -#include "set.h" - +#include "set.h" \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 74cd59d..29ecc96 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.0.0) project(test_set) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O0") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) From 4c30352951c0bb23fe19624eec8b217c1c008710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 3 Dec 2022 12:00:10 +0300 Subject: [PATCH 18/20] coverage libs --- .github/workflows/main.yml | 18 ++++++++++-------- Makefile | 8 ++++++-- main.cpp | 8 ++++---- set_lib/include/set.h | 1 + set_lib/src/set.cpp | 2 +- tests/test_set.cpp | 2 +- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 935cb53..556d4ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,14 +28,16 @@ jobs: - run: make build TEST_OPT=ON - run: make run - run: make test - # *** НЕТ CPP для тестирования *** - # - name: GO TEST COVERAGE - # run: make coverage - # - name: Upload artifacts (COVERAGE REPORT) - # uses: actions/upload-artifact@v2 - # with: - # name: coverage-report - # path: build/report + - name: GO TEST COVERAGE + run: | + make lcov + lcov --remove ./build/coverage.info -o ./build/coverage.info '/usr/include/*' '/usr/lib/*' $(echo $(pwd)/tests/\*) + make genhtml + - name: Upload artifacts (COVERAGE REPORT) + uses: actions/upload-artifact@v2 + with: + name: coverage-report + path: build/report - name: GO VALGRIND TESTS run: make valgrind_tests - name: GO VALGRIND TARGET diff --git a/Makefile b/Makefile index 886813f..3301a88 100644 --- a/Makefile +++ b/Makefile @@ -36,8 +36,12 @@ test: check: chmod u+x ${PATH_LINTERS_SCRIPT} && ./${PATH_LINTERS_SCRIPT} -coverage: - cd ${BUILD_DIR} && lcov -t "testing_${LIB_DIR}" -o coverage.info -c -d ${LIB_DIR} && genhtml -o report coverage.info +lcov: + cd ${BUILD_DIR} && lcov -t "testing_${LIB_DIR}" -o coverage.info -c -d ./${TESTS_DIR}/ +genhtml: + cd ${BUILD_DIR} && genhtml -o report coverage.info + +# lcov --remove coverage.info -o coverage.info '/usr/include/*' '/usr/lib/*' $$(cd .. && echo $(pwd)/${TESTS_DIR}/\* && cd ${BUILD_DIR}) && \ valgrind_tests: valgrind --tool=memcheck --leak-check=yes ./${BUILD_DIR}/${TESTS_DIR}/${TESTS_EXE} diff --git a/main.cpp b/main.cpp index 514d10b..0d2176c 100644 --- a/main.cpp +++ b/main.cpp @@ -8,8 +8,8 @@ using std::endl; int main(int argc, const char * argv[]) { Set set = {1, 5, 3, 7, 34, 88, 23}; - for (auto elem : set) - { - std::cout << elem << std::endl; - } + // for (auto elem : set) + // { + // std::cout << elem << std::endl; + // } } \ No newline at end of file diff --git a/set_lib/include/set.h b/set_lib/include/set.h index 1fee7d3..bace99d 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -136,5 +136,6 @@ class Set }; + #include "set_definition.h" diff --git a/set_lib/src/set.cpp b/set_lib/src/set.cpp index 2007440..aa2f9c5 100644 --- a/set_lib/src/set.cpp +++ b/set_lib/src/set.cpp @@ -1 +1 @@ -#include "set.h" \ No newline at end of file +#include "set.h" diff --git a/tests/test_set.cpp b/tests/test_set.cpp index aabcbca..ec2d79e 100644 --- a/tests/test_set.cpp +++ b/tests/test_set.cpp @@ -183,7 +183,7 @@ extern void check_operator_less(); extern void check_destructor(); extern void check_erase(); -TEST(TestBasicsFunctional, Test_Alexey_Halaidzhy) +TEST(TestOther, Test_Alexey_Halaidzhy) { // в тест кейсах exit(0) при ошибках, поэтому фейл будет отображен check_constness(); From 50e588e969fe2cc0c16f66f6b94643b71d025d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 3 Dec 2022 13:32:09 +0300 Subject: [PATCH 19/20] fix tests, fix ci --- .clang-format | 1 + .github/workflows/main.yml | 17 +- CPPLINT.cfg | 2 +- Makefile | 4 +- README.md | 19 + linters/run.sh | 7 +- main.cpp | 14 +- set_lib/include/iterator.h | 71 ++-- set_lib/include/iterator_definition.h | 101 ----- set_lib/include/iterator_definition.hpp | 98 +++++ set_lib/include/set.h | 242 ++++++----- .../{set_definition.h => set_definition.hpp} | 199 ++++----- tests/test_cases_alexey_halaidzhy.cpp | 392 +++++++++--------- tests/test_set.cpp | 314 ++++++++------ 14 files changed, 769 insertions(+), 712 deletions(-) delete mode 100644 set_lib/include/iterator_definition.h create mode 100644 set_lib/include/iterator_definition.hpp rename set_lib/include/{set_definition.h => set_definition.hpp} (72%) diff --git a/.clang-format b/.clang-format index 18bd48c..95be4dd 100644 --- a/.clang-format +++ b/.clang-format @@ -3,6 +3,7 @@ IndentWidth: 4 UseTab: Always AccessModifierOffset: 0 AccessModifierOffset: -4 +AlwaysBreakTemplateDeclarations: Yes # IndentAccessModifiers: false # does not work # https://clang.llvm.org/docs/ClangFormatStyleOptions.html \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 556d4ae..c226389 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,8 +27,21 @@ jobs: - uses: actions/checkout@v2 - run: make build TEST_OPT=ON - run: make run + - run: ./build/tests/test_set --gtest_filter=TestBasicsFunctional* + - name: GO MY TESTS COVERAGE + run: | + make lcov + lcov --remove ./build/coverage.info -o ./build/coverage.info '/usr/include/*' '/usr/lib/*' $(echo $(pwd)/tests/\*) + make genhtml + - name: Upload artifacts (COVERAGE REPORT) + uses: actions/upload-artifact@v2 + with: + name: coverage-report-my-tests + path: build/report + - run: make build TEST_OPT=ON + - run: make run - run: make test - - name: GO TEST COVERAGE + - name: GO ALL TESTS COVERAGE run: | make lcov lcov --remove ./build/coverage.info -o ./build/coverage.info '/usr/include/*' '/usr/lib/*' $(echo $(pwd)/tests/\*) @@ -36,7 +49,7 @@ jobs: - name: Upload artifacts (COVERAGE REPORT) uses: actions/upload-artifact@v2 with: - name: coverage-report + name: coverage-report-all-tests path: build/report - name: GO VALGRIND TESTS run: make valgrind_tests diff --git a/CPPLINT.cfg b/CPPLINT.cfg index 6dfc624..de5668d 100644 --- a/CPPLINT.cfg +++ b/CPPLINT.cfg @@ -7,4 +7,4 @@ filter=-build/header_guard filter=-build/include_subdir filter=-build/include filter=-readability/casting -filter=-whitespace/braces \ No newline at end of file +filter=-whitespace/braces diff --git a/Makefile b/Makefile index 3301a88..21d3615 100644 --- a/Makefile +++ b/Makefile @@ -41,8 +41,6 @@ lcov: genhtml: cd ${BUILD_DIR} && genhtml -o report coverage.info -# lcov --remove coverage.info -o coverage.info '/usr/include/*' '/usr/lib/*' $$(cd .. && echo $(pwd)/${TESTS_DIR}/\* && cd ${BUILD_DIR}) && \ - valgrind_tests: valgrind --tool=memcheck --leak-check=yes ./${BUILD_DIR}/${TESTS_DIR}/${TESTS_EXE} @@ -53,5 +51,5 @@ scan_build: cd ${BUILD_DIR} && scan-build $(MAKE) --no-print-directory formating: - clang-format -i -style=file main.cpp ${LIB_DIR}/include/*.h ${LIB_DIR}/src/*.cpp ${TESTS_DIR}/*.cpp + clang-format -i -style=file main.cpp ${LIB_DIR}/include/*.h ${LIB_DIR}/include/*.hpp ${LIB_DIR}/src/*.cpp ${TESTS_DIR}/*.cpp diff --git a/README.md b/README.md index 5f26b6a..7d131a7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,23 @@ # techopark_cpp_hw Репозиторий для сдачи домашних работ по С++ в Технопарке +### Мяделец Михаил WEB-11 **STL-совместимый контейнер** + +Необходимо реализовать упрощённую версию упорядоченного множества из STL Set. Асимптотики всех операций должны быть аналогичными std::set. Сравнение элементов типа T осуществлять только при помощи оператора <. +Необходимо поддержать следующие методы: +1) методы жизненного цикла - 4б +- конструктор по умолчанию; +- конструктор, принимающий пару итераторов элементов типа T, последовательно вставляемых в контейнер; +- конструктор, принимающий std::initializer_list элементов типа T; +- конструктор копирования ("глубокое копирование всех узлов контейнера"); +- оператор присваивания; +- деструктор; + +2) класс должен предоставлять const bidirectional-итератор для доступа к элементам, а также методы begin и end, и позволять просматривать все элементы контейнера без возможности их изменения, перемещаясь от каждого к следующему/предыдущему за O(1). Так как контейнер упорядоченный, то подразумевается их перебор в порядке возрастания - 4б; + +3) методы insert и erase вставки и удаления элементов из контейнера. Тип возвращаемого значения - void, При наличии/отсутствии элемента ничего делать не нужно. При модификации контейнера любой из этих операций итераторы могут инвалидироваться - 3б; + +4) константные методы: +- size и empty, возвращающие количество элементов и true/false в зависимости от наличия элементов в контейнере - 1б; +- find и lower_bound, которые возвращают соответственно итератор на искомый элемент во множестве/первый элемент, который не меньше искомого (или end() при его отсутствии) - 3б. diff --git a/linters/run.sh b/linters/run.sh index 310f9b4..4e1ef63 100644 --- a/linters/run.sh +++ b/linters/run.sh @@ -4,6 +4,7 @@ set -o pipefail SRC_PATHS="main.cpp set_lib/src/*.cpp" INCLUDE_PATHS="set_lib/include/*.h" +INCLUDE_PATHS_HPP="set_lib/include/*.hpp" TESTS_PATHS="tests/*.cpp" INCLUDE_DIRECTORIES="set_lib/include" @@ -29,7 +30,7 @@ function check_log() { # ********** cppcheck ********** print_header "RUN cppcheck" -check_log "cppcheck ${SRC_PATHS} ${INCLUDE_PATHS} ${TESTS_PATHS} --enable=all --inconclusive --error-exitcode=1 -I${INCLUDE_DIRECTORIES} --suppress=missingIncludeSystem" "\(information\)" +check_log "cppcheck ${SRC_PATHS} ${INCLUDE_PATHS} ${INCLUDE_PATHS_HPP} ${TESTS_PATHS} --enable=all --inconclusive --error-exitcode=1 -I${INCLUDE_DIRECTORIES} --suppress=missingIncludeSystem" "\(information\)" # # ********** clang-tidy ********** print_header "RUN clang-tidy" @@ -39,11 +40,11 @@ check_log "clang-tidy ${SRC_PATHS} ${TESTS_PATHS} -warnings-as-errors=* -extra-a # # ********** cpplint ********** print_header "RUN cpplint" check_log "cpplint --extensions=cpp ${SRC_PATHS} ${TESTS_PATHS}" "Can't open for reading" -check_log "cpplint --extensions=h ${INCLUDE_PATHS}" "Can't open for reading" +check_log "cpplint --extensions=h ${INCLUDE_PATHS} ${INCLUDE_PATHS_HPP}" "Can't open for reading" # # ********** clang-format ********** print_header "RUN clang-format" -diff <(clang-format --style=Microsoft ${SRC_PATHS} ${INCLUDE_PATHS} ${TESTS_PATHS}) <(cat ${SRC_PATHS} ${INCLUDE_PATHS} ${TESTS_PATHS}) || exit 1 +diff <(clang-format --style=Microsoft ${SRC_PATHS} ${INCLUDE_PATHS} ${INCLUDE_PATHS_HPP} ${TESTS_PATHS}) <(cat ${SRC_PATHS} ${INCLUDE_PATHS} ${INCLUDE_PATHS_HPP} ${TESTS_PATHS}) || exit 1 print_header "SUCCESS" \ No newline at end of file diff --git a/main.cpp b/main.cpp index 0d2176c..e48653b 100644 --- a/main.cpp +++ b/main.cpp @@ -1,15 +1,15 @@ -#include "set.h" #include "iterator.h" +#include "set.h" #include using std::cout; using std::endl; -int main(int argc, const char * argv[]) +int main(int argc, const char *argv[]) { - Set set = {1, 5, 3, 7, 34, 88, 23}; - // for (auto elem : set) - // { - // std::cout << elem << std::endl; - // } + Set set = {1, 5, 3, 7, 34, 88, 23}; + // for (auto elem : set) + // { + // std::cout << elem << std::endl; + // } } \ No newline at end of file diff --git a/set_lib/include/iterator.h b/set_lib/include/iterator.h index 0a620b2..c24715f 100644 --- a/set_lib/include/iterator.h +++ b/set_lib/include/iterator.h @@ -2,46 +2,45 @@ #include "set.h" - template class Iterator { public: - using key_type = T; - using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using key_compare = Cmp; - using value_compare = Cmp; - using reference = T&; - using const_reference = const T&; - using pointer = T*; - using const_pointer = const T*; - using iterator_category = std::bidirectional_iterator_tag; - - Iterator(typename Set::Node* node, - typename Set::Node* root, - bool after_end = false, bool before_begin = false); - Iterator() = default; - - Iterator& operator=(const Iterator &) = default; - - Iterator& operator++(); - Iterator operator++(int); - Iterator& operator--(); - Iterator operator--(int); - - const_reference operator*(); - const_pointer operator->(); - - bool operator==(const Iterator &); - bool operator!=(const Iterator &); + using key_type = T; + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using key_compare = Cmp; + using value_compare = Cmp; + using reference = T &; + using const_reference = const T &; + using pointer = T *; + using const_pointer = const T *; + using iterator_category = std::bidirectional_iterator_tag; + + Iterator(typename Set::Node *node, typename Set::Node *root, bool after_end = false, + bool before_begin = false); + Iterator() = default; + + Iterator &operator=(const Iterator &) = default; + + Iterator &operator++(); + Iterator operator++(int); + Iterator &operator--(); + Iterator operator--(int); + + const_reference operator*(); + const_pointer operator->(); + + bool operator==(const Iterator &); + bool operator!=(const Iterator &); + private: - typename Set::Node* node; - typename Set::Node* root; - // признаки местоположения итератора перед началом и после конца - bool before_begin = false; - bool after_end = false; + typename Set::Node *node; + typename Set::Node *root; + // признаки местоположения итератора перед первым элементом и после последнего + bool before_begin = false; + bool after_end = false; }; -#include "iterator_definition.h" \ No newline at end of file +#include "iterator_definition.hpp" diff --git a/set_lib/include/iterator_definition.h b/set_lib/include/iterator_definition.h deleted file mode 100644 index 8eafc42..0000000 --- a/set_lib/include/iterator_definition.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include - -#include "iterator.h" - -template -Iterator::Iterator(typename Set::Node* node, typename Set::Node* root, bool after_end, bool before_begin) -: node(node), root(root), before_begin(before_begin), after_end(after_end) -{ -} - -template -Iterator& Iterator::operator++() -{ - if (node) - { - node = node->next; - if (!node) - { - after_end = true; - } - } - else if (before_begin) - { - node = Set::getLeftMost(root); - before_begin = false; - } - // after_end++ = after_end - return *this; -} - -template -Iterator Iterator::operator++(int) -{ - Iterator tmp(*this); - operator++(); - return tmp; -} - -template -Iterator& Iterator::operator--() -{ - if (node) - { - node = node->prev; - if (!node) - { - before_begin = true; - } - } - else if (after_end) - { - // можно взять m_last from class Set, но Iterator не имеет ссылки на контейнер - node = Set::getRightMost(root); - after_end = false; - } - // before_begin-- = before_begin - return *this; -} - -template -Iterator Iterator::operator--(int) -{ - Iterator tmp(*this); - operator--(); - return tmp; -} - -template -const T& Iterator::operator*() -{ - if (!node) - { - throw std::runtime_error("operator*() to nullptr"); - } - return node->data; -} - -template -const T* Iterator::operator->() -{ - if (!node) - { - throw std::runtime_error("operator->() to nullptr"); - } - return &(node->data); -} - -template -bool Iterator::operator==(const Iterator &other) -{ - return node == other.node; -} - -template -bool Iterator::operator!=(const Iterator &other) -{ - return !(*this == other); -} - diff --git a/set_lib/include/iterator_definition.hpp b/set_lib/include/iterator_definition.hpp new file mode 100644 index 0000000..93a6556 --- /dev/null +++ b/set_lib/include/iterator_definition.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include + +#include "iterator.h" + +template +Iterator::Iterator(typename Set::Node *node, typename Set::Node *root, bool after_end, + bool before_begin) + : node(node), root(root), before_begin(before_begin), after_end(after_end) +{ +} + +template +Iterator &Iterator::operator++() +{ + if (node) + { + node = node->next; + if (!node) + { + after_end = true; + } + } + else if (before_begin) + { + node = Set::getLeftMost(root); + before_begin = false; + } + return *this; +} + +template +Iterator Iterator::operator++(int) +{ + Iterator tmp(*this); + ++(*this); + return tmp; +} + +template +Iterator &Iterator::operator--() +{ + if (node) + { + node = node->prev; + if (!node) + { + before_begin = true; + } + } + else if (after_end) + { + node = Set::getRightMost(root); + after_end = false; + } + return *this; +} + +template +Iterator Iterator::operator--(int) +{ + Iterator tmp(*this); + --(*this); + return tmp; +} + +template +const T &Iterator::operator*() +{ + if (!node) + { + throw std::runtime_error("operator*() to nullptr"); + } + return node->data; +} + +template +const T *Iterator::operator->() +{ + if (!node) + { + throw std::runtime_error("operator->() to nullptr"); + } + return &(node->data); +} + +template +bool Iterator::operator==(const Iterator &other) +{ + return node == other.node; +} + +template +bool Iterator::operator!=(const Iterator &other) +{ + return !(*this == other); +} diff --git a/set_lib/include/set.h b/set_lib/include/set.h index bace99d..7be0748 100644 --- a/set_lib/include/set.h +++ b/set_lib/include/set.h @@ -2,9 +2,8 @@ #include #include -#include #include - +#include template class Iterator; @@ -13,129 +12,126 @@ template > class Set { public: - using key_type = T; - using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - using key_compare = Cmp; - using value_compare = Cmp; - using reference = T&; - using const_reference = const T&; - using iterator = Iterator; + using key_type = T; + using value_type = T; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using key_compare = Cmp; + using value_compare = Cmp; + using reference = T &; + using const_reference = const T &; + using iterator = Iterator; + private: - struct Node - { - Node(const T &data) - : data(data), height(1), left(nullptr), right(nullptr), parent(nullptr), next(nullptr), prev(nullptr) - { - } - ~Node() - { - left = right = parent = next = prev = nullptr; - } - - T data; - size_t height; - // для АВЛ-дерева - Node* left; - Node* right; - Node* parent; - // для двусвязного спика - Node* next; - Node* prev; - }; + struct Node + { + Node(const T &data) + : data(data), height(1), left(nullptr), right(nullptr), parent(nullptr), next(nullptr), prev(nullptr) + { + } + ~Node() + { + left = right = parent = next = prev = nullptr; + } + + T data; + size_t height; + // для АВЛ-дерева + Node *left; + Node *right; + Node *parent; + // для двусвязного спика + Node *next; + Node *prev; + }; + public: - void show(); - Set(Cmp cmp = Cmp{}); - template ::value_type, T>::value>::type> - Set(InputIt first, InputIt last, Cmp cmp = Cmp{}); - Set(std::initializer_list const &init_list); - template - Set(Set const &other); - Set(Set const &other); - Set &operator=(Set other); - ~Set(); - size_type size() const; - bool empty() const; - - void insert(const_reference data); - void erase(const_reference data); - - iterator find(const_reference data) const; - iterator lower_bound(const_reference data) const; - - - iterator begin() const; - iterator end() const; - - bool operator==(Set const &other) const; - bool operator!=(Set const &other) const; + Set(Cmp cmp = Cmp{}); + template ::value_type, T>::value>::type> + Set(InputIt first, InputIt last, Cmp cmp = Cmp{}); + Set(std::initializer_list const &init_list); + template + Set(Set const &other); + Set(Set const &other); + Set &operator=(Set other); + ~Set(); + size_type size() const; + bool empty() const; + + void insert(const_reference data); + void erase(const_reference data); + + iterator find(const_reference data) const; + iterator lower_bound(const_reference data) const; + + iterator begin() const; + iterator end() const; + + bool operator==(Set const &other) const; + bool operator!=(Set const &other) const; + private: - friend class Iterator; - // корень дерева - Node* m_root = nullptr; - // узлы двусвязного списка - Node* m_first = nullptr; - std::optional m_first_value = std::nullopt; - Node* m_last = nullptr; - std::optional m_last_value = std::nullopt; - - Cmp m_cmp; - size_type m_size = 0; - - void setNodeEnd(); - - Node* findInternal(const_reference data) const; - Node* lower_boundInternal(const_reference data) const; - Node* eraseInternal(Node* node, const_reference data); - Node* insertInternal(Node* node, const_reference data); - - Node* detachReplacement(Node* node); - Node* findReplacement(Node* node) const; - - Node* rotateLeft(Node* node); - Node* rotateRight(Node* node); - - size_t getHeight(Node* node) const; - void fixHeight(Node* node); - - int getBalance(Node* node) const; - Node* doBalance(Node* node); - - Node* nextInternal(Node* node) const; - Node* prevInternal(Node* node) const; - - void Swap(Set &other); - - static Node* getLeftMost(Node* node) - { - if (!node) - { - return nullptr; - } - while (node->left) - { - node = node->left; - } - return node; - } - static Node* getRightMost(Node* node) - { - if (!node) - { - return nullptr; - } - while (node->right) - { - node = node->right; - } - return node; - } - - - + friend class Iterator; + // корень дерева + Node *m_root = nullptr; + // узлы двусвязного списка + Node *m_first = nullptr; + std::optional m_first_value = std::nullopt; + Node *m_last = nullptr; + std::optional m_last_value = std::nullopt; + + Cmp m_cmp; + size_type m_size = 0; + + void setNodeEnd(); + + Node *findInternal(const_reference data) const; + Node *lower_boundInternal(const_reference data) const; + Node *eraseInternal(Node *node, const_reference data); + Node *insertInternal(Node *node, const_reference data); + + Node *detachReplacement(Node *node); + Node *findReplacement(Node *node) const; + + Node *rotateLeft(Node *node); + Node *rotateRight(Node *node); + + size_t getHeight(Node *node) const; + void fixHeight(Node *node); + + int getBalance(Node *node) const; + Node *doBalance(Node *node); + + Node *nextInternal(Node *node) const; + Node *prevInternal(Node *node) const; + + void Swap(Set &other); + + static Node *getLeftMost(Node *node) + { + if (!node) + { + return nullptr; + } + while (node->left) + { + node = node->left; + } + return node; + } + static Node *getRightMost(Node *node) + { + if (!node) + { + return nullptr; + } + while (node->right) + { + node = node->right; + } + return node; + } }; - -#include "set_definition.h" - +#include "set_definition.hpp" diff --git a/set_lib/include/set_definition.h b/set_lib/include/set_definition.hpp similarity index 72% rename from set_lib/include/set_definition.h rename to set_lib/include/set_definition.hpp index e7cad3f..dea1fff 100644 --- a/set_lib/include/set_definition.h +++ b/set_lib/include/set_definition.hpp @@ -1,19 +1,16 @@ #pragma once -#include -#include - #include "set.h" template -Set::Set(Cmp cmp) : m_cmp(cmp), m_root(nullptr) -{ +Set::Set(Cmp cmp) : m_cmp(cmp), m_root(nullptr) +{ } template template -Set::Set(InputIt first, InputIt last, Cmp cmp) : m_cmp(cmp) -{ +Set::Set(InputIt first, InputIt last, Cmp cmp) : m_cmp(cmp) +{ for (; first != last; ++first) { insert(*first); @@ -23,14 +20,14 @@ Set::Set(InputIt first, InputIt last, Cmp cmp) : m_cmp(cmp) template Set::Set(std::initializer_list const &init_list) { - for (auto && elem : init_list) + for (auto &&elem : init_list) { insert(elem); } } template -template +template Set::Set(Set const &other) { for (auto elem : other) @@ -39,7 +36,6 @@ Set::Set(Set const &other) } } - template Set::Set(Set const &other) { @@ -62,9 +58,8 @@ Set::~Set() } } - template -Set& Set::operator=(Set other) +Set &Set::operator=(Set other) { Swap(other); return *this; @@ -114,25 +109,25 @@ void Set::insert(const T &data) ptr->next->prev = ptr; } } - + template -Iterator Set::find(const T &data) const +Iterator Set::find(const T &data) const { - auto ptr = findInternal(data); + auto ptr = findInternal(data); return ptr ? Iterator(ptr, m_root) : end(); } template Iterator Set::lower_bound(const T &data) const { - auto ptr = lower_boundInternal(data); + auto ptr = lower_boundInternal(data); return ptr ? Iterator(ptr, m_root) : end(); } template -typename Set::Node* Set::findInternal(const T &data) const +typename Set::Node *Set::findInternal(const T &data) const { - Node* node = m_root; + Node *node = m_root; while (node) { if (!m_cmp(node->data, data) && !m_cmp(data, node->data)) @@ -152,10 +147,10 @@ typename Set::Node* Set::findInternal(const T &data) const } template -typename Set::Node* Set::lower_boundInternal(const T &data) const +typename Set::Node *Set::lower_boundInternal(const T &data) const { - Node* node = m_root; - Node* result = nullptr; + Node *node = m_root; + Node *result = nullptr; while (node) { if (m_cmp(node->data, data)) @@ -164,23 +159,23 @@ typename Set::Node* Set::lower_boundInternal(const T &data) cons } else { - result = node; + result = node; node = node->left; } } return result; } - + template void Set::erase(const T &data) -{ +{ auto ptr = findInternal(data); if (ptr != nullptr) { auto prevNode = prevInternal(ptr); auto nextNode = nextInternal(ptr); // извлекаем из списка - if ( !(prevNode == nullptr && nextNode == nullptr) ) + if (!(prevNode == nullptr && nextNode == nullptr)) { if (prevNode == nullptr) { @@ -204,12 +199,10 @@ void Set::erase(const T &data) } template -typename Set::Node* Set::eraseInternal(Node* node, const T &data) +typename Set::Node *Set::eraseInternal(Node *node, const T &data) { if (!node) - { return nullptr; - } if (m_cmp(node->data, data)) { node->right = eraseInternal(node->right, data); @@ -228,16 +221,16 @@ typename Set::Node* Set::eraseInternal(Node* node, const T &data } else { - Node* left = node->left; - Node* right = node->right; - + Node *left = node->left; + Node *right = node->right; + if (!right) - { + { delete node; return left; - } - - Node* replace = findReplacement(right); + } + + Node *replace = findReplacement(right); replace->right = detachReplacement(right); if (replace->right) { @@ -249,89 +242,79 @@ typename Set::Node* Set::eraseInternal(Node* node, const T &data replace->left->parent = replace; } // на выходе из рекурсии редактируем parent - replace->parent = node->parent; + replace->parent = node->parent; delete node; - + return doBalance(replace); } return doBalance(node); } template -typename Set::Node* Set::findReplacement(Node* node) const +typename Set::Node *Set::findReplacement(Node *node) const { if (!node) - { return nullptr; - } while (node->left) - { + { node = node->left; - } + } return node; } template -typename Set::Node* Set::detachReplacement(Node* node) +typename Set::Node *Set::detachReplacement(Node *node) { if (!node) - { return nullptr; - } if (!node->left) - { - return node->right; - } - node->left = detachReplacement(node->left); - if (node->left) { - node->left->parent = node; + return node->right; } + node->left = detachReplacement(node->left); return doBalance(node); } template -typename Set::Node* Set::insertInternal(Node* node, const T &data) +typename Set::Node *Set::insertInternal(Node *node, const T &data) { if (!node) - { - return new Node(data); - } + { + return new Node(data); + } if (m_cmp(data, node->data)) { node->left = insertInternal(node->left, data); // nullptr не возвращается, т.к. вставка обязательна - node->left->parent = node; + node->left->parent = node; } else if (m_cmp(node->data, data)) { node->right = insertInternal(node->right, data); - node->right->parent = node; + node->right->parent = node; } return doBalance(node); } template -size_t Set::getHeight(Node* node) const +size_t Set::getHeight(Node *node) const { return node ? node->height : 0; } template -void Set::fixHeight(Node* node) +void Set::fixHeight(Node *node) { node->height = std::max(getHeight(node->left), getHeight(node->right)) + 1; } template -typename Set::Node* Set::rotateLeft(Node* node) +typename Set::Node *Set::rotateLeft(Node *node) { if (!node) - { return nullptr; - } - Node* tmp = node->right; + Node *tmp = node->right; node->right = tmp->left; if (tmp->left) { @@ -346,93 +329,82 @@ typename Set::Node* Set::rotateLeft(Node* node) } template -typename Set::Node* Set::rotateRight(Node* node) +typename Set::Node *Set::rotateRight(Node *node) { if (!node) - { return nullptr; - } - // node = a - // tmp = node->left = b - Node* tmp = node->left; - node->left = tmp->right; // теперь a->left = C + Node *tmp = node->left; + node->left = tmp->right; if (tmp->right) { tmp->right->parent = node; } - tmp->right = node; // теперь b->right = a + tmp->right = node; tmp->parent = node->parent; node->parent = tmp; - + fixHeight(node); fixHeight(tmp); return tmp; } template -int Set::getBalance(Node* node) const +int Set::getBalance(Node *node) const { return getHeight(node->right) - getHeight(node->left); } template -typename Set::Node* Set::doBalance(Node* node) +typename Set::Node *Set::doBalance(Node *node) { if (!node) - { return nullptr; - } fixHeight(node); - + switch (getBalance(node)) { - case 2: + case 2: { + if (getBalance(node->right) < 0) { - if (getBalance(node->right) < 0) - { - node->right = rotateRight(node->right); - } - return rotateLeft(node); + node->right = rotateRight(node->right); } - case -2: + return rotateLeft(node); + } + case -2: { + if (getBalance(node->left) > 0) { - if (getBalance(node->left) > 0) - { - node->left = rotateLeft(node->left); - } - return rotateRight(node); + node->left = rotateLeft(node->left); } - default: - { - return node; - } + return rotateRight(node); + } + default: { + return node; + } } } - template -Iterator Set::begin() const +Iterator Set::begin() const { if (!m_root) { return end(); - -} return Iterator(m_first, m_root); + } + return Iterator(m_first, m_root); } template -Iterator Set::end() const +Iterator Set::end() const { return Iterator(nullptr, m_root, true); } template -typename Set::Node* Set::nextInternal(Node* node) const +typename Set::Node *Set::nextInternal(Node *node) const { if (!node) - { return nullptr; - } + if (node->right) { node = node->right; @@ -440,10 +412,10 @@ typename Set::Node* Set::nextInternal(Node* node) const } else { - Node* needed_parent = node->parent; + Node *needed_parent = node->parent; while (needed_parent && needed_parent->left != node) { - node = needed_parent; + node = needed_parent; needed_parent = node->parent; } return needed_parent; @@ -451,12 +423,10 @@ typename Set::Node* Set::nextInternal(Node* node) const } template -typename Set::Node* Set::prevInternal(Node* node) const +typename Set::Node *Set::prevInternal(Node *node) const { if (!node) - { return nullptr; - } if (node->left) { node = node->left; @@ -464,10 +434,10 @@ typename Set::Node* Set::prevInternal(Node* node) const } else { - Node* needed_parent = node->parent; + Node *needed_parent = node->parent; while (needed_parent && needed_parent->right != node) { - node = needed_parent; + node = needed_parent; needed_parent = node->parent; } return needed_parent; @@ -506,16 +476,3 @@ bool Set::operator!=(Set const &other) const { return !(*this == other); } - - -template -void Set::show() -{ - Node *node = m_first; - while (node) - { - std::cout << node->data << " "; - node = node->next; - } - std::cout << std::endl; -} diff --git a/tests/test_cases_alexey_halaidzhy.cpp b/tests/test_cases_alexey_halaidzhy.cpp index f0d2ed5..e77e0be 100644 --- a/tests/test_cases_alexey_halaidzhy.cpp +++ b/tests/test_cases_alexey_halaidzhy.cpp @@ -1,214 +1,234 @@ -#include "set.h" #include "iterator.h" -#include -#include +#include "set.h" #include +#include +#include -void fail(const char *message) { - std::cerr << "Fail:\n"; - std::cerr << message << "\n"; - std::cout << "-1 bad output\n"; // to get WA - exit(0); +void fail(const char *message) +{ + std::cerr << "Fail:\n"; + std::cerr << message << "\n"; + std::cout << "-1 bad output\n"; // to get WA + exit(0); } -void check_constness() { - std::cerr << "check constness... "; - const Set s{-4, 5, 3, 0, 7}; - if (s.find(3) == s.end()) - fail("3 not found, incorrect find"); - if (*s.lower_bound(2) != 3 || s.lower_bound(8) != s.end() || *s.lower_bound(-2) != 0) - fail("incorrect lower_bound"); - if (s.empty()) - fail("incorrect empty"); - if (s.size() != 5) - fail("incorrect size"); - auto first = s.begin(); - Set::iterator last = s.end(); - if (*first != -4 || *(--last) != 7) - fail("incorrect begin or end"); - std::cerr << "ok!\n"; +void check_constness() +{ + std::cerr << "check constness... "; + const Set s{-4, 5, 3, 0, 7}; + if (s.find(3) == s.end()) + fail("3 not found, incorrect find"); + if (*s.lower_bound(2) != 3 || s.lower_bound(8) != s.end() || *s.lower_bound(-2) != 0) + fail("incorrect lower_bound"); + if (s.empty()) + fail("incorrect empty"); + if (s.size() != 5) + fail("incorrect size"); + auto first = s.begin(); + Set::iterator last = s.end(); + if (*first != -4 || *(--last) != 7) + fail("incorrect begin or end"); + std::cerr << "ok!\n"; } /* check if class correctly implements * copy constructor and = operator */ -void check_copy_correctness() { - std::cerr << "check copy... "; - int elems[] = {3, 3, -1, 6, 0, 0, 17, -5, 4, 2}; - Set s1(elems, elems + 10); - std::set set_elems(elems, elems + 10); - Set s2 = s1; - s2.insert(5); - s2.insert(18); - s2.insert(-2); - auto s1_it = s1.begin(), s2_it = s2.begin(); - auto s_it = set_elems.begin(); - while (s1_it != s1.end() || s2_it != s2.end() || s_it != set_elems.end()) { - if (*s2_it == 5 || *s2_it == 18 || *s2_it == -2) { - ++s2_it; - continue; - } - if (*s1_it != *s2_it || *s1_it != *s_it || *s2_it != *s_it) - fail("fail after copy construction and insertions"); - ++s1_it, ++s2_it, ++s_it; - } - - s1 = s2; - s2.insert(19); - auto cur_end = s2.end(); - cur_end--; - s1_it = s1.begin(), s2_it = s2.begin(); - while (s1_it != s1.end() || s2_it != cur_end) { - if (*s1_it != *s2_it) - fail("wrong = operator"); - ++s1_it, ++s2_it; - } - - - s1 = s1 = s2; - s1_it = s1.begin(), s2_it = s2.begin(); - while (s1_it != s1.end() || s2_it != s2.end()) { - if (*s1_it != *s2_it) - fail("wrong = operator"); - ++s1_it, ++s2_it; - } - std::cerr << "ok!\n"; +void check_copy_correctness() +{ + std::cerr << "check copy... "; + int elems[] = {3, 3, -1, 6, 0, 0, 17, -5, 4, 2}; + Set s1(elems, elems + 10); + std::set set_elems(elems, elems + 10); + Set s2 = s1; + s2.insert(5); + s2.insert(18); + s2.insert(-2); + auto s1_it = s1.begin(), s2_it = s2.begin(); + auto s_it = set_elems.begin(); + while (s1_it != s1.end() || s2_it != s2.end() || s_it != set_elems.end()) + { + if (*s2_it == 5 || *s2_it == 18 || *s2_it == -2) + { + ++s2_it; + continue; + } + if (*s1_it != *s2_it || *s1_it != *s_it || *s2_it != *s_it) + fail("fail after copy construction and insertions"); + ++s1_it, ++s2_it, ++s_it; + } + + s1 = s2; + s2.insert(19); + auto cur_end = s2.end(); + cur_end--; + s1_it = s1.begin(), s2_it = s2.begin(); + while (s1_it != s1.end() || s2_it != cur_end) + { + if (*s1_it != *s2_it) + fail("wrong = operator"); + ++s1_it, ++s2_it; + } + + s1 = s1 = s2; + s1_it = s1.begin(), s2_it = s2.begin(); + while (s1_it != s1.end() || s2_it != s2.end()) + { + if (*s1_it != *s2_it) + fail("wrong = operator"); + ++s1_it, ++s2_it; + } + std::cerr << "ok!\n"; } /* check if class correctly handles empty set */ -void check_empty() { - std::cerr << "check empty set handling... "; - Set s; - if (!s.empty()) - fail("wrong empty"); - auto begin = s.begin(), end = s.end(); - if (begin != end) - fail("incorrect handling empty set"); - std::string elem("abacaba"); - s.insert(elem); - if (*s.lower_bound("aac") != elem) - fail("wrong lower_bound"); - Set empty; - Set s2{"opa"}; - s2 = empty; - if (s2.size()) - fail("incorrect size"); - Set s3(s2); - if (!s3.empty()) - fail("incorrect empty"); - std::cerr << "ok!\n"; +void check_empty() +{ + std::cerr << "check empty set handling... "; + Set s; + if (!s.empty()) + fail("wrong empty"); + auto begin = s.begin(), end = s.end(); + if (begin != end) + fail("incorrect handling empty set"); + std::string elem("abacaba"); + s.insert(elem); + if (*s.lower_bound("aac") != elem) + fail("wrong lower_bound"); + Set empty; + Set s2{"opa"}; + s2 = empty; + if (s2.size()) + fail("incorrect size"); + Set s3(s2); + if (!s3.empty()) + fail("incorrect empty"); + std::cerr << "ok!\n"; } /* check if class correctly works with iterators */ -void check_iterators() { - std::cerr << "check iterators... "; - Set > s{{-3, 5}, {5, 5}, {-4, 1}, {-4, 4}, {0, 1}, {3, 0}}; - if (s.begin()->second != 1 || (++s.begin())->first != -4) - fail("wrong begin()"); - Set >::iterator cur = s.end(); - Set small{1}; - Set::iterator it; - it = small.begin(); - if (*it != 1) - fail("incorrect begin"); - auto begin = s.begin(); - begin++; - cur--; - if (begin == cur) - fail("wrong == for iterators"); - while (begin != cur) { - ++begin; - --cur; - } - if (*begin != *cur) - fail("wrong Iterators"); - std::cerr << "ok!\n"; +void check_iterators() +{ + std::cerr << "check iterators... "; + Set> s{{-3, 5}, {5, 5}, {-4, 1}, {-4, 4}, {0, 1}, {3, 0}}; + if (s.begin()->second != 1 || (++s.begin())->first != -4) + fail("wrong begin()"); + Set>::iterator cur = s.end(); + Set small{1}; + Set::iterator it; + it = small.begin(); + if (*it != 1) + fail("incorrect begin"); + auto begin = s.begin(); + begin++; + cur--; + if (begin == cur) + fail("wrong == for iterators"); + while (begin != cur) + { + ++begin; + --cur; + } + if (*begin != *cur) + fail("wrong Iterators"); + std::cerr << "ok!\n"; } -struct StrangeInt { - int x; - static int counter; - StrangeInt() { - ++counter; - } - StrangeInt(int x): x(x) { - ++counter; - } - StrangeInt(const StrangeInt& rs): x(rs.x) { - ++counter; - } - bool operator <(const StrangeInt& rs) const { - return x < rs.x; - } - - static void init() { - counter = 0; - } - - ~StrangeInt() { - --counter; - } - - friend std::ostream& operator <<(std::ostream& out, const StrangeInt& x) { - out << x.x; - return out; - } +struct StrangeInt +{ + int x; + static int counter; + StrangeInt() + { + ++counter; + } + StrangeInt(int x) : x(x) + { + ++counter; + } + StrangeInt(const StrangeInt &rs) : x(rs.x) + { + ++counter; + } + bool operator<(const StrangeInt &rs) const + { + return x < rs.x; + } + + static void init() + { + counter = 0; + } + + ~StrangeInt() + { + --counter; + } + + friend std::ostream &operator<<(std::ostream &out, const StrangeInt &x) + { + out << x.x; + return out; + } }; int StrangeInt::counter; /* check if class uses only < for elements comparing */ -void check_operator_less() { - std::cerr << "check operator <... "; - - Set s{-5, -3, -6, 13, 7, 1000, 963}; - auto it = s.lower_bound(999); - ++it; - if (it != s.end()) - fail("wrong ++ for iterator"); - std::cerr << "ok!\n"; +void check_operator_less() +{ + std::cerr << "check operator <... "; + + Set s{-5, -3, -6, 13, 7, 1000, 963}; + auto it = s.lower_bound(999); + ++it; + if (it != s.end()) + fail("wrong ++ for iterator"); + std::cerr << "ok!\n"; } /* check if class correctly implements destructor */ -void check_destructor() { - std::cerr << "check destructor... "; - StrangeInt::init(); - { - Set s{5, 4, 3, 2, 1, 0}; - if (s.size() != 6) - fail("wrong size"); - } - if (StrangeInt::counter) - fail("wrong destructor (or constructors)"); - { - Set s{-3, 3, -2, 2, -1, 1}; - Set s1(s); - s1.insert(0); - Set s2(s1); - if (s1.find(0) == s1.end()) - fail("wrong find"); - s1 = s; - if (s1.find(0) != s1.end()) - fail("wrong find"); - } - if (StrangeInt::counter) - fail("wrong destructor (or constructors)"); - std::cerr << "ok!\n"; +void check_destructor() +{ + std::cerr << "check destructor... "; + StrangeInt::init(); + { + Set s{5, 4, 3, 2, 1, 0}; + if (s.size() != 6) + fail("wrong size"); + } + if (StrangeInt::counter) + fail("wrong destructor (or constructors)"); + { + Set s{-3, 3, -2, 2, -1, 1}; + Set s1(s); + s1.insert(0); + Set s2(s1); + if (s1.find(0) == s1.end()) + fail("wrong find"); + s1 = s; + if (s1.find(0) != s1.end()) + fail("wrong find"); + } + if (StrangeInt::counter) + fail("wrong destructor (or constructors)"); + std::cerr << "ok!\n"; } /* check erase for correctness */ -void check_erase() { - std::cerr << "check erase... "; - Set s{"abacaba", "hello", "p"}; - s.erase("miss"); - s.erase("hello"); - if (s.size() != 2) - fail("Bad size"); - s.erase("p"); - if (*s.begin() != "abacaba") - fail("Bad begin"); - s.erase("1"); - s.erase("abacaba"); - s.erase("012"); - if (!s.empty()) - fail("Bad empty"); - std::cerr << "ok!\n"; +void check_erase() +{ + std::cerr << "check erase... "; + Set s{"abacaba", "hello", "p"}; + s.erase("miss"); + s.erase("hello"); + if (s.size() != 2) + fail("Bad size"); + s.erase("p"); + if (*s.begin() != "abacaba") + fail("Bad begin"); + s.erase("1"); + s.erase("abacaba"); + s.erase("012"); + if (!s.empty()) + fail("Bad empty"); + std::cerr << "ok!\n"; } diff --git a/tests/test_set.cpp b/tests/test_set.cpp index ec2d79e..b1d74b0 100644 --- a/tests/test_set.cpp +++ b/tests/test_set.cpp @@ -1,47 +1,45 @@ +#include "iterator.h" +#include "set.h" #include +#include #include #include -#include -#include "set.h" -#include "iterator.h" template void TestInsertErase(Set &set, std::istream &in) { char op; - T data; + T data; while (in >> op >> data) - { - switch (op) - { - case '+': - { - set.insert(data); - break; - } - case '-': - { - set.erase(data); - break; - } - } - } + { + switch (op) + { + case '+': { + set.insert(data); + break; + } + case '-': { + set.erase(data); + break; + } + } + } } TEST(TestBasicsFunctional, Test_Insert_Erase_Find_LowerBound) { Set set; - EXPECT_EQ(set.size(), 0); - EXPECT_TRUE(set.empty()); + EXPECT_EQ(set.size(), 0); + EXPECT_TRUE(set.empty()); // fill 1..9, -20, 20 - // remove odd + // remove odd std::string strTest = "+ 1 + 1 + 2 + 2 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 - 2 - 4 - 6 - 8 -8 -8 + -20 + 20"; std::istringstream stream(strTest); TestInsertErase(set, stream); - EXPECT_EQ(set.size(), 7); - EXPECT_TRUE(!set.empty()); + EXPECT_EQ(set.size(), 7); + EXPECT_TRUE(!set.empty()); EXPECT_EQ(*(set.find(1)), 1); EXPECT_EQ(*(set.find(3)), 3); @@ -55,124 +53,182 @@ TEST(TestBasicsFunctional, Test_Insert_Erase_Find_LowerBound) EXPECT_EQ(*(set.lower_bound(9)), 9); EXPECT_EQ(*(set.lower_bound(-100)), -20); - // EXPECT_EQ: отсутствие оператора == ... + // EXPECT_EQ: отсутствие оператора == ... EXPECT_TRUE(set.find(2) == set.end()); EXPECT_TRUE(set.find(4) == set.end()); EXPECT_TRUE(set.find(6) == set.end()); EXPECT_TRUE(set.find(8) == set.end()); - set.erase(12345); - for (auto elem : {1, 3, 5, 7, 9, -20}) - { - set.erase(elem); - } - EXPECT_EQ(set.size(), 1); - set.erase(20); - EXPECT_EQ(set.size(), 0); - set.erase(20); - set.erase(2001); + set.erase(12345); + for (auto elem : {1, 3, 5, 7, 9, -20}) + { + set.erase(elem); + } + EXPECT_EQ(set.size(), 1); + set.erase(20); + EXPECT_EQ(set.size(), 0); + set.erase(20); + set.erase(2001); } TEST(TestBasicsFunctional, Test_Increment_Decrement_Begin_End) { - Set set; - EXPECT_TRUE(set.begin() == set.end()); - set = {10, 20, 30, 40, 50, 60, 70, 80, 90}; - Set::iterator it = set.find(40); - EXPECT_TRUE(it != set.end()); - EXPECT_EQ(*it, 40); - EXPECT_EQ(*(--it), 30); - EXPECT_EQ(*(it++), 30); - EXPECT_EQ(*(it), 40); - EXPECT_EQ(*(++it), 50); - EXPECT_TRUE(it == set.find(50)); - EXPECT_TRUE(it != set.find(70)); - EXPECT_EQ(*set.begin(), 10); - EXPECT_EQ(*(++set.begin()), 20); - // РАБОТАЕТ!!! - EXPECT_EQ(*(--set.end()), 90); + Set set; + EXPECT_TRUE(set.begin() == set.end()); + set = {10, 20, 30, 40, 50, 60, 70, 80, 90}; + Set::iterator it = set.find(40); + EXPECT_TRUE(it != set.end()); + EXPECT_EQ(*it, 40); + EXPECT_EQ(*(--it), 30); + EXPECT_EQ(*(it++), 30); + EXPECT_EQ(*(it), 40); + EXPECT_EQ(*(++it), 50); + EXPECT_TRUE(it == set.find(50)); + EXPECT_TRUE(it != set.find(70)); + EXPECT_EQ(*set.begin(), 10); + EXPECT_EQ(*(++set.begin()), 20); + // РАБОТАЕТ!!! + EXPECT_EQ(*(--set.end()), 90); +} + +struct A +{ + int a; + int b; + bool operator<(A const &right) const + { + return a < right.a; + } +}; + +TEST(TestBasicsFunctional, Test_Before_Begin) +{ + Set set; + set = {{1, 2}, {3, 4}, {5, 6}}; + auto it = set.begin(); + it--; + EXPECT_THROW(*it, std::exception); + EXPECT_THROW(it->a, std::exception); + ++it; + EXPECT_EQ(it->b, 2); +} + +TEST(TestBasicsFunctional, Test_Strange) +{ + Set set; + auto it = set.end(); + ++it; + --it; + set.insert(55); + EXPECT_EQ(*(set.find(55)), 55); +} + +TEST(TestBasicsFunctional, Test_Iterator_default_ctor) +{ + Set set = {1, 2, 3}; + Set::iterator it; + it = set.begin(); + EXPECT_EQ(*it, 1); +} + +TEST(TestBasicsFunctional, Test_Insert_Erase_Random) +{ + Set set = {4, 6, 2}; + set.insert(1); + set.insert(3); + set.insert(45); + set.insert(13); + set.insert(78); + set.insert(-13); + set.insert(-345); + set.insert(-6); + set.erase(1); + set.erase(-13); + set.erase(-345); + set.erase(2); + set.erase(45); + set.insert(777); + set.erase(78); + set.erase(777); } TEST(TestBasicsFunctional, Test_Ctor_CopyCtor_AssignOperator) { - Set set1 = {1, 2, 3, 4, 5}; - Set set2(set1.begin(), set1.end()); - EXPECT_EQ(set1, set2); - set2.erase(4); - EXPECT_NE(set1, set2); - - set2 = set1; - EXPECT_EQ(set1, set2); - - auto it1 = set1.find(2); - auto it2 = set1.find(5); - Set set3(it1, it2); - EXPECT_EQ(set3.size(), 3); - auto it = set3.begin(); - for (auto elem : {2, 3, 4}) - { - EXPECT_EQ(*it, elem); - ++it; - } + Set set0 = {1, 2, 3, 4, 5}; + Set set1(set0); + Set set2(set1.begin(), set1.end()); + EXPECT_EQ(set1, set2); + set2.erase(4); + EXPECT_NE(set1, set2); + + set2 = set1; + EXPECT_EQ(set1, set2); + + auto it1 = set1.find(2); + auto it2 = set1.find(5); + Set set3(it1, it2); + EXPECT_EQ(set3.size(), 3); + auto it = set3.begin(); + for (auto elem : {2, 3, 4}) + { + EXPECT_EQ(*it, elem); + ++it; + } } TEST(TestBasicsFunctional, Test_Compatibility_with_STL_Next_Advance_Prev) { - // for range выше - Set set = {1, 2, 3, 4, 5}; - Set::iterator it = set.begin(); - std::advance(it, 3); - EXPECT_EQ(*it, 4); - auto it2 = std::next(it); - EXPECT_EQ(*it2, 5); - it2 = std::prev(it, 2); - EXPECT_EQ(*it2, 2); + // for range выше + Set set = {1, 2, 3, 4, 5}; + Set::iterator it = set.begin(); + std::advance(it, 3); + EXPECT_EQ(*it, 4); + auto it2 = std::next(it); + EXPECT_EQ(*it2, 5); + it2 = std::prev(it, 2); + EXPECT_EQ(*it2, 2); } TEST(TestBasicsFunctional, Test_Compatibility_with_STL_Vector) { - std::vector vec = {1, 2, 3, 4, 5}; - Set set(vec.begin(), vec.end()); - auto it = set.begin(); - for (auto &&elem : vec) - { - EXPECT_EQ(*it, elem); - ++it; - } - - int count = std::count_if(set.begin(), set.end(), [](int data) - { - return data % 2 == 0; - }); - EXPECT_EQ(count, 2); - - // CORRECT ERROR: no matching function for call to ‘Set::insert(Set::iterator&, const value_type&)’ - - std::vector vec2; - std::copy(set.begin(), set.end(), std::back_inserter(vec2)); - size_t index = 0; - for (auto &&elem : set) - { - EXPECT_EQ(elem, vec2[index]); - index++; - } - - - /* - - CORRECT ERROR: no matching function for call to ‘Set::insert(Set::iterator&, const value_type&)’ - Set set2 = {-2, -1, 0, 6}; - std::copy(set.begin(), set.end(), std::inserter(set2, set2.begin())); - */ - /* - нельзя, т.к. итератор константный - auto square = [](int &data) - { - data * data; - }; - std::for_each(set.begin(), set.end(), square); - - */ + std::vector vec = {1, 2, 3, 4, 5}; + Set set(vec.begin(), vec.end()); + auto it = set.begin(); + for (auto &&elem : vec) + { + EXPECT_EQ(*it, elem); + ++it; + } + + int count = std::count_if(set.begin(), set.end(), [](int data) { return data % 2 == 0; }); + EXPECT_EQ(count, 2); + + // CORRECT ERROR: no matching function for call to ‘Set::insert(Set::iterator&, const value_type&)’ + + std::vector vec2; + std::copy(set.begin(), set.end(), std::back_inserter(vec2)); + size_t index = 0; + for (auto &&elem : set) + { + EXPECT_EQ(elem, vec2[index]); + index++; + } + + /* + + CORRECT ERROR: no matching function for call to ‘Set::insert(Set::iterator&, const value_type&)’ + Set set2 = {-2, -1, 0, 6}; + std::copy(set.begin(), set.end(), std::inserter(set2, set2.begin())); + */ + /* + нельзя, т.к. итератор константный + auto square = [](int &data) + { + data * data; + }; + std::for_each(set.begin(), set.end(), square); + + */ } extern void check_constness(); @@ -185,12 +241,12 @@ extern void check_erase(); TEST(TestOther, Test_Alexey_Halaidzhy) { - // в тест кейсах exit(0) при ошибках, поэтому фейл будет отображен - check_constness(); - check_copy_correctness(); - check_empty(); - check_iterators(); - check_operator_less(); - check_destructor(); - check_erase(); + // в тест кейсах exit(0) при ошибках, поэтому фейл будет отображен + check_constness(); + check_copy_correctness(); + check_empty(); + check_iterators(); + check_operator_less(); + check_destructor(); + check_erase(); } From d4dd974b984952f064e37c0d0fb67778c859d4d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9C=D1=8F=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D1=86?= Date: Sat, 3 Dec 2022 13:37:25 +0300 Subject: [PATCH 20/20] small fix tests --- set_lib/include/set_definition.hpp | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/set_lib/include/set_definition.hpp b/set_lib/include/set_definition.hpp index dea1fff..30f1169 100644 --- a/set_lib/include/set_definition.hpp +++ b/set_lib/include/set_definition.hpp @@ -201,8 +201,7 @@ void Set::erase(const T &data) template typename Set::Node *Set::eraseInternal(Node *node, const T &data) { - if (!node) - return nullptr; + if (!node) return nullptr; if (m_cmp(node->data, data)) { node->right = eraseInternal(node->right, data); @@ -253,8 +252,7 @@ typename Set::Node *Set::eraseInternal(Node *node, const T &data template typename Set::Node *Set::findReplacement(Node *node) const { - if (!node) - return nullptr; + if (!node) return nullptr; while (node->left) { node = node->left; @@ -265,8 +263,7 @@ typename Set::Node *Set::findReplacement(Node *node) const template typename Set::Node *Set::detachReplacement(Node *node) { - if (!node) - return nullptr; + if (!node) return nullptr; if (!node->left) { return node->right; @@ -312,8 +309,7 @@ void Set::fixHeight(Node *node) template typename Set::Node *Set::rotateLeft(Node *node) { - if (!node) - return nullptr; + if (!node) return nullptr; Node *tmp = node->right; node->right = tmp->left; if (tmp->left) @@ -331,8 +327,7 @@ typename Set::Node *Set::rotateLeft(Node *node) template typename Set::Node *Set::rotateRight(Node *node) { - if (!node) - return nullptr; + if (!node) return nullptr; Node *tmp = node->left; node->left = tmp->right; if (tmp->right) @@ -357,8 +352,7 @@ int Set::getBalance(Node *node) const template typename Set::Node *Set::doBalance(Node *node) { - if (!node) - return nullptr; + if (!node) return nullptr; fixHeight(node); switch (getBalance(node)) @@ -402,8 +396,7 @@ Iterator Set::end() const template typename Set::Node *Set::nextInternal(Node *node) const { - if (!node) - return nullptr; + if (!node) return nullptr; if (node->right) { @@ -425,8 +418,7 @@ typename Set::Node *Set::nextInternal(Node *node) const template typename Set::Node *Set::prevInternal(Node *node) const { - if (!node) - return nullptr; + if (!node) return nullptr; if (node->left) { node = node->left;