数据结构_进阶(2):二叉树的OJ练习题

news2024/12/24 3:56:28

目录

1. 二叉树创建字符串。OJ链接

2. 二叉树的分层遍历1。OJ链接

3. 二叉树的分层遍历2。OJ链接

4. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 。OJ链接

5. 二叉树搜索树转换成排序双向链表。OJ链接

6. 根据一棵树的前序遍历与中序遍历构造二叉树。 OJ链接

7. 根据一棵树的中序遍历与后序遍历构造二叉树。OJ链接

8. 二叉树的前序遍历,非递归迭代实现 。OJ链接

9. 二叉树的中序遍历 ,非递归迭代实现。OJ链接

10. 二叉树的后序遍历 ,非递归迭代实现。OJ链接


1. 二叉树创建字符串。OJ链接

分析题型如下:

根据示例可以看到其省的括号并不是把所有的都省了,而是会保留左子树的括号
左右都为空省略,左为空不能省略,右为空可以省略

思路:

用递归遍历整棵树,注意要将每个节点的值转为字符串类型,再利用重载的+=来添加括号

我们先写一个不省略括号的代码,然后根据之前的三个条件进行限制

不省略括号的代码如下:

根据条件加入限制得到:

class Solution {
public:
    string tree2str(TreeNode* root) {
        if(root == nullptr)
            return "";

        string str = to_string(root->val);

        // 先判断左是否为空,不为空:继续;为空:再判断右为不为空;
        // 不为空:左不能省,继续;
        // 为空,那么此时左右都为空,就可以省略了。
        if(root->left || root->right)
        {
            str += '(';
            str += tree2str(root->left);
            str += ')';
        }

        // 在上面条件判断后,再判断右是否为空
        // 如果右为空:省略;右不为空:继续。
        if(root->right)
        {
            str += '(';
            str += tree2str(root->right);
            str += ')';
        }
        
        return str;
    }
};

2. 二叉树的分层遍历1。OJ链接

思路:

用一个队列来存放数据,在这个队列出数据的时候,将其的左右节点入栈,
再定义一个变量 levelsize 用来存储该层有多少个数

具体如下图:

代码:

class Solution {
public:
    // vector<vector<int>>二维数组
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> q;
        int levelsize = 0;

        if(root)
        {
            q.push(root);
            levelsize = 1;
        }

        vector<vector<int>> vv;

        //当队列为空时结束
        while(!q.empty())
        {
            // 通过levelsize来控制一层一层的出
            vector<int> v;//把每一层的数据放到一个vector里面

            while(levelsize--)
            {
                TreeNode* F = q.front();//F就是此时要控制的树的节点
                q.pop();
                v.push_back(F->val);

                if(F->left)
                    q.push(F->left);
                if(F->right)
                    q.push(F->right);
            }
            // 将第每一层的数组v放到二维数组中
            vv.push_back(v);
            // 更新下一层的数据
            levelsize = q.size();

        }

        return vv;
    }
};

3. 二叉树的分层遍历2。OJ链接

思路:

这道题的思路和上面那道题的思路一模一样,只是我们在最后需要稍微处理一下,使其反转打印

我们C++里面的算法头文件里面有一个reverse的逆置算法

 正好可以用到此问题上

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> q;
        int levelsize = 0;

        if(root)
        {
            q.push(root);
            levelsize = 1;
        }

        vector<vector<int>> vv;

        //当队列为空时结束
        while(!q.empty())
        {
            // 通过levelsize来控制一层一层的出
            vector<int> v;//把每一层的数据放到一个vector里面

            while(levelsize--)
            {
                TreeNode* F = q.front();//F就是此时要控制的树的节点
                q.pop();
                v.push_back(F->val);

                if(F->left)
                    q.push(F->left);
                if(F->right)
                    q.push(F->right);
            }
            // 将第每一层的数组v放到二维数组中
            vv.push_back(v);
            // 更新下一层的数据
            levelsize = q.size();

        }
        // 反转
        reverse(vv.begin(), vv.end());
        return vv;
    }
};

4. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先 。OJ链接

 

思路1:

