C++数据结构与算法 --二叉树

二叉树

(本博客主要是用法,对于二叉树的实现没有过多的讲解好像)
菜鸡一枚,不喜勿喷!~~~~
结点结构

struct Tree
{
  int val;
    Tree *left;
    Tree *right;
};

遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hk7PFq1d-1643965048440)(C:\Users\26737\AppData\Roaming\Typora\typora-user-images\image-20220203141700136.png)]

  • 先序遍历

    • //递归遍历
      void preorderTraversal(Tree* head)
      {
          if(head == nullptr)return;
          cout<<head->val<<endl;
          preorderTraversal(tree->left);
          preorderTraversal(tree->right);
      }
      //非递归遍历
      void preorderTraversal(Tree* head)
      {
          stack<Tree*>s;
          s.push(head);
          while(!s.empty())
          {
              head = s.top();
              s.pop();
              cout<<head->val<<" ";
              if(head->right)
                  s.push(head->right);
              if(head->left)  
                  s.push(head->left);
          }
      }
      
  • 中序遍历

    • //递归遍历
      void inOrderUnRecur(Tree* head)
      {
          if(head == nullptr)return;
          inOrderUnRecur(tree->left);
           cout<<head->val<<endl;
          inOrderUnRecur(tree->right);
      }
      //非递归遍历
      void inOrderUnRecur(Tree* head)
      {
      	stack<Tree*>s;
      	while (head!=nullptr||!s.empty())
      	{
              //左边界进栈
      		if (head)
      		{
      			s.push(head);
      			head = head->left;
      		}
              //弹出节点,到右数 重复过程
      		else
      		{
      			head = s.top();
      			s.pop();
      			cout << head->val << " ";
      			head = head->right;
      		}
      	}
      }
      
  • 后序遍历

    • //递归遍历
      void postorderTraversal(Tree* head)
      {
          if(head == nullptr)return;
          postorderTraversal(tree->left);
          postorderTraversal(tree->right);
          cout<<tree->val<<endl;
      }
      //非递归遍历
      void postorderTraversal(Tree* head)
      {
          stack<Tree*>s;
          stack<Tree*>collection;
          s.push(head);
          while(!s.empty())
          {
              head = s.top();
              collection.push(head);
              s.pop();
              if(head->left)  
                  s.push(head->left);
              if(head->right)
                  s.push(head->right);
          }
          while(!collection.empty())
          {
              cout<<collection.top()<<" ";
              collection.pop();
          }
      }
      

深度优先遍历 == 先序遍历

  • 宽度优先遍历

    • 队列 先放头节点,出队列打印,先放左后放右

    • void widthTraversal(Tree* head)
      {
      	if (head == nullptr)return;
      	queue<Tree*>q;
      	q.push(head);
      	while (!q.empty())
      	{
      		head = q.front();
      		q.pop();
      		cout << head->val << " ";
      		if (head->left)
      		{
      			q.push(head->left);
      		}
      		if (head->right)
      		{
      			q.push(head->right);
      		}
      	}
      }
      
      //层序遍历
      class Solution {
      public:
          vector<vector<int>> levelOrder(TreeNode* root) {
              vector <vector <int>> ret;
              if (!root) {
                  return ret;
              }
      
              queue <TreeNode*> q;
              q.push(root);
              //每次队列从有到无代表着一层
              while (!q.empty()) {
                  //获取该层的元素个数
                  int currentLevelSize = q.size();
                  ret.push_back(vector <int> ());
                  for (int i = 1; i <= currentLevelSize; ++i) {
                      auto node = q.front(); q.pop();
                      ret.back().push_back(node->val);
                      if (node->left) q.push(node->left);
                      if (node->right) q.push(node->right);
                  }
              }
              
              return ret;
          }
      };
      

树的最大宽度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPhTnbs9-1643965048442)(C:\Users\26737\AppData\Roaming\Typora\typora-user-images\image-20220203163946359.png)]

