括号匹配

//裁剪字符串,掐头去尾只保留被括号包围的部分 void trim(const char exp[], int& lo, int& hi) { while ((lo <= hi) && (exp[lo] != '(') && (exp[lo] != ')')) lo++; while ((lo <= hi) && (exp[hi] != '(') && (exp[hi] != ')')) hi--; } //分割字符串,分割成左右,即"("与")"括号相同的多个部分 int divide(const char exp[], int lo, int hi) { int mi = lo; int crc = 1; while ((0 < crc) && (++mi < hi)) { if (exp[mi] == ')') crc--; if (exp[mi] == '(') crc++; } return mi; } //综合上述两部分,递归求解 bool paren(const char exp[], int lo, int hi) { trim(exp, lo, hi); if (lo > hi) return true; if (exp[lo] != '(') return false; if (exp[hi] != ')') return false; int mi = divide(exp, lo, hi); if (mi > hi) return false; return paren(exp, lo + 1, mi - 1) && paren(exp, mi + 1, hi); }
对字符串形式的数学表达式求值
下面这段程序用到了指针的引用,与指针的主要区别在于调用函数中形参列表对其声明的方式不同,指针的声明形如:int* a 指针的引用声明形如:int*& a 其详细解读可网上搜索。

#define N_OPTR 9 typedef enum { ADD, SUB, MUL, DIV, POW, FAC, L_P, R_P, EOE } Operator; const char pri[N_OPTR][N_OPTR] = { '>','>','<','<','<','<','<','>','>', '>','>','<','<','<','<','<','>','>', '>','>','>','>','<','<','<','>','>', '>','>','>','>','<','<','<','>','>', '>','>','>','>','>','<','<','>','>', '>','>','>','>','>','>',' ','>','>', '<','<','<','<','<','<','<','=',' ', ' ',' ',' ',' ',' ',' ',' ',' ',' ', '<','<','<','<','<','<','<',' ','=' }; void readNumber(char*& p, stack<float>& stk) { float stkr; stk.push((float)(*p - '0')); while (isdigit(*(++p))) { stkr=stk.top() * 10 + (*p - '0'); stk.pop(); stk.push(stkr); } if ('.' != *p) return; float fraction = 1; while (isdigit(*(++p))) { stkr = stk.top() + (fraction /= 10) * (*p - '0'); stk.pop(); stk.push(stkr); } } Operator optr2rank(char op) { switch (op) { case '+': return ADD; case '-': return SUB; case '*': return MUL; case '/': return DIV; case '^': return POW; case '!': return FAC; case '(': return L_P; case ')': return R_P; case '': return EOE; default: exit(-1); } } char orderBetween(char op1, char op2) { return pri[optr2rank(op1)][optr2rank(op2)]; } void append(char*& rpn, float opnd) { int n = strlen(rpn); char buf[64]; if (opnd != (float)(int)opnd) sprintf(buf, "%.3f ", opnd); else sprintf(buf, "%d ", (int)opnd); rpn = (char*)realloc(rpn, sizeof(char)*(n + strlen(buf) + 1)); strcat(rpn, buf); } void append(char*& rpn, char optr) { int n = strlen(rpn); rpn = (char*)realloc(rpn, sizeof(char) * (n + 3)); //sprintf_s(rpn, "%c", optr); //char buf[64]; sprintf(rpn+n, "%c ", optr); //const char o = optr; //strcat_s(rpn, sizeof(buf), buf); rpn[n + 2] = ''; } float calcu(char op, float pOpnd) {//单目运算 float sum = 1; if (pOpnd == 0) return 1; else { while (pOpnd) { sum *= (pOpnd--); } } return sum; } float calcu(float pOpnd1, char op, float pOpnd2) {//单目运算 switch (op) { case '+': return pOpnd1 + pOpnd2; case '-': return pOpnd1 - pOpnd2; case '*': return pOpnd1 * pOpnd2; case '/': return pOpnd1 / pOpnd2; case '^': return pow(pOpnd1, pOpnd2); default: break; } } float evaluate(char* S, char*& RPN) { stack<float> opnd; stack<char> optr; optr.push(''); while (!optr.empty()) { if (isdigit(*S)) { readNumber(S, opnd); append(RPN, opnd.top()); }else switch (orderBetween(optr.top(),*S)) { case '<': optr.push(*S); S++; break; case '=': optr.pop(); S++; break; case '>': { char op = optr.top(); optr.pop(); append(RPN, op); if ('!' == op) { float pOpnd = opnd.top(); opnd.pop(); opnd.push(calcu(op, pOpnd)); } else { float pOpnd2 = opnd.top(); opnd.pop(); float pOpnd1 = opnd.top(); opnd.pop(); opnd.push(calcu(pOpnd1, op, pOpnd2)); } break; } default: exit(-1); } } return opnd.top(); }
二叉搜索树

