数据结构——二叉树习题(一)

1.构造二叉树

#pragma once
 
/* Binary Tree */
//二叉树

#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include "Stack.h"

typedef int TDataType;

typedef struct BTreeNode {
	TDataType	data;
	struct BTreeNode *left;
	struct BTreeNode *right;
}	BTreeNode;


BTreeNode * CreateNode(int data)
{
	BTreeNode *node = (BTreeNode *)malloc(sizeof(BTreeNode));
	node->data = data;
	node->left = node->right = NULL;

	return node;
}




BTreeNode* CreateTree(int preOrder[], int size, int* useSize)
{
	int rootValue = preOrder[0];
	int leftUse;
	int rightUse; 
	BTreeNode* root = CreateNode(rootValue);
	 if(size<=0)
	 {
		 *useSize = 0;
		 return NULL;

	 }

	 if(rootValue==-1)
	 {
		 *useSize = 1;
		 return NULL;
	 }

	 root->left = CreateTree(preOrder+1, size-1, &leftUse);
	 root->right = CreateTree(preOrder+1+leftUse, size-1-leftUse, &rightUse);
	 *useSize = 1+leftUse+rightUse;
	 return root;
}

2.递归写法 


//遍历/前序/中序/后序
void PreOrder(BTreeNode* root)
{
	if(root ==NULL)
	{
		return ;
	}

	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);

}

