• [数据结构与算法]Note


    括号匹配

    //裁剪字符串,掐头去尾只保留被括号包围的部分
    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);
    }
    View Code

     对字符串形式的数学表达式求值

    下面这段程序用到了指针的引用,与指针的主要区别在于调用函数中形参列表对其声明的方式不同,指针的声明形如: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();
    }
    View Code

     二叉搜索树

    #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_
    View Code

     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_
    View Code

     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_
    View Code

     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_
    View Code

    二维数组

    #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_
    View Code

     先进先出队列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_
    View Code

     先进后出栈结构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_
    View Code

     基于完全二叉树的二叉堆,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_
    View Code

     自适应二叉平衡树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_
    View Code
  • 相关阅读:
    C++报错undefined reference to vtable处理
    emplace_back无法支持<braceenclosed initializer list>吗?
    使用proxychains代理应用
    EasyExcel快速读写Excel数据
    解决SpringBoot跨域的三种方式
    SQL Server 锁(LOCK)大全
    MySQL预处理语句PREPARE、EXECUTE、DEALLOCATE使用大全
    C# 自定义泛型二维数组
    C# 一维数组与二维数组相互转换
    C#枚举高级应用
  • 原文地址:https://www.cnblogs.com/lightmonster/p/11033070.html
Copyright © 2020-2023  润新知