#pragma once #ifndef BINSEARCHTREE_H_ #define BINSEARCHTREE_H_ #include <stdlib.h> #include <stdint.h> #include <iostream> #include <exception> namespace alg { template<typename keyT,typename valueT> class BST { private: struct treeNode//树节点 { keyT key; valueT value; treeNode *parent; treeNode *left; treeNode *right; }; class BSTException :public std::exception {//用于异常处理的类 public: virtual const char* what()const throw() { return "key does not exist"; } }excp_key; private://原始树根 treeNode *m_root; private: BST(const BST&); BST& operator=(const BST&); public: BST() :m_root(nullptr) {};//构造函数,构造空树 ~BST() { destruct_(m_root); } treeNode* find(const keyT &key) {//二叉搜索原理,树本身有序,按此原则往左右遍历比较 treeNode *n = m_root; while (n != nullptr&&key != n->key) { if (key < n->key) n = n->left; else n = n->right; } return n; } void insert(const keyT &key, const valueT &value) {//插入新的节点 treeNode *z = new treeNode;//为新节点申请内存 z->key = key; z->value = value; z->left = z->right = z->parent = nullptr;//先不关联任何节点 treeNode *n = m_root; treeNode *y = nullptr; while (n!=nullptr)//不断深入左右子树,寻找合适的插入位置 { y = n; if (key < n->key) n = n->left; else n = n->right; } z->parent = y; if (y == nullptr)//二叉搜索树本身为空树,则插入节点直接作为根节点 m_root = z; else if (key < y->key) y->left = z; else y->right = z; } bool deleteKey(const keyT &key) { treeNode *z = find(key); if (z == nullptr) return false; if (z->left == nullptr) tansplant(z, z->right); else if (z->right == nullptr) transplant(z, z->left); else { treeNode *y = minimum(z->right);//找出右子树中最小的节点 if (y->parent != z) {//若最小节点不是孩子节点则进行替换 transplant(y, y->right); y->right = z->right; y->right->parent = y; } //对删除节点进行替换,替换为删除节点右子树中最小叶节点 transplant(z, y); y->left = z->left; y->left->parent = y; } delete z; return true; } void print_tree(treeNode *n, int indent) {//采用递归方式打印二叉搜索树,indent用于区分不同层次。 if (n == nullptr) return; print_tree(n->right, indent + 1); for (int i = 0; i < indent; ++i) { std::cout << " "; } std::cout << "[" << n->key << "," << n->value << "]" << std::endl; print_tree(n->left, indent + 1); } void print_helpler() { print_tree(m_root, 0); } private: void destruct_(treeNode *n) {//销毁节点n,逐级深入并销毁 if (n == nullptr) return; destruct_(n->left); destruct_(n->right); delete n; } void transplant(treeNode *u, treeNode *v) {//将节点u替换为v if (u->parent == nullptr) m_root = v; else if (u == u->parent->left) u->parent->left = v; else u->parent->right = v; if (v != nullptr) v->parent = u->parent; } treeNode *minimum(treeNode *x) {//找出节点x所在子树中的最小key值节点,即最左叶节点 while (x->left != nullptr) { x = x->left; } return x; } }; } #endif // !BINSEARCHTREE_H_
LUR缓存淘汰策略类

