win32实现红黑树插入删除

common.h

#ifndef _COMMON_H_
#define _COMMON_H_

#define APP_NAME ("RBTreeGUI")
#define OPR_NAME ("OprWnd")

#define TOP_OFFSET (10)
#define BUTTOM_OFFSET (30)
#define NODE_WIDTH (30)
#define NODE_HIGHT (30)
#define TEXT_TOP_OFFSET (7)
#define NODE_WIDTH_OFFSET  (5)
#define NODE_HIGHT_OFFSET  (NODE_HIGHT + 10)


#define WM_OPR_KEY    (WM_USER + 1)
#define WM_ADDNODE    (WM_USER + 2)
#define WM_DELNODE    (WM_USER + 3)
#define WM_MODNODE    (WM_USER + 4)
#define WM_FINDNODE   (WM_USER + 5)
#define WM_WORKLIST   (WM_USER + 6)
#define WM_START_STOP (WM_USER + 7)
#define WM_NEXT_STEP  (WM_USER + 8)
#define WM_AUTO       (WM_USER + 10)

#define STEP_TIMERID  (1000)
struct OprData
{
    int cmd;
    int key;

    OprData(){}
    OprData(const OprData& rst)
    {
        this->cmd = rst.cmd;
        this->key = rst.key;
    }

    bool operator==(const OprData& src)
    {
        if (this->cmd == src.cmd &&
            this->key == src.key)
        {
            return true;
        }

        return false;
    }
};

#endif

filelog.h

#ifndef _FILE_LOG_H_
#define _FILE_LOG_H_

#define LOG_DIR ("log")
#define LOG_FILENAME ("rbtree")

class FileLog
{
public:
    enum 
    {
        TYPE_DEBUG,
        TYPE_INFO,
        TYPE_ERROR,
        TYPE_RAW
    };
private:
    static FileLog* pThis;
private:
    char szPath[1024];
    void* hMutex;

public:
    static FileLog* getInstance()
    {
        if (!pThis)
        {
            pThis = new FileLog;
            pThis->init();
        }

        return pThis;
    }

    FileLog();
    ~FileLog();

public:
    void init();
    void uninit();
    void doLog(const char* file, const int lineno, const char* func,int level, const char* fmt, ...);

};

#define LOGI(fmt, ...) FileLog::getInstance()->doLog(__FILE__, __LINE__, __FUNCTION__, FileLog::TYPE_DEBUG, fmt, __VA_ARGS__)
#define LOGD(fmt, ...) FileLog::getInstance()->doLog(__FILE__, __LINE__, __FUNCTION__, FileLog::TYPE_INFO, fmt, __VA_ARGS__)
#define LOGE(fmt, ...) FileLog::getInstance()->doLog(__FILE__, __LINE__, __FUNCTION__, FileLog::TYPE_ERROR, fmt, __VA_ARGS__)
#define LOGR(fmt, ...) FileLog::getInstance()->doLog(__FILE__, __LINE__, __FUNCTION__, FileLog::TYPE_RAW, fmt, __VA_ARGS__)
#endif

mainWnd.h

#ifndef _MAIN_WND_H_
#define _MAIN_WND_H_

class MainWnd
{
private:
    void* hWnd;
public:
    MainWnd();
    ~MainWnd();

public:
    bool Create(void* hInst, const char* title, int cx, int cy, void* wndproc);
    void Show(int iCmd);
    void* GetHwnd() { return hWnd; }
};





#endif

oprWnd.h

#ifndef _OPR_WND_H_
#define _OPR_WND_H_
#include <list>
#include "common.h"

class OprWnd
{
private:
    void* hWnd;
    void* hWorkList;
    void* hStartStop;
    void* hNextStep;
    void* hAuto;
    bool mStart;
    bool mAuto;

    std::list<OprData> mOprQueue;
    void* hMutex;
    void* hStepSemp;
    bool SempUsed;
public:
    OprWnd();
    ~OprWnd();

private:
    bool GetKeyText(int &key);
    void FormatOpr(const OprData& opr, char* text, size_t sz);

public:
    bool Create(void* hInst, const char* title, int cx, int cy, void* wndproc);
    void Show(int iCmd);
    void* GetHwnd() { return hWnd; }

    void OnAddNode();
    void OnDelNode();
    void OnModNode();
    void OnFindNode();
    void OnStartStop();
    void OnNextStep();
    void OnAuto();

    bool GetNextOpr(OprData& opr);
    bool IsAuto() { return mAuto; }
    void WaitSignal();
};






#endif

RBTree.h

#ifndef _RB_TREE_H_
#define _RB_TREE_H_

#include <utility>
enum
{
    RED = 0,
    BLACK,
    HIGHLIGHT
};

template <typename K, typename V>
class RBTree
{
public:
    RBTree<K, V>* left;
    RBTree<K, V>* right;
    RBTree<K, V>* parent;
    std::pair<K, V> kv;
    unsigned char col;
public:
    RBTree() :
        left(nullptr), 
        right(nullptr), 
        parent(nullptr),
        col(RED)
    {
    }

    RBTree(const std::pair<K, V>& _kv) :
        left(nullptr), 
        right(nullptr), 
        parent(nullptr), 
        kv(_kv),
        col(RED)
    {
    }
    
    ~RBTree(){}
};

#endif

wndMng.h

#ifndef _WND_MNG_H_
#define _WND_MNG_H_

#include "mainWnd.h"
#include "oprWnd.h"
#include "RBTree.h"

typedef struct ElemType 
{
    int count;
    int pos_x;
    int pos_y;
    int paint_x;
    int paint_y;
    bool highlight;
}ElemType;

class WndMng
{
    enum 
    {
        PRE_ORDER,
        IN_ORDER,
        POST_ORDER
    };
private:
    MainWnd mMainWnd;
    OprWnd *mOprWnd;
    RBTree<int, ElemType>* mRbTree;
private:
    void* redBrush;
    void* blackBrush;
    void* highlightBrush;

private:
    int RBTreeCalcPos();
    void RBTreeSimpleInsert(const std::pair<int, ElemType>& item);
    void RBTreeCalcPaintPos(int deep);
    void RBTreePreTraver(RBTree<int, ElemType>* node);
    void RBTreeInTraver(RBTree<int, ElemType>* node);
    void RBTreePostTraver(RBTree<int, ElemType>* node);
    void RBTreeTraver(unsigned char order);

    void RBTreeRotateL(RBTree<int, ElemType>* node); // 左旋树
    void RBTreeRotateR(RBTree<int, ElemType>* node); // 右旋树

    char* RBTreeGetNodeInfo(RBTree<int, ElemType>* cur);
    char* RBTreeGetTreeInfo(RBTree<int, ElemType>* cur, RBTree<int, ElemType>* parent, RBTree<int, ElemType>* grandfather, RBTree<int, ElemType>* uncle);
public:
    void RBTreeInsert(const std::pair<int, ElemType>& key);
    bool RBTreeDelete(const std::pair<int, ElemType>& key);
    RBTree<int, ElemType>* RBTreeFind(const std::pair<int, ElemType>& key);
    RBTree<int, ElemType>* RBTreeModify(const std::pair<int, ElemType>& key);

    void DoWork();
public:
    void OnRButtonUp(void* hwnd, unsigned long lpParam);
    void ReportAndWait();

public:
    WndMng();
    ~WndMng();

    void Init();
    void Create(void* hInst);
    void StartWork();
    void PaintNode(void* hdc, int x, int y, const char* text, unsigned char col = RED, bool highlight = false);
    void PaintTree(void* hdc);
    
    void HideOprWnd();
    void OnOprWndCommand(void* hwnd, unsigned long wParam, unsigned long lParam);
};

