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