/*LRU(Least Recent Use):内存管理机制,页面置换算法,将最近使用最少的item丢弃*/ #pragma once #ifndef LRU_CACHE_H_ #define LRU_CACHE_H_ #include <iostream> #include <string> #include <stdint.h> #include <stdio.h> #include <string.h> #include <map> using namespace std; namespace alg { template <typename K,typename V> class LRUCache{ struct _Node_//LRU每个存储节点的形式 { K key; V value; _Node_ *next; _Node_ *pre; } CacheNode; public: LRUCache(int cache_size = 10) { cache_size_ = cache_size; p_cache_list_head = new CacheNode; p_cache_list_near = new CacheNode; p_cache_list_head->next = p_cache_list_near; p_cache_list_head->pre = nullptr; p_cache_list_near->pre = p_cache_list_head; p_cache_list_near->next = nullptr; } ~LRUCache() { CacheNode *p; p = p_cache_list_head0->next; while (p != nullptr) { delete p->pre; p = p->next; } delete p_cache_list_near; cache_hash.clear(); } V getValue(K key) {//获取key键指向的值 if (cache_hash.find(key) != cache_hash.end()) {//存在则获取并返回 CacheNode *p = cache_hash[key]; detachNode(p); addFirstNode(p); return cache_hash[key]->value; } else {//不存在则给出提示 cout << "[ERROR]No key with name ::" << key << endl; return V(); } } bool putValue(K key, V value) {//存入新的key-value对。 if (cache_hash.find(key) != cache_hash.end()) {//若已经存在相同key则更新value即可 cache_hash[key]->value = value; detachNode((CacheNode*)cache_hash[key]); addFirstNode((CacheNode*)cache_hash[key]); if (cache_hash.size() > cache_size_) {//越界的节点删除掉 cout << "[INFO]LRU Cache is full ... Delete Last One..." << endl; delEndNode(); } } else {//不存在相同key值节点则创建新的节点并作为首节点插入 CacheNode *p = new CacheNode; p->key = key; p->value = value; addFirstNode(p); cache_hash[key] = p;//并插入hash缓存中 if (cache_hash.size() > cache_size_) { cout << "[INFO]LRU Cache is full ... Delete Last One..." << endl; delEndNode(); } } return true; } void display() {//遍历所有节点并显示 CacheNode p = p_cache_list_head->next; while (p!=nullptr) { cout << " KEY[" << p->key << "]<==>VALUE[" << p->value << "]" << endl; p = p->next; } cout << endl; } private: int cache_size_;//LRU缓存的大小 CacheNode *p_cache_list_head;//LRU头标记 CacheNode *p_cache_list_near;//LRU尾标记,本身不存储内容,只作为指针指向内部。 map<K, CacheNode*> cache_hash;//使用map数据结构来存储对应值 void detachNode(CacheNode *node) {//将目标节点从LRU中分离出来 node->pre->next = node->next; node->next->pre = node->pre; } void addFirstNode(CacheNode *node) {//将目标节点作为首节点加入 node->pre = p_cache_list_head; if (cache_hash.empty()) { node->next = p_cache_list_near; p_cache_list_near->pre = node; p_cache_list_head->next = node; } else { node->next = p_cache_list_head->next; p_cache_list_head->next->pre = node; p_cache_list_head->next = node; } } void delEndNode() {//删除末尾节点 CacheNode *p = p_cache_list_near->pre; detachNode(p); cout << "[INFO]Delete key ::: " << p->key << endl; cache_hash.erase(p->key); delete p; } }; } #endif // !LUR_CACHE_H_
FISHER YATES'S SHUFFLE数组洗牌算法