#endif

filelog.cpp

#include "../include/filelog.h"
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>

FileLog* FileLog::pThis = NULL;

FileLog::FileLog()
{
    hMutex = NULL;
}

FileLog::~FileLog()
{
    uninit();
}

void FileLog::init()
{
    char appPath[512] = { 0 };
    GetModuleFileNameA(NULL, appPath, sizeof(appPath));

    const char* lpchr = strrchr(appPath, '\\');
    if (!lpchr)
    {
        return;
    }

    char appDir[512] = { 0 };
    strncpy_s(appDir, appPath, lpchr - appPath);
    strcat_s(appDir, "\\log");
    CreateDirectoryA(appDir, NULL);

    time_t now = time(0);
    tm tnow;
    localtime_s(&tnow, &now);
    char szTime[64] = { 0 };
    strftime(szTime, sizeof(szTime), "%Y-%m-%d", &tnow);
    sprintf_s(szPath, sizeof(szPath), "%s\\%s_log.txt", appDir, szTime);

    hMutex = OpenMutexA(SYNCHRONIZE, FALSE, "rbtree");
}

void FileLog::uninit()
{
    if (hMutex)
    {
        CloseHandle(hMutex);
        hMutex = NULL;
    }
}

void FileLog::doLog(const char* file, const int lineno, const char* func, int level, const char* fmt, ...)
{
    char fileBuff[4096] = { 0 };
    va_list ap;
    va_start(ap, fmt);
    vsnprintf_s(fileBuff, sizeof(fileBuff), fmt, ap);
    va_end(ap);
    
    WaitForSingleObject(hMutex, INFINITE);
    FILE* fp = NULL;
    fopen_s(&fp, szPath, "a+");
    if (fp)
    {
        switch (level)
        {
            case TYPE_DEBUG:
                fprintf_s(fp, "[%s:%d %s][DEBUG]%s\n", strrchr(file,'\\')+1, lineno, func, fileBuff);
                break;
            case TYPE_INFO:
                fprintf_s(fp, "[%s:%d %s][INFO]%s\n", strrchr(file, '\\')+1, lineno, func, fileBuff);
                break;
            case TYPE_ERROR:
                fprintf_s(fp, "[%s:%d %s][ERROR]%s\n", strrchr(file, '\\')+1, lineno, func, fileBuff);
                break;
            case TYPE_RAW:
            default:
                fprintf_s(fp, "%s\n", fileBuff);
                break;
        }
        fclose(fp);
    }
    ReleaseMutex(hMutex);
}

mainWnd.cpp

#include "../include/mainWnd.h"
#include "../include/common.h"
#include <windows.h>

MainWnd::MainWnd()
{
    hWnd = NULL;
}

MainWnd::~MainWnd()
{

}

bool MainWnd::Create(void* hInst, const char* title, int cx, int cy, void* wndproc)
{
    WNDCLASSEX wndcls = { 0 };

    wndcls.cbSize = sizeof(wndcls);
    wndcls.style = CS_HREDRAW | CS_VREDRAW;
    wndcls.lpfnWndProc = (WNDPROC)wndproc;
    wndcls.cbClsExtra = 0;
    wndcls.cbWndExtra = 0;
    wndcls.hInstance = (HINSTANCE)hInst;
    wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndcls.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
    wndcls.lpszMenuName = NULL;
    wndcls.lpszClassName = APP_NAME;
    wndcls.hIconSm = NULL;
    wndcls.style &= ~CS_VREDRAW;

    if (!RegisterClassEx(&wndcls))
    {
        MessageBox(NULL, "注册窗口失败", "error", MB_ICONINFORMATION);
        return false;
    }

    hWnd = CreateWindow(APP_NAME,
                        title,
                        WS_OVERLAPPEDWINDOW, 
                        CW_USEDEFAULT, 
                        CW_USEDEFAULT, 
                        cx, 
                        cy, 
                        NULL, 
                        NULL, 
                        (HINSTANCE)hInst,
                        NULL);
    return true;
}

void MainWnd::Show(int iCmd)
{
    if (hWnd)
    {
        ShowWindow((HWND)hWnd, iCmd);
        UpdateWindow((HWND)hWnd);
    }
}

oprWnd.cpp

#include "../include/oprWnd.h"
#include <windows.h>

OprWnd* pOprWnd = NULL;

OprWnd::OprWnd() :
hWnd(0), 
mStart(false), 
mAuto(true),
hMutex(NULL)
{
    pOprWnd = this;
    hStepSemp = NULL;
}

OprWnd::~OprWnd()
{
    if (hMutex)
    {
        CloseHandle(hMutex);
        hMutex = NULL;
    }

    if (hStepSemp)
    {
        CloseHandle(hStepSemp);
        hStepSemp = NULL;
    }
}

void CALLBACK TimeProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime);

bool OprWnd::Create(void* hInst, const char* title, int cx, int cy, void* wndproc)
{
    WNDCLASSEX wndcls = { 0 };

    wndcls.cbSize = sizeof(wndcls);
    wndcls.style = CS_HREDRAW | CS_VREDRAW;
    wndcls.lpfnWndProc = (WNDPROC)wndproc;
    wndcls.cbClsExtra = 0;
    wndcls.cbWndExtra = 0;
    wndcls.hInstance = (HINSTANCE)hInst;
    wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndcls.hbrBackground = static_cast<HBRUSH>(GetStockObject(COLOR_WINDOW));
    wndcls.lpszMenuName = NULL;
    wndcls.lpszClassName = OPR_NAME;
    wndcls.hIconSm = NULL;
    wndcls.style &= ~CS_VREDRAW;

    if (!RegisterClassEx(&wndcls))
    {
        MessageBox(NULL, "注册窗口失败", "error", MB_ICONINFORMATION);
        return false;
    }

    hWnd = CreateWindow(OPR_NAME,
                        title,
                        WS_OVERLAPPEDWINDOW,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        cx,
                        cy,
                        NULL,
                        NULL,
                        (HINSTANCE)hInst,
                        NULL);

    unsigned int LEFT_SHIFT = 10;
    unsigned int TOP_SHIFT = 10;
    unsigned int CTRL_WIDTH = 70;
    unsigned int CTRL_HEIGHT = 20;

    int pos_x = LEFT_SHIFT;
    int pos_y = TOP_SHIFT;

    int key = rand() % 999;
    char szText[32] = { 0 };
    sprintf_s(szText, "%d", key);

    CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", szText, WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,
                    pos_x, pos_y, CTRL_WIDTH, CTRL_HEIGHT, (HWND)hWnd, (HMENU)WM_OPR_KEY, (HINSTANCE)hInst, NULL);
    pos_x += CTRL_WIDTH + 5;
    CreateWindowExA(WS_EX_CLIENTEDGE, "Button", "新增", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
                    pos_x, pos_y, CTRL_WIDTH, CTRL_HEIGHT, (HWND)hWnd, (HMENU)WM_ADDNODE, (HINSTANCE)hInst, NULL);
    pos_x += CTRL_WIDTH + 5;
    CreateWindowExA(WS_EX_CLIENTEDGE, "Button", "删除", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                    pos_x, pos_y, CTRL_WIDTH, CTRL_HEIGHT, (HWND)hWnd, (HMENU)WM_DELNODE, (HINSTANCE)hInst, NULL);

    pos_x += CTRL_WIDTH + 5;
    CreateWindowExA(WS_EX_CLIENTEDGE, "Button", "查找", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                    pos_x, pos_y, CTRL_WIDTH, CTRL_HEIGHT, (HWND)hWnd, (HMENU)WM_FINDNODE, (HINSTANCE)hInst, NULL);
    /**
    pos_x += CTRL_WIDTH + 5;
    CreateWindowExA(WS_EX_CLIENTEDGE, "Button", "修改", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                    pos_x, pos_y, CTRL_WIDTH, CTRL_HEIGHT, (HWND)hWnd, (HMENU)WM_MODNODE, (HINSTANCE)hInst, NULL);
    */

    pos_x = LEFT_SHIFT;
    pos_y += CTRL_HEIGHT + 5;
    hWorkList = (void*)CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", WS_VISIBLE | WS_CHILD | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_VSCROLL,
                    pos_x, pos_y, 150, 120, (HWND)hWnd, (HMENU)WM_WORKLIST, (HINSTANCE)hInst, NULL);

    pos_x = LEFT_SHIFT;
    pos_y += 120 + 5;
    hStartStop = CreateWindowExA(WS_EX_CLIENTEDGE, "Button", "开始", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
                    pos_x, pos_y, CTRL_WIDTH, CTRL_HEIGHT + 5, (HWND)hWnd, (HMENU)WM_START_STOP, (HINSTANCE)hInst, NULL);

    pos_x += CTRL_WIDTH + 5;
    hNextStep = CreateWindowExA(WS_EX_CLIENTEDGE, "Button", "下一步", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
                    pos_x, pos_y, CTRL_WIDTH, CTRL_HEIGHT + 5, (HWND)hWnd, (HMENU)WM_NEXT_STEP, (HINSTANCE)hInst, NULL);

    pos_x += CTRL_WIDTH + 5;
    hAuto = CreateWindowA("Button", "自动", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_AUTOCHECKBOX,
                          pos_x, pos_y, CTRL_WIDTH, CTRL_HEIGHT + 5, (HWND)hWnd, (HMENU)WM_AUTO, (HINSTANCE)hInst, NULL);

    if (mAuto)
    {
        SendMessageA((HWND)hAuto, BM_SETCHECK, 1, 0);
        EnableWindow((HWND)hStartStop, FALSE);
        EnableWindow((HWND)hNextStep, FALSE);
    }

    hMutex = CreateMutexA(NULL, FALSE, "oprwnd");
    hStepSemp = CreateSemaphoreA(NULL, 0, 1, NULL);
    SempUsed = false;
    return true;
}

