数据结构——树与二叉树及查找的知识点汇总

树,二叉树,查找的算法总结

一,树的算法总结
总结树需要掌握的几点知识点:
1、树的遍历方式:前序,中序,后序,层序
2、树的递归方式
3、树的迭代(栈)
4、树的创建(列表或者是字典)
5、树的动态规划

下面总结一下常见代码:

//前序遍历
void PreOrderTraverse1(TreeNode* root){
    if (root == NULL)return;
    cout << root->val << '\t';
    PreOrderTraverse1(root->left);
    PreOrderTraverse1(root->right);
}

```cpp
//中序遍历
void InOrderTraverse(TreeNode* root){
    if (root == NULL)return;
    InOrderTraverse(root->left);
    cout << root->val << "\t";
    InOrderTraverse(root->right);
}

```cpp
//后序遍历
void PostOrderTraverse(TreeNode* root){
    if (root == NULL)return;
    PostOrderTraverse(root->left);
    PostOrderTraverse(root->right);
    cout << root->val << "\t";
}
//层次遍历
void LevelOrderTraverse(TreeNode* root){
    if (root == NULL)return;
    queue<TreeNode*> temp;
    temp.push(root);
    while (!temp.empty()){
        TreeNode *p = temp.front();
        cout << p->val << '\t';
        temp.pop();
        if (p->left)temp.push(p->left);
        if (p->right)temp.push(p->right);
    }

————————————————
在这里插入代码片

有关树的一些疑难问题及部分解答:
1.如何得到树的节点个数?
遍历这棵树,用一个值记录节点个数即可;

2.如何得到以可树的高度?
递归得到每个节点的左右子节点的高度,在加上当前节点自己,返回给上一层调用,这样就会一层一层的得到从每个叶子节点往上返回的高度,最终得到树的高度;

3.如何得到一棵树的镜像?(就是每个节点的左右子节点调换位置);
采用前序、中序、后序遍历中的任何一种,从叶子节点开始交换左右节点的指针,往上实现交换指针即可;

4.根据树的前序和中序遍历结果得到一棵树?

二叉树

1.二叉树的遍历算法
二叉树的遍历主要分为三种:先序遍历,中序遍历和后序遍历。还有一种就是按照层次遍历。
先序遍历指的就是先访问本节点,再访问该节点的左和右;
中序遍历指的就是:先访问左,再访问本节点,最后访问右;
后序遍历指的就是:先访问左右,最后访问本节点。
层次遍历:按照树的每一层进行遍历。
树的节点的数据结构常声明为:

struct TreeNode {
    int val;
    TreeNode *left;     
    TreeNode *right;    
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
}
————————————————


2.二叉树的一些其他算法
(1). 二叉树的深度
递归版本非常简洁,也非常易懂;迭代版本则需要利用我们之前介绍的按照层次遍历,层数就是二叉树的深度。

//递归版本
int TreeDepth(TreeNode *pRoot) {
    return pRoot ? 1 + max(TreeDepth(pRoot->left),
                           TreeDepth(pRoot->right)) : 0;
}
//迭代版本
int TreeDepth2(TreeNode *pRoot) {
    queue<TreeNode *> Q;
    Q.push(pRoot);
    int depth = 0;
    while(!Q.empty()) {
        int len = Q.size();
        ++depth;
        while(len--) {
            TreeNode *curr_node = Q.front();
            Q.pop();
            if(curr_node) {
                Q.push(curr_node->left);
                Q.push(curr_node->right);
            }
        }
    }
    return depth - 1;   //将叶节点的空孩子节点也算作一层了,所以减1
}
————————————————

(2). 二叉树的镜像
操作给定的二叉树,将其变换为源二叉树的镜像。使用递归,当节点存在至少一个孩子时,交换左右孩子,再递归处理。

//二叉树的镜像
void Mirror(TreeNode *pRoot) {
	if (pRoot && (pRoot->left || pRoot->right)) {
        std::swap(pRoot->left, pRoot->right);
		Mirror(pRoot->left);
        Mirror(pRoot->right);
	}
	return;

————————————————

(3). 二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
节点的数据结构表示为:

struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;  //父节点
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {}
};
————————————————

.重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

//重建二叉树
TreeNode *reConstructBinaryTree(vector<int>::iterator pre_first, 
							vector<int>::iterator pre_last,
                                vector<int>::iterator vin_first,
                                vector<int>::iterator vin_last) {
	if (vin_last - vin_first != pre_last - pre_first ||
			pre_last == pre_first ||
			vin_first == vin_last) {
		return nullptr;
	}
	TreeNode *curr_node = new TreeNode(*pre_first);
	if (pre_last == pre_first + 1) return curr_node;
	auto iter = vin_first;
	while (iter < vin_last) {
		if (*iter == *pre_first) break;
        iter++;
	}
	int len = iter - vin_first;
	curr_node->left = reConstructBinaryTree(pre_first + 1, pre_first + len + 1, vin_first, iter);
	curr_node->right = reConstructBinaryTree(pre_first + len + 1, pre_last, iter + 1, vin_last);
	return curr_node;
}
TreeNode *reConstructBinaryTree(vector<int> pre, vector<int> vin) {
  return reConstructBinaryTree(pre.begin(), pre.end(), vin.begin(), vin.end());
}
————————————————

树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

//树的子结构
bool isSubtree(TreeNode *pRoot1, TreeNode *pRoot2) {
  //判断以pRoot2为根节点的树是否是以pRoot1为根节点的树的子树
	if (!pRoot2) return true;
	if (!pRoot1) return false;
	return pRoot1->val != pRoot2->val ? false :
		   isSubtree(pRoot1->left, pRoot2->left) &&
		   isSubtree(pRoot1->right, pRoot2->right);
}
bool HasSubtree(TreeNode *pRoot1, TreeNode *pRoot2) {
	if(!pRoot1 || !pRoot2) return false;
	return isSubtree(pRoot1, pRoot2) ||
		   isSubtree(pRoot1->left, pRoot2) ||
		   isSubtree(pRoot1->right, pRoot2);
————————————————

查找

一、二叉树
结合了链表插入的灵活性和有序数组查找的高效性。
每一个结点包含:一个结点计数器(以该结点为根的子树中的结点总数),一个左结点,一个右结点,一个键,一个值。每个结点的键均大于其左子树上的键而小于其右子树上的键。

int get(Node x, int key){
    if(x == null)
        return null;
    if(key < x.key)
        return get(x.left, key);
    else if (key > x.key)
        return get(x.right, key);
    else
        return x.value;
}
 
void put(int key, int val){
    root = put(root, key, val);
}
 
Node put(Node x, int key, int val){
    if (x == null)
        return new Node(key, val, 1);//最后一个参数为结点计数器
    if(key < x.key)
        x.left = put(x.left, key, val);
    else if (key > x.key)
        x.right = put(x.right, key, val);
    else
        x.value = val;
    x.N = size(x.left) + size(x.right) + 1;
    return x;
}
————————————————
运行时间取决于树的形状,树的形状取决于键被插入的先后顺序,最好情况是平衡树,最坏情况是线性树。

删除树的最小结点也就是删除树中最左侧的结点,因为结点的大小顺序为:左<<

附加:
平衡二叉树
优点:最优的查找效率和空间需求;能够进行有序性相关操作
缺点:链接需要额外空间

二分查找算法是在有序数组中用到的较为频繁的一种算法,二分查找算法则更优
在未接触二分查找算法时,最通用的一种做法是,对数组进行遍历
思维导图:
![树与二叉树关系紧密,通过对知识点的掌握理解从而解决更多的问题](https://img-blog.csdnimg.cn/20210430145746245.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3BpZXBpZTg4MjA=,size_16,color_FFFFFF,t_70#pic_center在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值