首先我们要找最近的公共祖先,那么孩子肯定是在这个公共祖先的一左一右

p、q 是题目给我们的两个数,我们先找这两个数是在,此时节点的左边还是右边

此时会有三种情况:

1)如果p再左,q再右;或者,q在左,p在右。那么此时节点就是最近公共祖先
2)如果都在左,转换为子问题,递归到左子树去找公共祖先
3)如果都在右,转换为子问题,递归到右子树去找公共祖先

class Solution {
public:
    //写判断p、q在左还是右的函数
    bool IsInTree(TreeNode* root, TreeNode* x)
    {
        if(root == nullptr)
        {
            return false;
        }
        if(root == x)
            return true;
        else
            return IsInTree(root->left, x) || IsInTree(root->right, x);
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        //跟为空返回空
        if(root == nullptr)
            return nullptr;
        
        //如果p或q有一个为跟,另一个是孩子,root就是最近祖先
        if(p == root || q == root)
            return root;
        
        //判断p、q在左边还是右边
        bool pInLift = IsInTree(root->left, p);
        bool pInRight = !pInLift;

        bool qInLift = IsInTree(root->left, q); 
        bool qInRight = !qInLift;

        //1.如果一个在左,一个在右。那么此时节点就是最近公共祖先
        //2.如果都在左,转换为子问题,递归到左子树去找公共祖先
        //3.如果都在右,转换为子问题,递归到右子树去找公共祖先
        if((pInLift && qInRight) || (qInLift && pInRight))
        {
            return root;
        }
        else if(pInLift && qInLift)
        {
            return lowestCommonAncestor(root->left, p, q);
        }
        else
        {
            return lowestCommonAncestor(root->right, p, q);
        }
    }
};

思路2:

我们可以看到按照思路1来写的代码可以通过,但比较费时间

我们可以来算一下思路1代码的时间复杂度:

可能会有人觉得上述代码的时间复杂度是 O(n*logN),查找是N,高度是logN

但实际上并不是,我们要注意:只有完全二叉树和满二叉树我们才能认为它的高度是 logN
因为有可能是课歪脖子树,所以上述代码的时间复杂度是 O(n^2)

思路二就是用两个栈来记录p、q的路径,然后将两个路径进行比较

从3的左边开始遍历到6的时候左右都没有,就把6出了

class Solution {
public:
    bool Getpath(TreeNode* root, TreeNode*x, stack<TreeNode*>& path)
    {
        //先写递归结束条件
        if(root == nullptr)
            return false;
        //入栈
        path.push(root);

        // 等于要找的数,结束
        if(root == x)
            return true;

        // 不等于,继续递归找
        if(Getpath(root->left, x, path))
            return true;
        if(Getpath(root->right, x, path))
            return true;

        //递归到头都没找到,则出栈
        path.pop();
        return false;
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        // 定义两个栈,一个存放p的路径,一个存放q的路径
        stack<TreeNode*> pPath, qPath;

        // 找p和q,并记录其路径
        Getpath(root, p, pPath);
        Getpath(root, q, qPath);

        // 将长路径出,直到到和短路径一样长
        while(pPath.size() != qPath.size())
        {
            if(pPath.size() > qPath.size())
                pPath.pop();
            else
                qPath.pop();
        }    

        // 两个一起出,直到他们有相等的值结束
        while(pPath.top() != qPath.top())
        {
            pPath.pop();
            qPath.pop();
        }

        //此时不管是pPath还是qPath的首元素都是最进祖先
        return qPath.top();
    }
};

5. 二叉树搜索树转换成排序双向链表。OJ链接

要求里面需要我们在原树上进行修改,并且空间复杂读为 O(1),
如果没有这个要求,我们就可以将其中序遍历存放到vector中,然后再该链接关系,就会非常简单

思路:

我们还是中序遍历该树,得到:4,6,8,10,12,14,16
同时记录一个前驱prev,一个当前cur;因为是中序遍历,所以一个数的左一定是指向前驱的
此时难点在于找后继节点:我们让cur->left = prev  ,让prev->right = cur
最后,在修改完之后我们只能拿到root跟节点,但这个根节点不是循环链表的头,所以我们只需要去往左走,走到头即可