void OprWnd::Show(int iCmd)
{
    ShowWindow((HWND)hWnd, iCmd);
    UpdateWindow((HWND)hWnd);
}

void OprWnd::WaitSignal()
{
    SempUsed = true;
    WaitForSingleObject(hStepSemp, INFINITE);
    //ReleaseMutex(hMutex);
}

bool OprWnd::GetKeyText(int &key)
{
    char szKey[64] = { 0 };
    GetDlgItemTextA((HWND)hWnd, WM_OPR_KEY, szKey, sizeof(szKey));

    if (!szKey[0])
    {
        return false;
    }

    key = atoi(szKey);
    return true;
}

void OprWnd::FormatOpr(const OprData& opr, char* text, size_t sz)
{
    char Desc[128] = { 0 };
    switch (opr.cmd)
    {
        case WM_ADDNODE:
            sprintf_s(text, sz, "add key %d", opr.key);
            break;
        case WM_DELNODE:
            sprintf_s(text, sz, "del key %d", opr.key);
            break;
        case WM_MODNODE:
            sprintf_s(text, sz, "mod key %d", opr.key);
            break;
        case WM_FINDNODE:
            sprintf_s(text, sz, "find key %d", opr.key);
            break;
    }
}

void OprWnd::OnAddNode()
{
    int key = 0;
    if (GetKeyText(key))
    {
        WaitForSingleObject(hMutex, INFINITE);
        OprData opr;
        opr.cmd = WM_ADDNODE;
        opr.key = key;
        
        char Desc[128] = { 0 };
        FormatOpr(opr, Desc, sizeof(Desc));
        SendMessage((HWND)hWorkList, LB_ADDSTRING, 0, (LPARAM)Desc);

        mOprQueue.push_back(opr);

        ReleaseMutex(hMutex);
    }
}

void OprWnd::OnDelNode()
{
    int key = 0;
    if (GetKeyText(key))
    {
        WaitForSingleObject(hMutex, INFINITE);
        OprData opr;
        opr.cmd = WM_DELNODE;
        opr.key = key;

        char Desc[128] = { 0 };
        FormatOpr(opr, Desc, sizeof(Desc));
        SendMessage((HWND)hWorkList, LB_ADDSTRING, 0, (LPARAM)Desc);

        mOprQueue.push_back(opr);
        ReleaseMutex(hMutex);
    }
}

void OprWnd::OnModNode()
{
    int key = 0;
    if (GetKeyText(key))
    {
        WaitForSingleObject(hMutex, INFINITE);
        OprData opr;
        opr.cmd = WM_MODNODE;
        opr.key = key;

        char Desc[128] = { 0 };
        FormatOpr(opr, Desc, sizeof(Desc));
        SendMessage((HWND)hWorkList, LB_ADDSTRING, 0, (LPARAM)Desc);

        mOprQueue.push_back(opr);
        ReleaseMutex(hMutex);
    }
}

void OprWnd::OnFindNode()
{
    int key = 0;
    if (GetKeyText(key))
    {
        WaitForSingleObject(hMutex, INFINITE);
        OprData opr;
        opr.cmd = WM_FINDNODE;
        opr.key = key;

        char Desc[128] = { 0 };
        FormatOpr(opr, Desc, sizeof(Desc));
        SendMessage((HWND)hWorkList, LB_ADDSTRING, 0, (LPARAM)Desc);

        mOprQueue.push_back(opr);
        ReleaseMutex(hMutex);
    }
}

void OprWnd::OnStartStop()
{
    if (mStart)
    {
        mStart = false;
        SetWindowTextA((HWND)hStartStop, "开始");
        EnableWindow((HWND)hNextStep, true);
        KillTimer((HWND)hWnd, STEP_TIMERID);
    }
    else
    {
        SetWindowTextA((HWND)hStartStop, "停止");
        EnableWindow((HWND)hNextStep, false);
        mStart = true;
        SetTimer((HWND)hWnd, STEP_TIMERID, 1000, TimeProc);
    }
}

void OprWnd::OnNextStep()
{
    if (SempUsed)
    {
        ReleaseSemaphore(hStepSemp, 1, NULL);
    }
}

void OprWnd::OnAuto()
{
    int ret = SendMessageA((HWND)hAuto, BM_GETCHECK, 1, 0);
    if (ret)
    {
        mAuto = true;
        EnableWindow((HWND)hStartStop, false);
        EnableWindow((HWND)hNextStep, false);
    }
    else
    {
        mAuto = false;
        EnableWindow((HWND)hStartStop, true);
        EnableWindow((HWND)hNextStep, true);
    }
}

bool OprWnd::GetNextOpr(OprData& opr)
{
    WaitForSingleObject(hMutex, INFINITE);
    if (mOprQueue.empty())
    {
        ReleaseMutex(hMutex);
        return false;
    }

    opr = mOprQueue.front();
    mOprQueue.remove(opr);

    SendMessage((HWND)hWorkList, LB_RESETCONTENT, 0, 0);
    char Desc[128] = { 0 };
    for (auto it = mOprQueue.begin(); it != mOprQueue.end(); it++)
    {
        //FormatOpr(*it, Desc, sizeof(Desc));
        SendMessage((HWND)hWorkList, LB_ADDSTRING, 0, (LPARAM)Desc);
    }

    ReleaseMutex(hMutex);
    return true;
}

void CALLBACK TimeProc(HWND hwnd, UINT message, UINT idTimer, DWORD dwTime)
{
    if (pOprWnd)
    {
        pOprWnd->OnNextStep();
    }
}