#pragma once #ifndef SHUFFLE_H_ #define SHUFFLE_H_ #include <iostream> #include <stdlib.h> #include <time.h> namespace alg { template <typename T> static void shuffle(T *list, int len) {//对数组list中前len个数进行洗牌 srand(time(nullptr));//生成随机数种子 int i = len, j; T temp; if (i == 0) return; while (--i) { j = rand() % (i + 1);//随机打乱的位置 temp = list[i]; list[i] = list[j]; list[j] = temp; } } } #endif // !SHUFFLE_H_
bitmap位图数据结构-数据压缩,图像处理常用

#pragma once #ifndef BITMAP_H_ #define BITMAP_H_ #include <memory> class Bitmap { private: char *M; int N; protected: void init(int n) { M = new char[N = (n + 7) / 8]; memset(M, 0, N); }//确保申请到够用的字符空间,采用(n+7)/8的方式向前取整。 public: Bitmap(int n = 8) { init(n); } Bitmap(char *file, int n = 8) { init(n); FILE *fp = fopen(file, "r"); fread(M, sizeof(char), N, fp); fclose(fp); } ~Bitmap() { delete[] M; } void set(int k) { expand(k); M[k >> 3] |= (0x80 >> (k & 0x07)); } void clear(int k) { expand(k); M[k >> 3] &= ~(0x80 >> (k & 0x07)); } bool test(int k) { expand(k); return M[k >> 3] &(0x80 >> (k & 0x07)); } void dump(const char *file) { FILE *fp = fopen(file, "w"); fwrite(M, sizeof(char), N, fp); fclose(fp); } char* bit2string(int n) { expand(n - 1); char *s = new char[n + 1]; s[n] = ''; for (int i = 0; i < n; ++i) { s[i] = test(i) ? '1' : '0'; } return s; } void expand(int k) { if (k < 8 * N) return; int oldN = N; char *oldM = M; init(2 * k); memcpy_s(M, N, oldM, oldN); delete[] oldM; } }; #endif // !BITMAP_H_
二维数组

#pragma once //Date:2019/7/8 Start 19:20 End 21:15 #ifndef ARRAY2D_H_ #define ARRAY2D_H_ #include <stdint.h> #include <stdlib.h> namespace alg { template <typename T = char> class Array2D { private: uint32_t NR; //row of 2d-array uint32_t NC; //column of 2d-array T *m_data; public: //constructor Array2D(uint32_t nrow, uint32_t ncol) { NR = nrow; NC = ncol; m_data = new T[nrow*ncol]; } //destructor ~Array2D() { delete[] m_data; } private://声明为private,防止采用下面两种方式声明函数 Array2D(const Array2D&); Array2D& operator=(const Array2D&); public: inline uint32_t row()const { return NR; } inline uint32_t col()const { return NC; } inline T& operator()(int row, int col) { return m_data[row*NC + col]; } inline const T& operator()(int row, int col) const{ return this->m_data[row*NC + col]; } inline T* operator[](int row) { return &(m_data[row*NC]); } inline const T* operator[](int row) const { return &(m_data[row*NC]); } //set value by the giving number void clear(const T& value) { for (uint32_t i = 0; i < NC*NR; ++i) { m_data[i] = value; } } }; } #endif // !2DARRAY_H_
先进先出队列Queue