//在深度优先遍历上更改
//使用哈希表
int maxTreeWidth(Tree* head)
{
	if (head == nullptr)return 0;
	queue<Tree*>q;
	unordered_map<Tree*, int>levelMap;
    //当前的层数      当前层数结点的个数    最大宽度
	int curLevel = 1, curLevelNodes = 0, maxNum = -1;
	levelMap.insert(make_pair(head, curLevel));
	q.push(head);
	while (!q.empty())
	{
		head = q.front();
		q.pop();
        //根据树的结点找到当前结点的层数
		unordered_map<Tree*,int>::iterator curNodeLevel = levelMap.find(head);
		if (curNodeLevel->second == curLevel)
			curLevelNodes++;
		else
		{
			maxNum = max(maxNum, curLevelNodes);
			++curLevel;
			curLevelNodes = 1;
		}
		if (head->left)
		{
			levelMap.insert(make_pair(head->left, (curNodeLevel->second) + 1));
			q.push(head->left);
		}
		if (head->right)
		{
			levelMap.insert(make_pair(head->right, (curNodeLevel->second) + 1));
			q.push(head->right);
		}
	}
	return max(maxNum, curLevelNodes);
}


//不使用哈希表  有限几个变量
int maxTreeWidthNoHash(Tree* head)
{
	if (head == nullptr)return 0;
	queue<Tree*>q;
	q.push(head);
	Tree* levelEnd = head, * nextEnd = head;
	int num = 1, maxNum = -1;
	while (!q.empty())
	{
		head = q.front();
		q.pop();
		if (head->left)
		{
			q.push(head->left);
			nextEnd = head->left;
		}
		if (head->right)
		{
			q.push(head->right);
			nextEnd = head->right;
		}
		if (head == levelEnd)
		{
			maxNum = max(maxNum, num);
			num = 1;
			levelEnd = nextEnd;
			nextEnd = nullptr;
		}
		else
		{
			num++;
		}
	}
	return maxNum;
}

class Solution {
public:
	int levelOrder(Tree* root) {
		int ret = 0;
		if (!root) {
			return ret;
		}

		queue <Tree*> q;
		q.push(root);
		//每次队列从有到无代表着一层
		while (!q.empty()) {
			//获取该层的元素个数
			int currentLevelSize = q.size();
			ret = max(ret, currentLevelSize);
            //循环的目的就是清空每一层的节点
			for (int i = 1; i <= currentLevelSize; ++i) {
				auto node = q.front(); q.pop();
				if (node->left) q.push(node->left);
				if (node->right) q.push(node->right);
			}
		}

		return ret;
	}
};

搜索二叉树 BST

左边小 中间在其中 右边大

右边>中间>左边

判断是否为BST:可以中序遍历进行判断

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AQoF4PkC-1643965048443)(C:\Users\26737\AppData\Roaming\Typora\typora-user-images\image-20220203212450438.png)]

//递归实现
bool isBST(Tree* head)
{
	if (!head)return false;
	//判断左树是否为搜索二叉树
	bool leftIsBST = isBST(head->left);
	int preValue = INT32_MIN;
	//左边的BST
	if (leftIsBST)
	{
		//将上次的值改为当前结点的值
		preValue = head->val;
	}
	else
	{
		return false;
	}
	//走到这说明左树是BST,直接返回右数是否为BST
	return isBST(head->right);
}