RBTree.cpp 红黑树主要操作

#include "../include/wndMng.h"
#include "../include/common.h"
#include <windows.h>
#include <stack>
#include "../include/filelog.h"
using namespace std;

const char *RBTREE_COLOR[] =
{
    "RED",
    "BLACK",
    "HIGHLIGHT"
};

void WndMng::RBTreePreTraver(RBTree<int, ElemType>* node)
{
    if (!node)
    {
        return;
    }

    printf("key:%d count:%d pos:(%d, %d) paint:(%d, %d)\n", node->kv.first, node->kv.second.count, node->kv.second.pos_x, node->kv.second.pos_y, node->kv.second.paint_x, node->kv.second.paint_y);
    RBTreePreTraver(node->left);
    RBTreePreTraver(node->right);
}

void WndMng::RBTreeInTraver(RBTree<int, ElemType>* node)
{
    if (!node)
    {
        return;
    }

    RBTreeInTraver(node->left);
    printf("key:%d count:%d pos:(%d, %d) paint:(%d, %d)\n", node->kv.first, node->kv.second.count, node->kv.second.pos_x, node->kv.second.pos_y, node->kv.second.paint_x, node->kv.second.paint_y);
    RBTreeInTraver(node->right);
}

void WndMng::RBTreePostTraver(RBTree<int, ElemType>* node)
{
    if (!node)
    {
        return;
    }
    RBTreePostTraver(node->left);
    RBTreePostTraver(node->right);
    printf("key:%d count:%d pos:(%d, %d) paint:(%d, %d)\n", node->kv.first, node->kv.second.count, node->kv.second.pos_x, node->kv.second.pos_y, node->kv.second.paint_x, node->kv.second.paint_y);
}

void WndMng::RBTreeTraver(unsigned char order)
{
    switch (order)
    {
        case PRE_ORDER:
            printf("pre tree traver\n");
            RBTreePreTraver(mRbTree);
            break;
        case IN_ORDER:
            printf("in tree traver\n");
            RBTreeInTraver(mRbTree);
            break;
        case POST_ORDER:
            printf("post tree traver\n");
            RBTreePostTraver(mRbTree);
            break;
    }
}

char* WndMng::RBTreeGetNodeInfo(RBTree<int, ElemType>* cur)
{
    static char info[64] = { 0 };
    if (cur)
    {
        sprintf_s(info, sizeof(info), "key:%d col:%s", cur->kv.first, RBTREE_COLOR[cur->col]);
    }
    else
    {
        strcpy_s(info, "null");
    }

    return info;
}

char* WndMng::RBTreeGetTreeInfo(RBTree<int, ElemType>* cur, RBTree<int, ElemType>* parent, RBTree<int, ElemType>* grandfather, RBTree<int, ElemType>* uncle)
{
    static char info[1024] = { 0 };

    char szCur[64] = { 0 };
    char szParent[64] = { 0 };
    char szGrandFather[64] = { 0 };
    char szUncle[64] = { 0 };

    sprintf_s(szCur, "c=[%s] ", RBTreeGetNodeInfo(cur));
    sprintf_s(szParent, "p=[%s] ", RBTreeGetNodeInfo(parent));
    sprintf_s(szGrandFather, "g=[%s] ", RBTreeGetNodeInfo(grandfather));
    sprintf_s(szUncle, "u=[%s]", RBTreeGetNodeInfo(uncle));

    strcpy_s(info, szCur);
    strcat_s(info, szParent);
    strcat_s(info, szGrandFather);
    strcat_s(info, szUncle);

    return info;
}

void WndMng::RBTreeCalcPaintPos(int deep)
{
    if (!mRbTree)
    {
        return;
    }
    int max_leaves = 1 << (deep - 1);
    int max_width = max_leaves * 2 - 1;
    int **arr = new int*[deep];
    for (int i = 0; i < deep; i++)
    {
        arr[i] = new int[max_leaves];
        memset(arr[i], 0, sizeof(int)*max_leaves);
    }

    int posx = 0;
    for (int i = 0; i < max_leaves; i++)
    {
        arr[deep - 1][i] = posx;
        posx += 2;
    }

    for (int i = deep - 2; i >= 0; i--)
    {
        int leaves = 1 << i;
        for (int j = 0; j < leaves; j++)
        {
            arr[i][j] = (arr[i + 1][j * 2] + arr[i + 1][j * 2 + 1]) / 2;
        }
    }

    int paint_width = (NODE_WIDTH + NODE_WIDTH_OFFSET) * max_leaves;
    int paint_hight = NODE_HIGHT_OFFSET * deep;

    SetWindowPos((HWND)mMainWnd.GetHwnd(), 0, 0, 0, NODE_WIDTH + paint_width, TOP_OFFSET + BUTTOM_OFFSET + paint_hight, SWP_NOMOVE | SWP_NOZORDER);

    // 根结点位置
    mRbTree->kv.second.paint_x = paint_width / 2;
    mRbTree->kv.second.paint_y = 0;

    stack<RBTree<int, ElemType>*> nodestack;
    nodestack.push(mRbTree);

    while (!nodestack.empty())
    {
        RBTree<int, ElemType>* node = nodestack.top();
        nodestack.pop();

        int pos = arr[node->kv.second.pos_y - 1][node->kv.second.pos_x - 1];
        node->kv.second.paint_y = TOP_OFFSET + (node->kv.second.pos_y - 1) * NODE_HIGHT_OFFSET;
        node->kv.second.paint_x = pos * paint_width / max_width;

        if (node->left)
        {
            nodestack.push(node->left);
        }
        if (node->right)
        {
            nodestack.push(node->right);
        }
    }

    delete[] arr;
}

int WndMng::RBTreeCalcPos()
{
    if (!mRbTree)
    {
        return 0;
    }

    int deep = 0;

    mRbTree->kv.second.pos_x = 1;
    mRbTree->kv.second.pos_y = 1;

    stack<RBTree<int, ElemType>*> nodestack;
    stack<RBTree<int, ElemType>*> tmpstack;

    nodestack.push(mRbTree);

    while (!nodestack.empty())
    {
        while (!nodestack.empty())
        {
            RBTree<int, ElemType>* node = nodestack.top();
            RBTree<int, ElemType>* parent = node->parent;
            nodestack.pop();

            if (parent)
            {
                if (parent->left == node)
                {
                    node->kv.second.pos_x = parent->kv.second.pos_x * 2 - 1;
                    node->kv.second.pos_y = parent->kv.second.pos_y + 1;
                }
                else
                {
                    node->kv.second.pos_x = parent->kv.second.pos_x * 2;
                    node->kv.second.pos_y = parent->kv.second.pos_y + 1;
                }
            }

            if (node->left)
            {
                tmpstack.push(node->left);
            }
            if (node->right)
            {
                tmpstack.push(node->right);
            }
        }
        deep++;

        while (!tmpstack.empty())
        {
            RBTree<int, ElemType>* node = tmpstack.top();
            tmpstack.pop();
            nodestack.push(node);
        }
    }
    return deep;
}

void WndMng::RBTreeSimpleInsert(const std::pair<int, ElemType>& kv)
{
    if (!mRbTree)
    {
        mRbTree = new RBTree<int, ElemType>(kv);
        return;
    }

    RBTree<int, ElemType>* newNode = new RBTree<int, ElemType>(kv);
    RBTree<int, ElemType>* node = mRbTree;
    RBTree<int, ElemType>* parent = nullptr;
    while (node)
    {
        parent = node;
        if (kv.first > node->kv.first)
        {
            node = node->right;
        }
        else if (kv.first < node->kv.first)
        {
            node = node->left;
        }
        else
        {
            return;
        }
    }

    if (parent->kv.first > kv.first)
    {
        parent->left = newNode;
        newNode->parent = parent;
    }
    else
    {
        parent->right = newNode;
        newNode->parent = parent;
    }
}