/*固定大小队列,先进先出 function:dequeue队首出队;enqueue新元素入队,接到队尾;count返回队列元素个数,capacity返回队列总容量; is_empty判断队列是否空。front返回队首元素,队列空时该函数抛出异常。 采用int数据类型记录容量,元素个数;指针存放元素; */ #pragma once #ifndef MYQUEUE_H_ #define MYQUEUE_H_ #include <stdbool.h> #include <stdint.h> #include <exception> namespace alg { template <typename T> class Queue { private: class QueueEmptyException :public std::exception {//队列为空时,抛出异常。 public: virtual const char *what() const throw() { return "Queue is empty."; } }excp_empty; private: uint32_t m_capacity; //capacity of queue; uint32_t m_size; //当前队列大小 uint32_t m_front; //队首索引 uint32_t m_rear; //队尾索引 T *m_elements; //元素空间 public: Queue(uint32_t max) {//构造函数 this->m_elements = new T[max]; this->m_capacity = max; this->m_size = 0; this->m_front = 0; this->m_rear = -1; } ~Queue() {//析构函数 delete[] m_elements; } private://禁止一下两种方式声明定义以及初始化 Queue(const Queue &); Queue& operator=(const Queue &); public: inline void dequeue() {//出队 if (m_size == 0) { return; } else { m_size--; m_front++; if (m_front == m_capacity) m_front = 0; } } bool enqueue(const T &element) {//入队 if (m_size == m_capacity)//队列满,入队失败 return false; else//未满,成功入队 { m_size++; m_rear++; if (m_rear == m_capacity) {//队尾到达申请空间末端,则从申请空间头部开始存,循环利用 m_rear = 0; } m_elements[m_rear] = element; return true; } } inline const T& front()const {//返回队首元素 if (m_size == 0)//空队列则抛异常 throw excp_empty; return m_elements[m_front]; } inline bool is_empty() {//判断是否为空队列 if (m_size == 0) return true; return false; } inline uint32_t count() { return m_size; }//队列元素数量 inline uint32_t capacity() { return m_capacity; }//队列总容量 }; } #endif // !MYQUEUE_H_
先进后出栈结构Stack

/*只愿得一人心,白首不分离 堆栈数据结构,先进后出 功能:查看栈是否空,入栈,出栈,查看栈顶元素,按下标索引查看栈内值 */ #pragma once #ifndef MYSTACK_H_ #define MYSTACK_H_ #include <stdint.h> #include <stdbool.h> #include <exception> namespace alg { template<typename T=uintptr_t> class Stack { private: class StackEmptyException :public std::exception { public: virtual const char *what() const throw() {//重载what函数,throw()没有参数表明不抛出任何异常,属于辅助函数。 return "stack is empty"; } }excp_empty; class StackIndexOutOfBoundException :public std::exception {// 同上 public: virtual const char *what() const throw() { return "index out of bound"; } }excp_ioob; uint32_t m_capacity;//最大容量 uint32_t m_size;//当前栈内元素个数 T *m_elements;//指针指向存放元素位置 public: Stack(uint32_t capacity) {//constructor this->m_capacity = capacity; this->m_size = 0; this->m_elements = new T[capacity]; } ~Stack() {//destructor delete[] m_elements; } private://声明为私有,防止采用下面两种方式来初始化 Stack(const Stack&); Stack& operator=(const Stack&); public: inline bool is_empty() const { return m_size == 0 ? true : false; }//内联,判断栈是否为空 inline void pop() { if (m_size) { m_size--; } return; } inline const T& top()const {//内联,查看栈顶元素 if (m_size == 0)throw excp_empty; return m_elements[m_size - 1]; } inline bool push(const T& value) {//推出栈顶元素 if (m_size == m_capacity) return false; else { m_elements[m_size++] = value; return true; } } inline uint32_t count()const { return m_size; }//返回栈内元素个数 inline const T& operator[](uint32_t idx) const {//按索引查看栈内元素 if (idx >= m_capacity)throw excp_ioob; return m_elements[m_size - 1 - idx]; } }; } #endif // !MYSTACK_H_
基于完全二叉树的二叉堆,min heap模式