//非递归实现
bool isBSTNoRecursion(Tree* head)
{
	stack<Tree*>s;
	int preValue = INT32_MIN;
	while (!s.empty()||head!=nullptr)
	{
		if (head)
		{
			s.push(head);
			head = head->left;
		}
		else
		{
			head = s.top();
			s.pop();
			if (preValue>=head->val)
				return false;
			else
				preValue = head->val;
			head = head->right;
		}
	}
	return true;
}
//黑盒实现 这种情况默认子树给整棵树所有想要的信息   二叉树递归套路
struct returnData
{
	int max;
	int min;
    //是否为搜索二叉树
	bool isBST;
    //代表树是否村子啊
	bool isFlag;
	returnData(bool is, int mi, int ma,bool f) :max(ma), min(mi), isBST(is), isFlag(f) {}
};
returnData process(Tree* head)
{
	if (head==nullptr)
	{
		return returnData(true,INT32_MIN,INT32_MAX,false);
	}
	//获取左树的信息
	returnData left = process(head->left);
	//获取右树的信息
	returnData right = process(head->right);

	//整棵树的信息
	bool isBST = true;
	int min_X = head->val;
	int max_X = head->val;
	if (left.isFlag)
	{
		min_X = min(min_X, left.min);
		max_X = max(max_X, left.max);
	}
	if (right.isFlag)
	{
		min_X = min(min_X, right.min);
		max_X = max(max_X, right.max);
	}
	if (left.isFlag&&(!left.isBST || left.max>=head->val))
	{
		isBST = false;
	}
	if (right.isFlag && (!right.isBST || right.min <= head->val))
	{
		isBST = false;
	}
	return returnData(isBST, min_X, max_X,true);
}

完全二叉树 CBT

怎么判断?按照宽度遍历

条件

  • 任一节点,有右节点无左节点 == 返回false
  • 在条件一成立的条件下,如果遇到第一个左右不全的节点,后续的节点都得是叶节点(不能有子节点)
bool isCBT(Tree* head)
{
	queue<Tree*>q;
	q.push(head);
	//是否遇到了第一个左右不全的节点
	bool flag = false;
	while (!q.empty())
	{
		head = q.front();
		q.pop();
		if (
			//左空 右不空
			(head->left== nullptr &&head->right!=nullptr)
			||
            //遇到第一个左右不全的节点,后续的节点有的不是叶节点
			(flag&&(head->left != nullptr || head->right != nullptr))
			)
		{
			return false;
		} 
		if (head->left)
			q.push(head->left);
		if (head->right)
			q.push(head->right);
		if (head->left == nullptr || head->right == nullptr)
		{
			flag = true;
		}
	}
	return true;
}

满二叉树

节点个数(N)和最大深度(L)满足:N = 2^L - 1

//满二叉树
class manBinaryTree
{
private:
	struct returnData
	{
		int nodes;
		int height;
		returnData(int n, int h) :nodes(n), height(h) {}
	};
	returnData process(Tree* &head)
	{
		if (head == nullptr)
		{
			return returnData(0, 0);
		}
		returnData left = process(head->left);
		returnData right = process(head->right);

		int height = max(left.height, right.height) + 1;
		int nodes = left.nodes + right.nodes + 1;
		return returnData(nodes, height);
	}
public:
	bool isMBT(Tree*& head)
	{
		returnData data = process(head);
		cout << "nodes" << data.nodes << " " << "height:" << data.height << endl;
		//1 << data.height代表 1右移data.height位 就是2的data.height次方
		return data.nodes == ( (1 << data.height) - 1);
	}
};

平衡二叉树

任一一颗子树,左树的高度和右树的高度差都不能大于一

  • 左子树是平衡二叉树
  • 右子树是平衡二叉树
  • |左子树高度 - 右子树高度|<=1

在这里插入图片描述

//代码黑盒   二叉树递归套路
class balanceBinaryTree
{
public:
	struct returnData
	{
		bool isBBT;
        //树的高度
		int height;
		returnData(bool bbt, int h) :isBBT(bbt), height(h) {}
	};
	returnData process(Tree* head)
	{
		if (head == nullptr)
		{
			return returnData(true, 0);
		}
		returnData left = process(head->left);
		returnData right = process(head->right);
		//整棵树的信息
        //此处会计算树的高度
		int height = max(left.height, right.height) + 1;
		bool isBBT = true;
		if (!left.isBBT||!right.isBBT||abs(left.height - right.height)>1)
			isBBT = false;
		return returnData(isBBT, height);
	}
};

二叉树递归套路

树型DP

给定一棵树,认为左右子树可以给自己所有想要的信息

实用