// 左旋树
void WndMng::RBTreeRotateL(RBTree<int, ElemType>* node)
{
    //      p            p
    //      c            r
    //    l   r   -->  c   4
    //   1 2 3 4      l 3
    //               1 2
    // c=node
    // l=childL
    // r=childR
    // p=parent
    if (!node->right)
    {
        return;
    }

    RBTree<int, ElemType>* childR = node->right;
    if (node->parent)
    {
        RBTree<int, ElemType>* parent = node->parent;
        if (parent->left == node)
        {
            parent->left = childR;
            childR->parent = parent;
        }
        else
        {
            parent->right = childR;
            childR->parent = parent;
        }
    }
    else
    {
        mRbTree = childR;
        mRbTree->parent = NULL;
    }

    node->right = childR->left;
    if (childR->left)
    {
        childR->left->parent = node;
    }

    childR->left = node;
    node->parent = childR;
}

// 右旋树
void WndMng::RBTreeRotateR(RBTree<int, ElemType>* node)
{
    //     g            g
    //     c            l
    //   l   r  -->   1    c
    //  1 2 3 4           2  r
    //                      3 4
    // c=node
    // l=childL
    // r=childR
    // p=parent

    if (!node->left)
    {
        return;
    }

    RBTree<int, ElemType>* childL = node->left;
    if (node->parent)
    {
        RBTree<int, ElemType>* parent = node->parent;
        if (parent->left == node)
        {
            parent->left = childL;
            childL->parent = parent;
        }
        else
        {
            parent->right = childL;
            childL->parent = parent;
        }
    }
    else
    {
        mRbTree = childL;
        mRbTree->parent = NULL;
    }

    node->left = childL->right;
    if (childL->right)
    {
        childL->right->parent = node;
    }

    childL->right = node;
    node->parent = childL;
}

void WndMng::RBTreeInsert(const std::pair<int, ElemType>& item)
{
    LOGD("插入key(%d)开始", item.first);
    if (!mRbTree)
    {
        mRbTree = new RBTree<int, ElemType>(item);
        mRbTree->col = BLACK;
        mRbTree->kv.second.count = 1;
        LOGD("插入到根结点key:%d", item.first);
        LOGD("插入key(%d)结束", item.first);
        return;
    }

    // 1.按照二叉搜索树的方式,找到待插入位置
    RBTree<int, ElemType>* cur = mRbTree;
    RBTree<int, ElemType>* parent = NULL;
    while (cur)
    {
        if (item.first > cur->kv.first)
        {
            parent = cur;
            cur = cur->right;
        }
        else if (item.first < cur->kv.first)
        {
            parent = cur;
            cur = cur->left;
        }
        else if (item.first == cur->kv.first)
        {
            cur->kv.second.count++;
            return;
        }
    }

    // 2.将待插入结点插入到树中
    RBTree<int, ElemType>* newNode = new RBTree<int, ElemType>(item);
    newNode->kv.second.count = 1;
    cur = newNode;
    
    if (cur->kv.first > parent->kv.first)
    {
        parent->right = cur;
        cur->parent = parent;

        LOGD("插入到[%s]的右孩子", RBTreeGetNodeInfo(parent));
        ReportAndWait();
    }
    else
    {
        parent->left = cur;
        cur->parent = parent;

        LOGD("插入到[%s]的左孩子", RBTreeGetNodeInfo(parent));
        ReportAndWait();
    }

    // 3.调整结点
    //     只有当插入结点的父结点是红色时,才需要对红黑树进行调整
    while (parent && RED == parent->col)
    {
        RBTree<int, ElemType>* grandfather = parent->parent;
        if (grandfather->left == parent)   // 父结点是祖父结点左孩子
        {
            // 叔叔结点为右结点
            RBTree<int, ElemType>* uncle = grandfather->right;

            // 情况1:叔叔存在且为红色
            if (uncle && RED == uncle->col)
            {
                parent->col = BLACK;
                grandfather->col = RED;
                uncle->col = BLACK;

                LOGD("插入key(%d).情况1:变换颜色. 调整后: %s",
                     item.first, RBTreeGetTreeInfo(cur, parent, grandfather, uncle));

                // 继续向上调整
                cur = grandfather;
                parent = grandfather->parent;
             
                ReportAndWait();
            }
            // 情况2:叔叔存在且为黑色
            // 情况3:叔叔不存在
            else
            {
                // 祖孙三代为一条直线->右单旋->调整颜色
                if (parent->left == cur)
                {
                    RBTreeRotateR(grandfather);
                    ReportAndWait();
                    grandfather->col = RED;
                    parent->col = BLACK;

                    LOGD("插入key(%d).情况2+3:直线->右单旋->调整颜色. 调整后: %s",
                         item.first, RBTreeGetTreeInfo(cur, parent, grandfather, uncle));
                }
                else
                {
                    // 祖孙三代折线->左右双旋->调整颜色
                    RBTreeRotateL(parent);
                    ReportAndWait();
                    RBTreeRotateR(grandfather);
                    ReportAndWait();

                    grandfather->col = RED;
                    cur->col = BLACK;
                    
                    LOGD("插入key(%d).情况2+3:折线->左右双旋->调整颜色. 调整后: %s",
                         item.first, RBTreeGetTreeInfo(cur, parent, grandfather, uncle));
                }

                // 做了旋转操作后不需要再继续调整
                ReportAndWait();
                break;
            }
        }
        else
        {
            // 叔叔结点为左结点
            RBTree<int, ElemType>* uncle = grandfather->left;

            // 情况1:叔叔结点存在且为红色
            if (uncle && RED == uncle->col)
            {
                grandfather->col = RED;
                uncle->col = BLACK;
                parent->col = BLACK;

                LOGD("插入key(%d).情况1:变换颜色. 调整后: %s",
                     item.first, RBTreeGetTreeInfo(cur, parent, grandfather, uncle));

                // 继续向上调整
                cur = grandfather;
                parent = grandfather->parent;

                ReportAndWait();
            }
            // 情况2:叔叔存在且为黑色
            // 情况3:叔叔不存在
            else
            {
                // 祖孙三代为直线关系:左单旋->颜色调整
                if (parent->right == cur)
                {
                    RBTreeRotateL(grandfather);
                    ReportAndWait();

                    grandfather->col = RED;
                    parent->col = BLACK;

                    LOGD("插入key(%d).情况2+3:直线->左单旋->调整颜色. 调整后: %s",
                         item.first, RBTreeGetTreeInfo(cur, parent, grandfather, uncle));
                }
                // 祖孙三代为折线关系:右左双旋->颜色调整
                else
                {
                    RBTreeRotateR(parent);
                    ReportAndWait();
                    RBTreeRotateL(grandfather);
                    ReportAndWait();

                    grandfather->col = RED;
                    cur->col = BLACK;

                    LOGD("插入key(%d).情况2+3:折线->右左双旋->调整颜色. 调整后: %s",
                         item.first, RBTreeGetTreeInfo(cur, parent, grandfather, uncle));
                }

                // 做了旋转操作后不需要再继续调整
                ReportAndWait();
                break;
            }
        }
    }
    mRbTree->col = BLACK;  // 根结点的颜色为黑色

    LOGD("插入key(%d)结束", item.first);
}