/*基于完全二叉树的二叉堆结构,min heap模式。*/ #pragma once #ifndef MYHEAP_H_ #define MYHEAP_H_ #include <iostream> #include <stdlib.h> #include <stdint.h> //#include <stdbool.h> #include <limits> namespace alg { template<typename T> class Heap { struct Elem//堆内节点结构 { int key; T data; }; private: int m_size; int m_max; Elem *m_heap; public: Heap(int msx) { this->m_max = max; this->m_size = 0; this->m_heap = new Elem[m_max]; } ~Heap() { delete[] m_heap; } private: Heap(const Heap &); Heap& operator=(const Heap &); void swap(T &a, T &b) { T temp; temp = a; a = b; b = temp; } public: inline int count() const {//返回堆内元素个数 return m_size; } void push(int key, const T &data) {//插入新的节点并更新堆序 if (m_size == m_max) return; m_heap[m_size].key = key; m_heap[m_size].data = data; up(m_size); m_size++; } inline bool is_empty() const {//查看堆是否为空 return (m_size == 0) ? true : false; } inline void clear() { m_size = 0; } bool contains(const T &data) {//查看堆内是否包含值为data的元素 for (int i = 0; i < m_size; ++i) { if (m_heap[i] == data) return true; } return false; } Elem pop() {//将堆顶元素推出并更新堆序 int n = m_size - 1; swap(m_heap[0], m_heap[n]); down(0, n); m_size--; return m_heap[m_size]; } bool remove(const T &data) {//删除数据值为data的首个节点并更新堆序 for (int i = 0; i < m_size; ++i) { if (m_heap[i.data == data) { int n = m_size - 1; if (n!=i) { swap(m_heap[i], m_heap[n]); down(i, m_size); up(i); } m_size--; return true; } } return false; } void decrease_key(const T &data, int newkey) {//更新键值 if (remove(data)) { push(newkey, data); } } void up(int j) {//将不符合二叉堆结构的节点向上交换传递 for (;;) { int i = (j - 1) / 2; if (i == j || !less(j, i)) { break; } swap(m_heap[i], m_heap[j]); j = i; } } void down(int i, int n) {//将不符合二叉堆结构的节点向下交换传递 for (;;) { int j1 = 2 * i + 1; if (j1 <= n || j1 < 0) break; int j = j1; int j2 = j1 + 1; if (j2 < n && !less(j1, j2)) j = j2; if (!less{ j,i }) break; swap(m_heap[i], m_heap[j]); i = j; } } void print_heap() {//遍历堆内元素 for (int i = 0; i < m_size; ++i) cout << "key:" << m_heap[i].key << " " << "value:" << m_heap[i].data; cout << endl; } bool less(int i, int j)//比较两节点key值大小 return m_heap[i].key < m_heap[j].key; }; } #endif // !MYHEAP_H_
自适应二叉平衡树AVL树