void InOrder(BTreeNode* root)
{
	if(root == NULL)
	{
		return ;
	}

	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

void PostOrder(BTreeNode* root)
{
	if(root ==NULL)
	{
		return ;

	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}

 

3. 非递归写法

栈内数据的含义:

前序: 根,左子树都遍历过了

中序:左子树遍历过了

后序:左子树遍历过了

4. 非递归写法中如何判断右子树被遍历过了?

<1>右子树为空

<2>利用last记录

 

//非递归
//前序(右子树没有被遍历过)
void PreOrderLoop(BTreeNode* root)
{
	Stack stack;
	
	BTreeNode* cur;
	BTreeNode* top;
    StackInit(&stack);
	cur = root;
	while (cur!=NULL||!StackEmpty(&stack))
	{
		while(cur!=NULL)
		{
			printf("%d ", cur->data);
			
			StackPush(&stack, cur);
            cur = cur->left;
		}

		top = StackTop(&stack);
		StackPop(&stack);

		cur = top->right;
	}
	
}

//中序(右子树和根没有被遍历过)
void InOrderLoop(BTreeNode* root)
{
  Stack stack; 
  BTreeNode* cur;
  BTreeNode* top;
  StackInit(&stack);
  cur = root;
  while(cur != NULL||!StackEmpty(&stack))
  {
     while(cur!= NULL)
	 {
		 StackPush(&stack, cur);
		 cur = cur->left;
	 }
	 //此时左子树已经遍历完了
     
	 top = StackTop(&stack);
	 StackPop(&stack);
	 printf("%d ", top->data);

	 cur = top->right;


  }
}


//后序
void PostOrderLoop(BTreeNode * root)
{
	Stack stack;
	BTreeNode* cur;
	BTreeNode* top;
	BTreeNode* last = NULL;
	
	StackInit(&stack);
    cur = root;
	while(cur!= NULL|| !StackEmpty(&stack))
	{
		while(cur!=NULL)
		{
			StackPush(&stack, cur);
			cur = cur->left;
		}
		//左子树已经遍历完

		top = StackTop(&stack);

		if(top->right==NULL||top->right==last)
		{
			printf("%d ", top->data);
			StackPop(&stack);
		    last = top;
		}
		else
		{

			cur = top->right;
		}
	}
}

 5.后序遍历的作用:

<1> 保存了从根到到当前结点的路径(栈中)

<2>求高度(最长的路径)

<3>求镜像

二叉树的性质

//求结点个数
//1.用后序遍历解决
int count = 0;
void GetSize1(BTreeNode* root)
{
    if(root==NULL)
	{
		return ;
	}
	GetSize1(root->left);
	GetSize1(root->right);
	count++;
}
//子问题
int GetSize2(BTreeNode* root)
{
	int left = 0;
	int right = 0;
	if(root==NULL)
	{
		return 0;
	}
	 left = GetSize2(root->left);
	 right = GetSize2(root->right);
	return left+right+1;
}

int LeafSize(BTreeNode* root)
{
	int left = 0;
	int right = 0;
	if(root==NULL)
	{
		return 0;
	}
	if(root->left==NULL&&root->right==NULL)
	{
		return 1;
	}
	left = LeafSize(root->left);
	right = LeafSize(root->right);

    return left+right;

}

int LeafSizeK(BTreeNode* root,int k)
{
	int left = 0;
	int right = 0;
	assert(k>=1);
	//空树
	if(root==NULL)
	{
		return 0;
	}
	if(k==1)
	{
		return 1;
	}

	left = LeafSizeK(root->left, k-1);
	right = LeafSizeK(root->right, k-1);
	return left+right;

}

//求深度
#define MAX(a,b) ((a)>(b)?(a):(b))
int GetHight(BTreeNode* root)
{
	int left = 0;
	int right = 0;
	if(root==NULL)
	{
		return 0;
	}

	left = GetHight(root->left);
	right = GetHight(root->right);
	return (MAX(left,right)+1);
	
}

//找数据,前提是data不能重复
BTreeNode* Find(BTreeNode* root, TDataType data)
{
	BTreeNode* result = NULL;
	if(root==NULL)
	{
		return NULL;
	}
	if(root->data==data)
	{
		return root;
	}
	result = Find(root->left, data);
	if(result!=NULL)
	{
       return result;
	}
	
	result = Find(root->right, data);
	if(result!=NULL)
	{
		return result;
	}
	
	else
	{
		return NULL;
	}

}

 

测试用例  

void Test()
{
	int preOrder[] = { 1, 2, 3, -1, 4, 5, -1, -1, -1, 6, -1, -1, 7, 8, -1, -1, 9, -1, 10  };
	int size = sizeof(preOrder) / sizeof(int);
	int usedSize;
	BTreeNode* r = NULL;

	BTreeNode *root = CreateTree(preOrder, size, &usedSize);
	GetSize1(root);printf("%d\n", count);
	printf("结点个数:%d\n", GetSize2(root));
	printf("叶子结个数:%d\n", LeafSize(root));
	printf("第三层的结点个数:%d\n", LeafSizeK(root,3));
	printf("深度:%d\n", GetHight(root));
	r = Find(root, 3);

	PreOrderLoop(root); printf("\n");
	InOrderLoop(root);printf("\n");
	PostOrderLoop(root); printf("\n");

	printf("成功\n");
}

  


 

(1)非递归定义 树(tree)是由n(n≥0)个结点组成的有限集合。n=0的树称为空树;n>0的树T: ① 有且仅有一个结点n0,它没有前驱结点,只有后继结点。n0称作树的(root)结点。 ② 除结点外n0 , 其余的每一个结点都有且仅有一个直接前驱结点;有零个或多个直接后继结点。 (2)递归定义 一颗大树分成几个大的分枝,每个大分枝再分成几个小分枝,小分枝再分成更小的分枝,… ,每个分枝也都是一颗树,由此我们可以给出树的递归定义。 树(tree)是由n(n≥0)个结点组成的有限集合。n=0的树称为空树;n>0的树T: ① 有且仅有一个结点n0,它没有前驱结点,只有后继结点。n0称作树的(root)结点。 ② 除结点之外的其他结点分为m(m≥0)个互不相交的集合T0,T1,…,Tm-1,其中每个集合Ti(0≤i<m)本身又是一棵树,称为子树(subtree)。 2、掌握树的各种术语: (1) 父母、孩子与兄弟结点 (2) 度 (3) 结点层次、树的高度 (4) 边、路径 (5) 无序树、有序树 (6) 森林 3、二叉树的定义 二叉树(binary tree)是由n(n≥0)个结点组成的有限集合,此集合或者为空,或者由一个结点加上两棵分别称为子树的,互不相交的二叉树组成。 二叉树可以为空集,因此可以有空的子树或者子树,亦或者子树皆为空。 4、掌握二叉树的五个性质 5、二叉树的二叉链表存储。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值