bool WndMng::RBTreeDelete(const std::pair<int, ElemType>& key)
{
    LOGD("删除key(%d)", key.first);
    RBTree<int, ElemType>* delNode = NULL;           // 待删除结点
    RBTree<int, ElemType>* delParentNode = NULL;     // 待删除结点的父结点

    RBTree<int, ElemType>* cur = mRbTree;
    RBTree<int, ElemType>* parent = NULL;

    // 第一步:找到待删除结点
    while (cur)
    {
        if (key.first > cur->kv.first)
        {
            cur = cur->right;
            parent = cur->parent;
        }
        else if (key.first < cur->kv.first)
        {
            cur = cur->left;
            parent = cur->parent;
        }
        else // 找到待删除结点
        {
            LOGD("删除key(%d).找到待删除结点[%s]", key.first, RBTreeGetNodeInfo(cur));
            cur->kv.second.highlight = true;
            ReportAndWait();

            // 待删除结点的左子树为空
            if (cur->left == NULL)
            {
                if (cur == mRbTree) // 待删除结点是根结点
                {
                    mRbTree = mRbTree->right; // 让根结点的右子树作为新的根结点
                    if (mRbTree)
                    {
                        mRbTree->parent = NULL;
                        mRbTree->col = BLACK;
                    }
                    LOGD("删除key(%d).结束", key.first);
                    delete cur;    // 删除原根节点
                    return true;
                }
                else
                {
                    // 记录待删除结点
                    delParentNode = parent;
                    delNode = cur;
                }
                break;
            }
            // 待删除结点的右子树为空
            else if (cur->right == NULL)
            {
                if (cur == mRbTree)       // 待删除结点是根结点
                {
                    mRbTree = mRbTree->left; // 让根结点的左子树作为新的根结点
                    if (mRbTree)
                    {
                        mRbTree->parent = NULL;
                        mRbTree->col = BLACK;   // 根结点为黑色
                    }

                    LOGD("删除key(%d).结束", key.first);
                    delete cur;
                    return true;
                }
                else
                {
                    // 记录待删除结点
                    delParentNode = parent;
                    delNode = cur;
                }
                break;
            }
            // 待删除结点左右孩子都不为空
            else
            {
                // 替换法删除
                // 寻找待删除结点右子树当中key值最小的结点作为实际删除结点

                RBTree<int, ElemType>* minParent = cur;
                RBTree<int, ElemType>* minRight = cur->right;
                while (minRight->left)
                {
                    minParent = minRight;
                    minRight = minRight->left;
                }

                // 将待删除结点的key-val改为minRight的key-val
                cur->kv.first = minRight->kv.first;
                cur->kv.second = minRight->kv.second;

                // 记录待删除结点
                delParentNode = minParent;
                delNode = minRight;

                delNode->kv.second.highlight = true;
                cur->kv.second.highlight = true;

                ReportAndWait();
                LOGD("删除key(%d).使用替换法删除", key.first);
                break;
            }
        }
    }

    // 找不到待删除结点
    if (!delNode)
    {
        return false;
    }
    // 记录待删除的结点及其父结点
    RBTree<int, ElemType>* del = delNode;
    RBTree<int, ElemType>* delP = delParentNode;

    LOGD("删除key(%d).调整红黑树", key.first);
    // 第二步:调整红黑树
    if (BLACK == delNode->col) // 待删除结点是黑色结点
    {
        if (delNode->left)         // 待删除结点有一个红色的左孩子(不可能黑色)
        {
            delNode->left->col = BLACK;  // 将这个红色的孩子变成黑色即可

            LOGD("删除key(%d).调整红黑树:左孩子变为黑色", key.first);
            ReportAndWait();
        }
        else if (delNode->right)   // 带删除结点有一个红色的右孩子(不可能黑色)
        {
            delNode->right->col = BLACK; // 将这个红色的右孩子变成黑色即可

            LOGD("删除key(%d).调整红黑树:右孩子变为黑色", key.first);
            ReportAndWait();
        }
        else // 带删除结点左右结点均为空
        {
            while (delNode != mRbTree) // 可能一直调整到根结点
            {
                if (delNode == delParentNode->left) // 待删除结点是其父节点的左孩子
                {
                    // 兄弟结点是其父节点的右孩子
                    RBTree<int, ElemType>* brother = delParentNode->right;
                    // 情况一:brother为红色
                    if (RED == brother->col)
                    {
                        delParentNode->col = RED;
                        brother->col = BLACK;
                        RBTreeRotateL(delParentNode);

                        LOGD("删除key(%d).调整红黑树,情况一:左旋转 brother=[%s]", key.first, RBTreeGetNodeInfo(brother));
                        ReportAndWait();

                        // 需要继续处理
                        brother = delParentNode->right;
                    }

                    // 情况二:brother为黑色,且其左右孩子都是黑色结点或为空
                    if ((NULL == brother->left || BLACK == brother->left->col) &&
                        (NULL == brother->right || BLACK == brother->right->col))
                    {

                        brother->col = RED;

                        LOGD("删除key(%d).调整红黑树,情况二:调整颜色. 调整后: brother=[%s]", key.first, RBTreeGetNodeInfo(brother));
                        ReportAndWait();

                        if (RED == delParentNode->col)
                        {
                            delParentNode->col = BLACK;
                            break;
                        }
                        // 需要继续处理
                        delNode = delParentNode;
                        delParentNode = delNode->parent;
                    }
                    else
                    {
                        // 情况三:brother为黑色,且其左孩子是红色结点,右孩子是黑色结点或为空
                        if (NULL == brother->right || BLACK == brother->right->col)
                        {

                            brother->left->col = BLACK;
                            brother->col = RED;
                            RBTreeRotateR(brother);

                            LOGD("删除key(%d).调整红黑树,情况三:调整颜色->右旋转. 调整后: brother=[%s]", key.first, RBTreeGetNodeInfo(brother));
                            ReportAndWait();

                            // 需要继续处理
                            brother = delParentNode->right;
                        }
                        // 情况四:brother为黑色,且其右孩子是红色结点
                        brother->col = delParentNode->col;
                        delParentNode->col = BLACK;
                        brother->right->col = BLACK;
                        RBTreeRotateL(delParentNode);

                        LOGD("删除key(%d).调整红黑树,情况四:调整颜色->左旋转. 调整后: brother=[%s]", key.first, RBTreeGetNodeInfo(brother));
                        ReportAndWait();
                        break;
                    }
                }
                else // 待删除结点是其父节点的左孩子
                {
                    RBTree<int, ElemType>* brother = delParentNode->left;  // 兄弟结点是其父节点的左孩子
                    // 情况一:brother为红色
                    if (RED == brother->col)
                    {
                        delParentNode->col = RED;
                        brother->col = BLACK;
                        RBTreeRotateR(delParentNode);

                        LOGD("删除key(%d).调整红黑树,情况一:右旋转 brother=[%s]", key.first, RBTreeGetNodeInfo(brother));
                        ReportAndWait();

                        // 需要继续处理
                        brother = delParentNode->left;
                    }

                    // 情况二:brother为黑色,且其左右孩子都是黑色结点或为空
                    if ((NULL == brother->left || BLACK == brother->left->col) &&
                        (NULL == brother->right || BLACK == brother->right->col))
                    {
                        brother->col = RED;

                        LOGD("删除key(%d).调整红黑树,情况二:调整颜色. 调整后: brother=[%s]", key.first, RBTreeGetNodeInfo(brother));
                        ReportAndWait();

                        if (RED == delParentNode->col)
                        {
                            delParentNode->col = BLACK;
                            break;
                        }
                        // 需要继续处理
                        delNode = delParentNode;
                        delParentNode = delNode->parent;
                    }
                    else
                    {
                        // 情况三:brother为黑色,且其右孩子是红色结点,左孩子是黑色结点或空
                        if (NULL == brother->left || BLACK == brother->left->col)
                        {
                            brother->right->col = BLACK;
                            brother->col = RED;
                            RBTreeRotateL(brother);

                            LOGD("删除key(%d).调整红黑树,情况三:调整颜色->右旋转. 调整后: brother=[%s]", key.first, RBTreeGetNodeInfo(brother));
                            ReportAndWait();

                            // 需要继续处理
                            brother = delParentNode->left;
                        }

                        // 情况四:brother为黑色,且其左孩子是红色结点
                        brother->col = delParentNode->col;
                        delParentNode->col = BLACK;
                        brother->left->col = BLACK;
                        RBTreeRotateR(delParentNode);

                        LOGD("删除key(%d).调整红黑树,情况四:调整颜色->左旋转. 调整后: brother=[%s]", key.first, RBTreeGetNodeInfo(brother));
                        ReportAndWait();
                        break;
                    }
                }
            }
        }
    }

    LOGD("删除key(%d).进行实际删除.", key.first);

    // 第三步:进行实际删除
    if (NULL == del->left)          // 实际删除结点的左子树为空
    {
        if (del == delP->left)        // 实际删除结点是其父节点的左孩子
        {
            delP->left = del->right;
            if (del->right)
            {
                del->right->parent = delP;
            }
        }
        else                        // 实际删除结点是其父节点的有孩子
        {
            delP->right = del->right;
            if (del->right)
            {
                del->right->parent = delP;
            }
        }
    }
    else // 实际删除结点的右子树为空
    {
        if (del == delP->left)  // 实际删除结点是其父节点的左孩子
        {
            delP->left = del->left;
            if (del->left)
            {
                del->left->parent = delP;
            }
        }
        else // 实际删除结点是其父节点的右孩子
        {
            delP->right = del->left;
            if (del->left)
            {
                del->left->parent = delP;
            }
        }
    }
    delete del;
    return true;
}