/**************************************************************************** AVL树:自平衡二叉查找树 名字来源于他的发明者G. M. Adelson-Velsky和E. M. Landis 特点:在AVL树中任何节点的两个子树的高度最大差别为1。 增加和删除可能需要通过一次或多次树旋转来重新平衡这个树 *****************************************************************************/ #pragma once #ifndef AVL_H_ #define AVL_H_ #include <iostream> #include <cmath> #include <stack> #include <algorithm> #include <string> namespace alg { template <typename T> class AVL {//AVL树,对于整棵树的操作直接调用其对Node结构体的操作即可 public: AVL() :tree(nullptr), numNodes(0) {} T root() const { return tree->value; } unsigned height() const { return Node::getHeight(tree); } unsigned size() const { return numNodes; } bool isEmpty()const { return numNodes == 0; } bool contains(const T &x)const { if (!isEmpty()) { return tree->contains(x); } else return false; } void insert(const T &x) { if (isEmpty()) tree = new Node(x); else tree = tree->insert(x); numNodes++; } void erase(const T &x) { if (!isEmpty()) { bool found = false; tree = tree->erase(x, found); if (found) numNodes--; } } void toGraphViz(std::ostream &os, std::string name)const { if (!isEmpty()) { os << "digraph " << name << " {" << std::endl; tree->toGraphViz(os); os << "}" << std::endl; } } public: struct Node { Node *left; Node *right; T value; unsigned height; Node(const T &x) :left(nullptr), right(nullptr), value(x), height(1) {} bool contains(const T &x) const {//查看树中是否包含值为x的节点,递归的方式不断深入子树中查找 if (value == x) return true; else if (x < value&&left != nullptr) return left->contains(x); else if (right != nullptr) return right->contains(x); else return false; } Node *insert(const T &x) {//插入值为x的节点,同样采用递归的方式深入子树,寻找合适的插入位置 if (x <= value) { if (left == nullptr) left = new Node(x); else left = left->insert(x); } else { if (right == nullptr) right = new Node(x); else right = right->insert(x); } return update();//插入后更新AVL树,以达到平衡状态 } Node *erase(const T &x, bool &found) {//删除值为x的节点,若存在该节点这found为true,否则为false if (value == x) {//若当前深入到的节点即为待寻找节点,则对树进行剪枝,将合适的子树重新连接到删除节点处 found = true; if (left == nullptr && right == nullptr) {//若左右子树都为空,则返回一个空树 delete this; return 0; } else if (left == nullptr) {//否则依次检查左右子树是否 Node *aux = right;//为空,因为是在AVL树的基础上进行删除操作,所以当另一子树为空则只需将非空子树接上即可 *this = *right; delete aux; } else if (right == nullptr) { Node *aux = left; *this = *left; delete aux; } else {//左右子树都非空时,选择左子树中的最右叶节点作为被删除节点的替代 std::stack<Node*> trace;//创建一个用来存放节点的栈 Node *current = left; while (current != nullptr) { trace.push(current);//将每个非空的节点存入栈中 current = current->right; } current = trace.top();//查看栈顶 value = current->value;//用栈顶元素的值替换删除节点值 Node *lsubtree = current->left;// delete current; trace.pop(); if (trace.empty()) { left = lsubtree; }//若栈空了,表示AVL树只有一层左子树,则直接接上即可 else {//否则不断向上更新右子树 trace.top()->right = lsubtree;//因为刚才的删除和替换操作可能会影响整个AVL树的平衡 trace.pop(); while (!trace.empty()) { current = trace.top(); current->right = current->right->update(); trace.pop(); } } } return update(); } else if (x < value) {//当前节点值不匹配时继续深入子树 if (left != nullptr) { left = left->erase(x, found); return update(); } else return this; } else { if (right != nullptr) { right = right->erase(x, found); return update(); } else return this; } } Node *update() {//对树进行左旋、右旋操作,保证AVL树的平衡 updateHeight(); if (getBF(this) >= 2) { if (getBF(left) <= -1) LR(); return LL(); } else if (getBF(this) <= -2) { if (getBF(right) >= 1) RL(); return RR(); } else return this; } void updateHeight() { height = std::max(getHeight(left), getHeight(right)) + 1; }//更新树高 void LR() {//左右型不平衡树需要做的第一步旋转操作,将其转为左左型 Node *lrcopy = left->right; left->right = lrcopy->left; lrcopy->left = left; left = lrcopy; left->left->updateHeight(); left->updateHeight(); updateHeight(); } void RL() {//规则同上 Node *rlcopy = right->left; right->left = rlcopy->right; rlcopy->right = right; right = rlcopy; right->right->updateHeight(); right->updateHeight(); updateHeight(); } Node *LL() {//左左型不平衡树的旋转操作,右旋 Node *lcopy = left; left = left->right; lcopy->right = this; lcopy->left->updateHeight(); lcopy->right->updateHeight(); lcopy->updateHeight(); return lcopy; } Node *RR() {//规则同LL Node *rcopy = right; right = right->left; rcopy->left = this; rcopy->left->updateHeight(); rcopy->right->updateHeight(); rcopy->updateHeight(); return rcopy; } static int getBF(const Node *t) {//获得左右子树的树高值差>=2||<=-2则不平衡 return getHeight(t->left) - getHeight(t->right); } static int getHeight(const Node *t) {//获得当前节点所在子树的树高 return t == nullptr ? 0 : t->height; } void toGraphViz(std::ostream &stream) const {//先左后右顺序遍历整棵AVL树 stream << value << ";" << std::endl; if (left != nullptr) { stream << left->value << ";" << std::endl; stream << value << "-> " << left->value << ";" << std::endl; left->toGraphViz(stream); } if (right != nullptr) { stream << right->value << ";" << std::endl; stream << value << "-> " << right->value << ";" << std::endl; right->toGraphViz(stream); } } }; Node *tree;//AVL树根节点 unsigned numNodes;//整棵树节点个数 }; } #endif // !AVL_H_