二叉树基础内容

目录

二叉树概念及结构

概念

满二叉树

完全二叉树

二叉树的存储方式

堆:大根堆和小跟堆

堆的性质:

二叉树的定义

遍历

递归遍历

层序遍历

层序遍历题目


概念及结构

概念

一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

二叉树有两种主要的形式:满二叉树完全二叉树

满二叉树

满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。

节点的度:一个节点含有的子树的个数称为该节点的度

这棵二叉树为满二叉树,也可以说深度为k,有2^k-1个节点的二叉树

完全二叉树

完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。

二叉树的存储方式

链式存储也有顺序存储;

链式存储如下

struct TreeNode {

    int val;

    TreeNode *left;

    TreeNode *right;

    
};

顺序存储如下

如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。

堆:大根堆和小跟堆

堆的性质:
  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

二叉树的定义

struct TreeNode {

    int val;

    TreeNode *left;

    TreeNode *right;
    
};

遍历

二叉树主要有两种遍历方式:

  1. 深度优先遍历:先往深走,遇到叶子节点再往回走。
  2. 广度优先遍历:一层一层的去遍历。

那么从深度优先遍历和广度优先遍历进一步拓展,才有如下遍历方式:

  • 深度优先遍历
    • 前序遍历(递归法,迭代法)
    • 中序遍历(递归法,迭代法)
    • 后序遍历(递归法,迭代法)
  • 广度优先遍历
    • 层次遍历(迭代法)

前后中遍历看的是中间遍历的顺序

  • 前序遍历:中左右
  • 中序遍历:左中右
  • 后序遍历:左右中

递归遍历

递归遍历要注意三要素:确定递归函数的参数和返回值

                                        确定终止条件

                                        确定单层递归的逻辑


前序遍历(递归)

/*前序遍历*/
void PreOrder(BiTree T)
{
	if (T == NULL)  return;
	
	printf("树结点的值:%c\n", T->data);             // 访问结点              
	PreOrder(T->lchild);   // 遍历结点左子树
	PreOrder(T->rchild);   // 遍历结点右子树
	
}

递归可以用栈来实现,访问结点并入栈遍历左子树,结点出栈遍历右子树。

(非递归)

算法思路:

1、二叉树为空啥也不做;

2、结点不为空,访问并入栈,接着遍历其左子树;

3、结点为空但栈不为空,栈顶元素出栈,遍历栈顶元素的右子树;

4、结点为空并且栈为空结束遍历。

/*前序遍历*/
void PreOrder2(BiTree T)
{
	Stack<BiTree>a;				  // 申请一个辅助栈
	BiTree p = T;			  // p为遍历指针
	while (p || !empty(a))  // 栈不为空或p不为空时循环
	{
		if (p!==NULL)			      // 一路向左直到尽头
		{
			visit(p);		  // 访问当前节点,并入栈
			a.Push(p)
			p = p->lchild;	  // 左孩子不空,一直向左走
		}
		else				  //出栈,并转向出栈结点的右子树
		{
			Pop();	  // 栈顶元素出栈
			p = p->rchild;    // 向右子树走,p赋值为当前结点的右孩子

		}					  // 返回while循环继续进入if-else语句
	}
}

中序遍历(递归)

/*中序遍历*/
void InOrder(BiTree T)
{
	if (T == NULL) return ;
	
	InOrder(T->lchild);    // 遍历结点左子树
   	printf("树结点的值:%c\n", T->data);            // 访问结点
	InOrder(T->rchild);    // 遍历结点右子树
	
}


非递归

/*中序遍历*/
void InOrder2(BiTree T)
{
	Stack<BiTree>a;                  // 申请一个辅助栈
	BiTree p = T;				// p为遍历指针
	while (p || !Empty(S))    // 栈不空或p不空时循环
	{
		if (p)					// 一路向左
		{
			a.Push(p);        // 当前结点入栈
			p = p->lchild;		// 左孩子不空,一直向左走
		}
		else					// 出栈,并转向出栈结点的右子树
		{
			a.Pop();		// 栈顶元素出栈
			visit(p);			// 访问出栈结点
			p = p->rchild;		// 向右子树走,p赋值为当前结点的右孩子
		}						// 返回while循环继续进入if-else语句
	}
}

后序遍历(递归)


	/*后序遍历*/
void PostOrder(BiTree T)
{
	if (T == NULL)  return;
	
		PostOrder(T->lchild);	// 遍历结点左子树
		PostOrder(T->rchild);	// 遍历结点右子树
		printf("树结点的值:%c\n", T->data);     // 访问结点
	
}
 

非递归

层序遍历

层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树

可以用队列来解决 相当于广搜

 vector<vector<int>> levelOrder(TreeNode* root) {

        queue<TreeNode*> que;

        if (root != NULL) que.push(root);

        vector<vector<int>> result;//二维数组result

        while (!que.empty()) {

            int size = que.size();//size大小是每一层结点

            vector<int> vec;//一维数组  记录每一层的结点

            // 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的

           while(size--) {

                TreeNode* node = que.front();//记录这个点是为了找它的子孩子

                que.pop();

                vec.push_back(node->val);//这一层的结点被收集进这一个一维数组

                if (node->left) que.push(node->left);

                if (node->right) que.push(node->right);
            }
            result.push_back(vec);//将每一个一维数组收集起来合成一个二维数组
        }
        return result;
    }

层序遍历题目

最右边的节点就是层序遍历时每一层最后一个数  只要在写时判断一下这个节点是不是这层最后一个节点就行 ,若是,则收集起来

 vector<int> rightSideView(TreeNode* root) //返回为一维数组
{

        queue<TreeNode*> que;

        if (root != NULL) que.push(root);

        vector<int> result;//result为一个一维数组

        while (!que.empty()) 
       {

            int size = que.size();//size为每一层的节点个数

               while(size--) {

                TreeNode* node = que.front();

                que.pop();

                if (i == size ) result.push_back(node->val); // 将每一层的最后元素放入result数组中

                if (node->left) que.push(node->left);

                if (node->right) que.push(node->right);
            }
        }
        return result;
    }

n叉树的层序遍历与二叉树的层序遍历差不多,只是在找子孩子结点时有所不同

二叉树

结构体定义时每一个节点设置两个指针(left  right)

  if (node->left) que.push(node->left);

  if (node->right) que.push(node->right);

n叉树

结构体定义时每一个节点设置多个指针(此时可以用数组来表示)

struct TreeNode {

    int val;

    TreeNode *children[100];

    
    
};

       for (int i = 0; i < node->children.size(); i++) { // 将节点孩子加入队列

                    if (node->children[i]) que.push(node->children[i]);

                }

求最大深度也可以用层序遍历  在求每一层结点个数(size)后面加一个depth++;

求最小深度时看的是当一层层遍历时,遇到的第一个叶节点(左右孩子都为空时)的层数就是最小深度

 int minDepth(TreeNode* root) //看返回值
{

        if (root == NULL) return 0;

        int depth = 0;

        queue<TreeNode*> que;

        que.push(root);

        while(!que.empty()) {

            int size = que.size();

            depth++; // 记录最小深度

            for (int i = 0; i < size; i++) {

                TreeNode* node = que.front();

                que.pop();

                if (node->left) que.push(node->left);

                if (node->right) que.push(node->right);

                if (!node->left && !node->right) { // 当左右孩子都为空的时候,说明是最低点的一层了,退出
                    return depth;//此时为最小深度
                }
            }
        }
        return depth;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值