RBTree<int, ElemType>* WndMng::RBTreeFind(const std::pair<int, ElemType>& key)
{
    if (!mRbTree)
    {
        return NULL;
    }

    RBTree<int, ElemType>* cur = mRbTree;
    while (cur)
    {
        if (cur->kv.first == key.first)
        {
            return cur;
        }
        if (key.first > cur->kv.first)
        {
            cur = cur->right;
        }
        else
        {
            cur = cur->left;
        }
    }

    return NULL;
}

RBTree<int, ElemType>* WndMng::RBTreeModify(const std::pair<int, ElemType>& key)
{
    if (!mRbTree)
    {
        return NULL;
    }

    RBTree<int, ElemType>* cur = mRbTree;
    while (cur)
    {
        if (cur->kv.first == key.first)
        {
            cur->kv.second = key.second;
            return cur;
        }
        if (key.first > cur->kv.first)
        {
            cur = cur->right;
        }
        else
        {
            cur = cur->left;
        }
    }

    return NULL;
}

void WndMng::DoWork()
{
    RBTree<int, ElemType>* tmpNode = NULL;
    while (true)
    {
        if (!mOprWnd)
        {
            continue;
        }

        OprData opr;
        if (!mOprWnd->GetNextOpr(opr))
        {
            continue;
        }

        ElemType elem;
        memset(&elem, 0, sizeof(elem));
        switch (opr.cmd)
        {
            case WM_ADDNODE:
                RBTreeInsert(make_pair(opr.key, elem));
                break;
            case WM_DELNODE:
                RBTreeDelete(make_pair(opr.key, elem));
                break;
            case WM_MODNODE:
                tmpNode = RBTreeModify(make_pair(opr.key, elem));
                if (tmpNode)
                {
                    tmpNode->kv.second.highlight = true;
                }
                break;
            case WM_FINDNODE:
                tmpNode = RBTreeFind(make_pair(opr.key, elem));
                if (tmpNode)
                {
                    tmpNode->kv.second.highlight = true;
                }
                break;
            default:
                break;
        }

        int deep = RBTreeCalcPos();
        RBTreeCalcPaintPos(deep);

        /**
        AllocConsole();
        FILE* fp;
        freopen_s(&fp, "CONOUT$", "w+t", stdout);
        RBTreeTraver(PRE_ORDER);
        RBTreeTraver(IN_ORDER);
        RBTreeTraver(POST_ORDER);
        FreeConsole();
        */

        InvalidateRect((HWND)mMainWnd.GetHwnd(), NULL, TRUE);
    }
}

wndMng.cpp

#include "../include/wndMng.h"
#include "../include/common.h"
#include "../include/filelog.h"
#include <windows.h>
#include <time.h>
#include <stack>
#include <vector>
using namespace std;

WndMng* gWndMng = NULL;

WndMng::WndMng()
{
    gWndMng = this;
    redBrush = NULL;
    blackBrush = NULL;
    highlightBrush = NULL;
    mRbTree = NULL;
    mOprWnd = NULL;
}

WndMng::~WndMng()
{
    if (redBrush)
    {
        DeleteObject(redBrush);
    }
    if (blackBrush)
    {
        DeleteObject(blackBrush);
    }
    if (highlightBrush)
    {
        DeleteObject(highlightBrush);
    }
}

DWORD WINAPI WorkThread(LPVOID lpParam);
LRESULT CALLBACK MainWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK OprWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

void WndMng::Create(void* hInst)
{
    mMainWnd.Create(hInst, "红黑树", 100,200,MainWinProc);
    mMainWnd.Show(SW_SHOW);

    srand((unsigned int)time(0));

    int key = 0;
    ElemType elem = { 0 };
    for (int i = 0; i < 6; i++)
    {
        key = rand() % 999;
        //RBTreeSimpleInsert(std::make_pair(key, elem));
        RBTreeInsert(std::make_pair(key, elem));
    }
    printf("\n");

    int deep = RBTreeCalcPos();
    RBTreeCalcPaintPos(deep);

    /**
    AllocConsole();
    FILE* fp;
    freopen_s(&fp, "CONOUT$", "w+t", stdout);
    RBTreeTraver(PRE_ORDER);
    RBTreeTraver(IN_ORDER);
    RBTreeTraver(POST_ORDER);
    FreeConsole();
    */

    mOprWnd = new OprWnd;
    mOprWnd->Create(NULL, "红黑树操作", 400, 300, OprWinProc);
}

DWORD WINAPI WorkThread(LPVOID lpParam)
{
    WndMng* pWnd = (WndMng*)lpParam;
    if (pWnd)
    {
        pWnd->DoWork();
    }
    return 0;
}

void WndMng::StartWork()
{
    DWORD dwTid = 0;
    if (!CreateThread(NULL, 0, WorkThread, this, 0, &dwTid))
    {
        LOGE("create thread failed! errno=%d", GetLastError());
    }
    else
    {
        LOGD("start work..\n");
    }
}

void WndMng::Init()
{
    if (!redBrush)
    {
        redBrush = CreateSolidBrush(RGB(255, 0, 0));
    }

    if (!blackBrush)
    {
        blackBrush = CreateSolidBrush(RGB(0, 0, 0));
    }
    if (!highlightBrush)
    {
        highlightBrush = CreateSolidBrush(RGB(255, 255, 0));
    }
}

void WndMng::ReportAndWait()
{
    if (!mOprWnd || mOprWnd->IsAuto())
    {
        return;
    }
    //Sleep(1000);
    int deep = RBTreeCalcPos();
    RBTreeCalcPaintPos(deep);
    InvalidateRect((HWND)mMainWnd.GetHwnd(), NULL, TRUE);

    mOprWnd->WaitSignal();
}