最低公共祖先

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GzzeA4LD-1643965048446)(C:\Users\26737\AppData\Roaming\Typora\typora-user-images\image-20220204130443355.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AOwIBpCg-1643965048447)(C:\Users\26737\AppData\Roaming\Typora\typora-user-images\image-20220204130616896.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjQkrwUK-1643965048448)(C:\Users\26737\AppData\Roaming\Typora\typora-user-images\image-20220204135351424.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v2vPod2C-1643965048449)(C:\Users\26737\AppData\Roaming\Typora\typora-user-images\image-20220204135356827.png)]

//使用哈希表实现


//套路的实现  具体看上图
class LowestAncestor 
{
public:
	Tree* lowerAncestorFun(Tree* head, Tree* o1, Tree * o2)
	{
		return process(head, o1, o2);
	}
private:
	Tree* process(Tree* head, Tree* o1, Tree* o2)
	{
		if (head == nullptr||head==o1||head==o2)
			return head;
		Tree* left = process(head->left,o1,o2);
		Tree* right = process(head->right, o1, o2);
		//左边右边都不为空的话  代表该head为公共祖先
		if (left!=nullptr&&right!=nullptr)
			return head;
		//代表左右两个节点全null返回null  一个不为空返回不为空的哪一个
		return (left != nullptr) ? left : right;
	}
};

后继节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NbTJtzuU-1643965048449)(C:\Users\26737\AppData\Roaming\Typora\typora-user-images\image-20220204152643460.png)]

一种情况没有父指针:时间复杂度O(N)

如果两个节点距离相差为k:时间复杂度O(K)

struct  TreeP
{
	int val;
	TreeP* left;
	TreeP* right;
	TreeP* parent;
	TreeP() : val(0), left(nullptr), right(nullptr),parent(nullptr) {}
	TreeP(int x) : val(x), left(nullptr), right(nullptr), parent(nullptr) {}
	TreeP(int x, TreeP* left, TreeP* right, TreeP* parent) : val(x), left(left), right(right), parent(parent) {}
};
//后继节点
class FindBackList 
{
public:
	TreeP* findBackList(TreeP* curList)
	{
		if (curList == nullptr)
			return nullptr;
		//有右树
		if (curList->right)
			return findLeft(curList->right);
		//无右树
		else
		{
			TreeP* parent = curList->parent;
			while (parent!=nullptr&& curList != parent->left)
			{
				curList = parent;
				parent = curList->parent;
			}
			return parent;
		}
	}
private:
	TreeP* findLeft(TreeP* head)
	{
		while (head->left)
			head = head->left;
		return head;
	}
};

序列化和反序列化

在这里插入图片描述
在这里插入图片描述

//序列化和反序列化
class TreeBeString
{
public:
	string treeBeString(Tree* head)
	{
		if (head == nullptr)return "#_";
		
		string res =to_string(head->val)+ "_";
		res+=treeBeString(head->left);
		res+=treeBeString(head->right);
		return res;
	}
	Tree* stringBeTree(string s)
	{
		int pos = -1,index = 1;
		int len = s.size();
		queue<string>ch;
		//6_5_4_#_#_6_#_#_9_8_#_#_10_#_#_
		while (pos<len-1)
		{
			string str = s.substr(pos+1, index-pos-1);//开始位置  开始个数
			pos = s.find('_', pos+1);
			index = s.find('_', index + 1);
			ch.push(str);
		}
		return reconByPreString(ch);
		
	}
	Tree* reconByPreString(queue<string>s)
	{
		string value = s.front();
		s.pop();
		if (value == "#")
			return nullptr;
		//aoti将char 或者 char[]转化为int
		Tree* head = new Tree(atoi(value.c_str()));
		head->left = reconByPreString(s);
		head->right = reconByPreString(s);
		return head;
	}
};

纸条折痕问题

在这里插入图片描述

//纸条遍历
class T
{
public:
	void printAllFolds(int N)
	{
		//false代表 凹   true代表凸
		process(1, N, false);
	}
private:
	void process(int i, int N, bool down)
	{
	//相当于模拟中序遍历二叉树  并不实际存在的二叉树
		//i代表当前层数
		if (i > N)return;
		process(i + 1, N, false);
		cout <<(down ? "凸" : "凹");
		process(i + 1, N, true);
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值