class Solution 
{
public:
	// prev在递归是不能改变,所以需要引用起别名
	void InorderTraversal(TreeNode* cur, TreeNode*& prev)
	{
		if(cur == nullptr)
			return;
		//中序遍历
		InorderTraversal(cur->left, prev);
		
		cur->left = prev;
		//防止刚开始prev为空
		if(prev)
			prev->right = cur;
		prev = cur;

		InorderTraversal(cur->right, prev);
	}
    TreeNode* Convert(TreeNode* pRootOfTree)
	{
        TreeNode* prev = nullptr;
		InorderTraversal(pRootOfTree, prev);

		TreeNode* head = pRootOfTree;

		// 寻找头结点
		while(head && head->left)
			head = head->left;

		return head;
    }
};

6. 根据一棵树的前序遍历与中序遍历构造二叉树。 OJ链接

思路:

通过前序数组不断去确定根,然后对中序数组进行空间划分,当空间没有是返回根

class Solution 
{
public:
    // 因为需要递归,不好再原树上进行操作,所以先建立一个子函数
    // int& prei定义前序的一个下标需要一直往后走,中序需要定义一段区间,来分割子树:inbegin、inend
    TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder, int& prei, int inbegin, int inend) 
    {
        // 结束条件
        if(inbegin > inend)
            return nullptr;

        TreeNode* root = new TreeNode(preorder[prei]);

        // 分割出左右区间
        int rooti = inbegin;
        // 再中序数组里面找到根
        while(rooti <= inend)
        {
            //判断中序数组里的值与前序数组里的值是否相等,相等找到,不相等继续找
            if(inorder[rooti] == preorder[prei])
                break;
            else
                rooti++;
        }
        // 此时在前序数组里面找下一个左子树的根节点
        ++prei;

        // 中序数组被分割出了三段区间:[inbegin, rooti-1]; rooti; [rooti+1,inend]
        root->left = _buildTree(preorder, inorder, prei, inbegin, rooti-1);
        root->right = _buildTree(preorder, inorder, prei, rooti+1, inend);
        
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
    {
        int i = 0;
        return _buildTree(preorder, inorder, i, 0, inorder.size()-1);
    }
};

7. 根据一棵树的中序遍历与后序遍历构造二叉树。OJ链接

和上一题的解题思路一致,只是把从前序数组的前往后找根节点,换位了,后序数组的从后往前找根节点,需要注意的是,在建立二叉树的过程中,需要先构建右子树,然后再构建左子树

class Solution {
public:
    TreeNode* _buildTree(vector<int>& postorder, vector<int>& inorder, int& prei, int inbegin, int inend) 
    {
        // 结束条件
        if(inend < inbegin)
            return nullptr;

        TreeNode* root = new TreeNode(postorder[prei]);

        // 分割出左右区间
        int rooti = inbegin;
        // 再中序数组里面找到根
        while(rooti <= inend) //rooti <= inend
        {
            //判断中序数组里的值与后序数组里的值是否相等,相等找到,不相等继续找
            if(inorder[rooti] == postorder[prei])
                break;
            else
                rooti++;
        }
        // 此时在后序数组里面找下一个左子树的根节点
        --prei;

        // 中序数组被分割出了三段区间:[inbegin, rooti-1]; rooti; [rooti+1,inend]
        root->right = _buildTree(postorder, inorder, prei, rooti+1, inend);
        root->left = _buildTree(postorder, inorder, prei, inbegin, rooti-1);
        
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) 
    {
        int i = postorder.size()-1;
        return _buildTree(postorder, inorder, i, 0, inorder.size()-1);
    }
};

8. 二叉树的前序遍历,非递归迭代实现 。OJ链接

思路:

还是用栈,先把左路的数都放入栈,然后再依次出栈,其孩子入栈

  • 1.左路节点
  • 2.左路节点的右子树

这里的右子树怎么访问?
继续变为子问题,再继续左路节点,如下图详解:

下图中入栈顺序是前序的顺序,出栈顺序是后续的顺序

代码如下:

class Solution {
public:
    //  非递归实现:
    vector<int> preorderTraversal(TreeNode* root) 
    {
        // 创建一个栈来存放数据
        stack<TreeNode*> st;
        TreeNode* cur = root;
        // 创建对象v来存放出栈的数据
        vector<int> v;
        // 需要cur为空并且栈为空才会结束
        while(cur || !st.empty())
        {
            // 一直往左边去走,直到左边为空
            while(cur)
            {
                // 入栈前,给数组v尾插数据
                v.push_back(cur->val);
                // 将左树的值入栈
                st.push(cur);
                //继续往左走
                cur = cur->left;
            }

            //左为空后出栈,走右
            //取栈顶数据,然后出栈
            TreeNode* top = st.top();
            st.pop();

            cur = top->right;
        }

        return v;
    }
};

9. 二叉树的中序遍历 ,非递归迭代实现。OJ链接

思路:

和前序队列一样,仔细观察前序队列的图,就可以发现,每次出栈的顺序就是中序队列的顺序,所以下面代码仅仅只是将vector的尾插放在了出栈前而不是入栈前。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        // 创建一个栈来存放数据
        stack<TreeNode*> st;
        TreeNode* cur = root;
        // 创建对象v来存放出栈的数据
        vector<int> v;
        // 需要cur为空并且栈为空才会结束
        while(cur || !st.empty())
        {
            // 一直往左边去走,直到左边为空
            while(cur)
            {
                // 将左树的值入栈
                st.push(cur);
                //继续往左走
                cur = cur->left;
            }

            //左为空后出栈,走右
            //取栈顶数据,然后出栈
            TreeNode* top = st.top();

            //出栈时,给v里面放入数据,此时将会是中序队列
            v.push_back(top->val);
            st.pop();

            cur = top->right;
        }

        return v;
    }
};

10. 二叉树的后序遍历 ,非递归迭代实现。OJ链接

后序遍历比前序和中序要难思考一点,所以一般笔试什么的都会考后序遍历

思路1:

我们先走左子树,走到最后一个左子树的时候
1)当其右子树为空,我们可以直接拿取
2)当右子树不为空,我们第二次走到父节点时,拿取(举个例子,如下:)
        

        我们会在第二次访问的时候拿取

代码如下:(注意看注释理解)

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        // 创建一个栈来存放数据
        stack<TreeNode*> st;
        TreeNode* cur = root;
        // 创建对象v来存放出栈的数据
        vector<int> v;

        // 加入
        TreeNode* prev = nullptr;

        // 需要cur为空并且栈为空才会结束
        while(cur || !st.empty())
        {
            // 一直往左边去走,直到左边为空
            while(cur)
            {
                // 将左树的值入栈
                st.push(cur);
                //继续往左走
                cur = cur->left;
            }

            //左为空后出栈,走右
            //取栈顶数据,然后出栈
            TreeNode* top = st.top();

            //1、右为空,可以访问跟节点
            //2、右子树已经被访问过了(上一个访问的节点是右子树的根)
            if(top->right == nullptr || top->right == prev)
            {
                v.push_back(top->val);
                st.pop();

                prev = top;
            }
            else
            {
                //访问右子树,子问题
                cur = top->right;
            }
        }
        return v;
    }
};

思路2:

后序遍历的访问方式是:左右根,我们把它逆置一下变为:根右左
和前序比较可以发现只需要改一下前序代码,
使其先入栈右边的树,然后再入左边的树,最后来个逆置也是可以的!

这种方法也是最简单的,也这算是一个取巧的操作,代码如下:

class Solution {
public:
    //  非递归实现:
    vector<int> preorderTraversal(TreeNode* root) 
    {
        // 创建一个栈来存放数据
        stack<TreeNode*> st;
        TreeNode* cur = root;
        // 创建对象v来存放出栈的数据
        vector<int> v;
        // 需要cur为空并且栈为空才会结束
        while(cur || !st.empty())
        {
            // 一直往右边去走,直到右边为空
            while(cur)
            {
                // 入栈前,给数组v尾插数据
                v.push_back(cur->val);
                // 将左树的值入栈
                st.push(cur);
                //继续往右走
                cur = cur->right;
            }

            //左为空后出栈,走右
            //取栈顶数据,然后出栈
            TreeNode* top = st.top();
            st.pop();

            cur = top->left;
        }
        reverse(v.begin(), v.end());
        
        return v;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/761253.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年NOC决赛-加码未来编程赛项决赛模拟题-Python模拟题--卷4

第一题、计算 1+2+3+⋯+(n−1)+n 的值,其中正整数 n 不大于 100。由于你没有高斯聪明,所以你不被允许使用等差数列求和公式直接求出答案。 输入格式 输入一个正整数 n。 输出格式 输出一个正整数,表示最后求和的答案。 输入输出样例 输入 #1 100 输出 #1 5050 第二…

手撕自定义类型:结构体,枚举,联合——【C语言】

在开始学习之前我们先来欣赏一下五岳之一华山的风景&#xff0c;来营造一个好心情&#xff0c;只有一个好心情我们才能更好的学习 目录 结构体 1 结构体的声明 1.1 结构的基础知识 1.2 结构的声明 1.3 特殊的声明 1.4 结构的自引用 1.5 结构体变量的定义和初始化 1.6 …

Go语言之重要数组类型切片(slice)make,append函数

切片是一个动态数组&#xff0c;因为数组的长度是固定的&#xff0c;所以操作起来很不方便&#xff0c;比如一个names数组&#xff0c;我想增加一个学生姓名都没有办法&#xff0c;十分不灵活。所以在开发中数组并不常用&#xff0c;切片类型才是大量使用的。 切片基本操作 切片…

Linux系统文件编程及文件读、写操作

Linux 系统编程Day01 文章目录 Linux 系统编程Day011.文件编程概述1.1 文件的打开及创建1.1.1 参数说明1.1.2 文件写入操作示例1.1.3 文件的权限 2.文件操作2.1 写入文件2.2 文件读取操作2.3 文件的光标移动操作 3.文件操作原理简述3.1文件描述符3.2 Linux文件操作流程 1.文件编…

【数据结构】二叉树的前中后序遍历(C语言)

文章目录 什么是二叉树树相关的概念树的表示形式特殊的二叉树如何创造出一棵二叉树二叉树的遍历先序遍历(前序遍历)中序遍历后序遍历 总结 什么是二叉树 [二叉树] 顾名思义就是有两个分支节点的树&#xff0c;不仅如此&#xff0c;除了叶子外的所有节点都具有两个分支节点&…

单个电源模块给多个负载使用,并且电源后还经过了磁珠-二级电源直流压降仿真

单个电源模块给多个负载使用,并且电源后还经过了磁珠-二级电源直流压降仿真 下面介绍单个电源模块给多个负载使用,并且电源后还经过了磁珠-二级电源直流压降仿真,常见于二级压降仿真,以下图为例

备战秋招 | 笔试强训5

目录 一、选择题 二、编程题 三、选择题题解 四、编程题题解 一、选择题 1、在上下文和头文件均正常情况下&#xff0c;以下程序的输出结果是&#xff08;&#xff09; int x 1; do {printf("%2d\n",x); }while(x--); A. 1 B. 无任何输出 C. 2 D. 陷入死循环 …

三种智能算法优化PID参数软件,MATLABAPP开发

今天的主题是&#xff1a;三种智能算法优化常见传递函数的PID参数&#xff0c;采用MATLAB APP Designer 开发。提供代码源程序&#xff0c;可以自行修改源代码&#xff08;不是封装软件&#xff09; 这个软件基本涵盖了所有的传递函数类型&#xff0c;传递函数的参数简单易改。…

【Java反射机制详解】—— 每天一点小知识

&#x1f4a7; J a v a 反射机制详解 \color{#FF1493}{Java反射机制详解} Java反射机制详解&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算法》专栏的文章…

pytest 参数化进阶

目录 前言&#xff1a; 语法 参数化误区 实践 简要回顾 前言&#xff1a; pytest是一个功能强大的Python测试框架&#xff0c;它提供了参数化功能&#xff0c;可以帮助简化测试用例的编写和管理。 语法 本文就赶紧聊一聊 pytest 的参数化是怎么玩的。 pytest.mark.par…

week27

这周是磨难的一周不知道NT装了多少次系统&#xff0c;删除了多少数据好消息是把BIOS和ubuntu安装地很熟练了&#xff0c;而且经过爱上了心仪的Ubuntu23.04&#xff0c;就是她了坏消息是一个学期做的笔记全都没了&#xff0c;以后不好回忆了&#xff0c;好消息是不用考试了&…

总结929

今日做了一篇阅读题&#xff0c;差点全军覆没&#xff0c;通过这篇阅读&#xff0c;主要说明了两大问题&#xff0c;一个是单词&#xff0c;背的还不够牢固&#xff0c;其二&#xff0c;语法功底还不够扎实。但说实话&#xff0c;在语法方面&#xff0c;还是下了一番功夫&#…

linux 内网批量快速传输大文件 nc

使用nc工具 传输内网宽带拉满先运行接收端 开始监听使用 ansible 拷贝脚本到其它接收端服务器批量运行接收端脚本查看nc是否运行运行发送端运行发送端脚本开始传输文件 传输内网宽带拉满 先运行接收端 开始监听 接收端脚本 re.sh #!/bin/bash #Revision: 1.0 #Author:…

动态规划(一) —— 从背包系列问题看DP

前言 动态规划可以算是算法初学者的噩梦哈哈&#xff0c;这段时间荔枝在持续学习Java后端的同时也没有忘记刷题嘿嘿嘿&#xff0c;总算把代码随想录上给出的有关动态规划的题目刷完了。接下来的几篇文章荔枝将会对于刷过的动态规划问题做出总结并给出相应的个人体会和理解。在本…

compose之沉浸式(侵入式)状态栏(隐藏状态栏)

沉浸式(侵入式)状态栏 效果图&#xff1a; 1、代码加入&#xff1a;WindowCompat.setDecorFitsSystemWindows(window, false) ComposeTestTheme {WindowCompat.setDecorFitsSystemWindows(window, false)Greeting("Android")} 2、沉浸式(侵入式)主题&#xff1a; …

消息推送(websocket)集群化解决方案

目录 需求分析解决方案实现步骤架构图配置websocket请求地址配置websocket连接前置和连接关闭监听配置websocket处理程序配置redis交换机配置redis订阅监听配置redis发布监听需求分析 及时信息传递:消息推送功能能够确保网站向用户发送及时的重要信息,包括新闻更新、促销活动…

消息队列——rabbitmq的不同工作模式

目录 Work queues 工作队列模式 Pub/Sub 订阅模式 Routing路由模式 Topics通配符模式 工作模式总结 Work queues 工作队列模式 C1和C2属于竞争关系&#xff0c;一个消息只有一个消费者可以取到。 代码部分只需要用两个消费者进程监听同一个队里即可。 两个消费者呈现竞争关…

Redis进阶底层原理-主从复制

Redis的主从节点都会记录对方的信息&#xff0c;核心还包括ReplicationID 和 offset &#xff0c; ReplicationID &#xff1a; 主从节点实例的ID &#xff0c;redis内部就是通过这个id去识别主从节点。offset&#xff1a;数据同步偏移量&#xff0c;也就是从节点每次从主节点同…

3.6 Bootstrap 导航元素

文章目录 Bootstrap 导航元素表格导航或标签胶囊式的导航菜单基本的胶囊式导航菜单垂直的胶囊式导航菜单 两端对齐的导航禁用链接下拉菜单带有下拉菜单的标签带有下拉菜单的胶囊标签页与胶囊式标签页 Bootstrap 导航元素 本文将讲解 Bootstrap 提供的用于定义导航元素的一些选项…

使用thrift编写C++服务器、客户端

在上一节《Linux 下编译 thrift》中&#xff0c;我们成功编译出了thrift的库文件&#xff0c;本节我们来编写thrift的C服务器&#xff0c;客户端。 官网 https://thrift.apache.org/tutorial/cpp.html 有thrift的C例子。在我们之前下载下来的thrift 源码根目录的tutorial/cpp目…