void WndMng::PaintTree(void* hdc)
{
    if (!mRbTree)
    {
        return;
    }

    stack<RBTree<int, ElemType>*> nodestack;
    nodestack.push(mRbTree);

    char text[32] = { 0 };

    vector<RBTree<int, ElemType>*> highlightnode;

    while (!nodestack.empty())
    {
        RBTree<int, ElemType>* node = nodestack.top();
        RBTree<int, ElemType>* parent = node->parent;
        nodestack.pop();

        if (parent)
        {
            //SetPixel((HDC)hdc, parent->kv.second.paint_x, parent->kv.second.paint_y, RGB(255, 0, 0));
            MoveToEx((HDC)hdc, node->kv.second.paint_x + NODE_WIDTH / 2, node->kv.second.paint_y + NODE_HIGHT / 2, NULL);
            LineTo((HDC)hdc, parent->kv.second.paint_x + NODE_WIDTH / 2, parent->kv.second.paint_y + NODE_HIGHT / 2);
            sprintf_s(text, sizeof(text), "%d", parent->kv.first);
            PaintNode(hdc, parent->kv.second.paint_x, parent->kv.second.paint_y, text, parent->col, parent->kv.second.highlight);
        }
        
        sprintf_s(text, sizeof(text), "%d", node->kv.first);
        PaintNode(hdc, node->kv.second.paint_x, node->kv.second.paint_y, text, node->col, node->kv.second.highlight);

        if (node->left)
        {
            nodestack.push(node->left);
        }
        if (node->right)
        {
            nodestack.push(node->right);
        }

        if (node->kv.second.highlight)
        {
            highlightnode.push_back(node);
        }
    }

    for (size_t i = 0; i < highlightnode.size(); i++)
    {
        highlightnode[i]->kv.second.highlight = false;
    }
}

void WndMng::PaintNode(void* hdc, int x, int y, const char* text, unsigned char col, bool highlight)
{
    RECT txRt =
    {
        /*.left = */x,
        /*.top = */y + TEXT_TOP_OFFSET,
        /*.right = */x + NODE_WIDTH,
        /*.bottom = */y + NODE_WIDTH
    };
    SetBkMode((HDC)hdc, TRANSPARENT);

    HBRUSH hOldBrush = NULL;
    switch (col)
    {
        case RED:
            hOldBrush = (HBRUSH)SelectObject((HDC)hdc, redBrush);
            Ellipse((HDC)hdc, x, y, x + NODE_WIDTH, y + NODE_WIDTH);
            SelectObject((HDC)hdc, hOldBrush);

            if (highlight)
            {
                SetTextColor((HDC)hdc, RGB(255, 255, 0));
                DrawTextA((HDC)hdc, text, -1, &txRt, DT_SINGLELINE | DT_CENTER);
            }
            else
            {
                SetTextColor((HDC)hdc, RGB(0, 0, 0));
                DrawTextA((HDC)hdc, text, -1, &txRt, DT_SINGLELINE | DT_CENTER);
            }

            break;
        case BLACK:
            hOldBrush = (HBRUSH)SelectObject((HDC)hdc, blackBrush);
            Ellipse((HDC)hdc, x, y, x + NODE_WIDTH, y + NODE_WIDTH);
            SelectObject((HDC)hdc, hOldBrush);

            if (highlight)
            {
                SetTextColor((HDC)hdc, RGB(255, 255, 0));
                DrawTextA((HDC)hdc, text, -1, &txRt, DT_SINGLELINE | DT_CENTER);
            }
            else
            {
                SetTextColor((HDC)hdc, RGB(255, 255, 255));
                DrawTextA((HDC)hdc, text, -1, &txRt, DT_SINGLELINE | DT_CENTER);
            }
            break;
    }
}

LRESULT CALLBACK MainWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TEXTMETRIC tm;

    switch (message)
    {
        case WM_CREATE:
            hdc = GetDC(hWnd);
            GetTextMetrics(hdc, &tm);
            gWndMng->Init();
            return 0;
        case WM_RBUTTONUP:
            gWndMng->OnRButtonUp(hWnd, lParam);
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            gWndMng->PaintTree(hdc);
            EndPaint(hWnd, &ps);
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}


void WndMng::OnRButtonUp(void* hwnd, unsigned long lParam)
{
        // 创建弹出式菜单
    HMENU hPopup = CreatePopupMenu();

    // 添加菜单项
    AppendMenu(hPopup, MF_STRING, 1002, "新增结点");   // 可以发送WM_COMMAND消息
    AppendMenu(hPopup, MF_SEPARATOR, 1003, NULL);
    AppendMenu(hPopup, MF_STRING, 1004, "删除结点");
    AppendMenu(hPopup, MF_SEPARATOR, 1005, NULL);
    AppendMenu(hPopup, MF_STRING, 1006, "查找结点");
    AppendMenu(hPopup, MF_SEPARATOR, 1007, NULL);
    AppendMenu(hPopup, MF_STRING, 1008, "修改结点");
    AppendMenu(hPopup, MF_SEPARATOR, 1009, NULL);
    AppendMenu(hPopup, MF_STRING, 1010, "清除结点");

    POINT pt = { LOWORD(lParam), HIWORD(lParam) };

    // 将客户区坐标系坐标转化为屏幕坐标系坐标
    ClientToScreen((HWND)hwnd, &pt);

    // 显示菜单

    BOOL nRet = TrackPopupMenu(hPopup, TPM_CENTERALIGN | TPM_VCENTERALIGN | TPM_RETURNCMD, // TPM_RETURNCMD 可以不发出消息,只返回被点击菜单项的ID 
                               pt.x, pt.y, // 屏幕坐标系下的位置,不该是窗口坐标系下的位置,除非重合
                               0, (HWND)hwnd, NULL);
    switch (nRet)
    {
        case 1002:
        case 1004:
        case 1006:
        case 1008:
            mOprWnd->Show(SW_SHOW);
        break;
        case 1010://TODO:
            break;
    }
}

void WndMng::HideOprWnd()
{
    if (mOprWnd)
    {
        mOprWnd->Show(SW_HIDE);
    }
}

void WndMng::OnOprWndCommand(void* hwnd, unsigned long wParam, unsigned long lParam)
{
    if (!mOprWnd)
    {
        return;
    }

    DWORD dwID = LOWORD(wParam);
    DWORD dwEvent = HIWORD(lParam);

    switch (dwID)
    {
        case WM_ADDNODE:
            mOprWnd->OnAddNode();
            break;
        case WM_DELNODE:
            mOprWnd->OnDelNode();
            break;
        case WM_MODNODE:
            mOprWnd->OnModNode();
            break;
        case WM_FINDNODE:
            mOprWnd->OnFindNode();
            break;
        case WM_START_STOP:
            mOprWnd->OnStartStop();
            break;
        case WM_NEXT_STEP:
            mOprWnd->OnNextStep();
            break;
        case WM_AUTO:
            mOprWnd->OnAuto();
            break;
    }
}

LRESULT CALLBACK OprWinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_COMMAND:
            gWndMng->OnOprWndCommand(hWnd, wParam, lParam);
            break;
        case WM_CLOSE:
            gWndMng->HideOprWnd();
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}


main.cpp

#include <windows.h>
#include "include/wndMng.h"


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, PSTR szCmdLine, int iCmdShow)
{
    WndMng wndmng;
    wndmng.Create(hInstance);
    wndmng.StartWork();
    MSG msg = { 0 };
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return static_cast<int>(msg.wParam);
}






在这里插入图片描述
勾选自动后会一次性操作完。
非自动需要选择开始(1s一次)或者下一步手动执行

参考文章:https://blog.csdn.net/chenlong_cxy/article/details/121481859

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值