链式二叉树的基本操作和基本OJ题(c语言)

@[TOC](链式二叉树的基本操作)

@[TOC](链式二叉树的遍历)

@[TOC](链式二叉树形状的判断)

@[TOC](链式二叉树的相关计算)

@[TOC](常见的基本OJ题)

@[TOC](单值二叉树(OJ题+源码+简单叙述核心思想))

@[TOC](对称二叉树(OJ题+源码+简单叙述核心思想))

@[TOC](另一颗树的子树(OJ题+源码+简单叙述核心思想))

声明展示:

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>;
#include <windows.h>
#include <windows.h>
#include <time.h>
#include <assert.h>
#include<stdbool.h>

//heap链表实现

typedef char NodeDataType;

typedef struct Node
{
	NodeDataType val;
	Node* leftchild;
	Node* rightchild;
};

//创建一个结点
Node* BuyNode(NodeDataType x);
//二叉树前序遍历
void PreOrder(Node* root);
//二叉树中序遍历
void InOrder(Node* root);
//二叉树后序遍历
void PostOrder(Node* root);
//计算非特殊二叉树的结点数
int CountTreeSize(Node* root);
//计算叶子结点的个数
int CountLeavesSize(Node* root);
//计算二叉树第k层结点的个数
int CountLeavesKSize(Node* root, int k);
//计算二叉树的深度(规定一个结点的树深度为1)
int CountTreeDpeth(Node* root);
//二叉树查找值为x的结点
Node* FindTree(Node* root,NodeDataType x);
//二叉树销毁
void TreeDestory(Node* root);
//层序遍历二叉树  //空结点则不打印
void LayerPrintTree(Node* root);
//判断是否为完全二叉树	
void IsFullBinaryTree(Node* root);




//因为层序遍历二叉树 以及 判断是否为完全二叉树 需要利用到队列,故以下为队列的代码


typedef Node* QDataType ;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QueueNode;


typedef struct Queue  //队列头节点
{
	QueueNode* head;  //一级结构体指针传参,不可改变此指针指向的地方,但可以改变指针指向地方上的内容
	QueueNode* tail;
}Queue;


void QueueInit(Queue* pq);//初始化队列
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
int QueueSize(Queue* pq);
bool QueueEmpty(Queue* pq);

# 链式二叉树的基本操作

链式二叉树的创建

二叉树的内容因为具有不规则性,所以链式二叉的创建不像 链表 堆 队列 或者 用数组存储 特地去写增删查改等操作的函数接口。创建二叉树直接手动链接各结点。

Node* BuyNode(NodeDataType x)
{
	Node* tem = (Node*)malloc(sizeof(Node));
	if (tem == NULL)
	{
		printf("malloc faild");
		exit(-1);
	}
	tem->val = x; 
	return tem;
}


int main()
{	
	//手搓一个非特殊二叉树
	Node* A = BuyNode('A');
	Node* B = BuyNode('B');
	Node* C = BuyNode('C');
	Node* D = BuyNode('D');
	Node* E = BuyNode('E');	
	Node* F = BuyNode('F');
	A->leftchild = B;//b
	B->leftchild = D;//D 
	D->rightchild = NULL;
	D->leftchild = NULL; 
	B->rightchild = NULL;
	A->rightchild = C;//c
	C->leftchild = E;//E
	E->leftchild = NULL;
	E->rightchild = NULL;
	C->rightchild = F;//F
	F->leftchild = NULL;
	F->rightchild = NULL;
	//之后验证函数是否可以在次处验证即可
	return 0;
}

链式二叉树查找指定值(val)的的结点。

链式二叉树的销毁

Node* FindTree(Node* root,NodeDataType x )
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->val == x)
	{
		return root; 
	}
	Node* tem1 =  FindTree(root->leftchild,x);
	Node* tem2 = FindTree(root->rightchild, x);
	if (tem1 != NULL)
	{
		return tem1;
	}
	if (tem2 != NULL)
	{
		return tem2;
	}
	return NULL; 
}


void TreeDestory(Node* root)
{
	if (root == NULL)
	{
		return;
	}
	TreeDestory(root->leftchild);
	TreeDestory(root->rightchild);
	free(root);
}

# 二叉树的遍历

前序遍历:按 A BC (根左右) 的顺序输出。

中序遍历:按B|A|C (左根右) 的顺序输出。

后序遍历:按BC A (左右根) 的顺序输出。

层序遍历:按照视觉视觉上从上往下,从左向右遍历。

大佬的详解

代码实现:

/前序;根 左子树,右子树
void PreOrder(Node* root) 
{
	if (root == NULL)
	{
		printf(" NULL ");
		return;
	}
	printf(" %c ", root->val);
	PreOrder(root->leftchild);
	PreOrder(root->rightchild);
}


//中序: 左子树 根 右子树 
void InOrder(Node* root)
{
	if (root == NULL)
	{
		printf(" NULL ");
		return;
	}
	InOrder(root->leftchild);
	printf(" %c ", root->val );
	InOrder(root->rightchild);
}


//后序: 左子树 右子树 根 
void PostOrder(Node* root)
{
	if (root == NULL)
	{
		printf(" NULL");
		return;
	}
	PostOrder(root->leftchild);
	PostOrder(root->rightchild);
	printf(" %c ", root->val);
}


//层序遍历
void LayerPrintTree(Node* root)
{
	if (root == NULL)
	{
		return;
	}
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (QueueEmpty(&q) != 1 )
	{
		Node* tem = QueueFront(&q);
		printf("%c", tem->val);
		QueuePop(&q);
		if (tem->leftchild != NULL)
		{
			QueuePush(&q, tem->leftchild);
		}
		if (tem->rightchild != NULL)
		{
			QueuePush(&q, tem->rightchild);
		}
	}
}

# 链式二叉树形状的判断 

判断是否为完全二叉树。 

完全二叉树的定义:完全二叉树是由满二叉树而引出来的,若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数(即1~h-1层为一个满二叉树),第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

完全二叉树:

 非完全二叉树:

#链式二叉树相关计算:

结点数计算    :方法:递归   思想:每经过一个不为空的结点返回值 +1

叶子节点数计算  : 方法:递归  思想:在遍历思想的基础上,判段结点左右孩子均为空时返回值+1

第k层节点计算 :方法:递归  //利用k到达k-1层,k-1的孩子不为空则+1

计算树的深度(规定只有一个结点的树深度为1) :方法:递归  思想:每往下一层便深度+1,

最终谁深度大返回谁。




int CountTreeSize(Node* root) //计算结点个数
{
	if (root == NULL)
	{
		return 0;
	}	
	return CountTreeSize(root->rightchild) + CountTreeSize(root->leftchild) + 1;
}


//计算叶子结点个数
int CountLeavesSize(Node* root)   
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->leftchild == NULL && root->rightchild == NULL)
	{
		return 1;
	}
	return CountLeavesSize(root->leftchild) + CountLeavesSize(root->rightchild);
}


//计算二叉树第k层结点的个数
int CountLeavesKSize(Node* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1 )
	{
		return 1;
	}
	if (k > 1)
	{
		return CountLeavesKSize(root->leftchild, k - 1) + CountLeavesKSize(root->rightchild,k - 1);
	}
	return NULL;
}

//计算深度

int CountTreeDpeth(Node* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->leftchild == NULL && root->rightchild == NULL)
	{
		return 1;
	}
	int tem1 = CountTreeDpeth(root->leftchild);
	int tem2 = CountTreeDpeth(root->rightchild);

	return tem1 > tem2 ? tem1 + 1 : tem2 + 1 ;

}

# 常见OJ题 

# 单值二叉树

题目要求:

核心思想:在递归的基础下,分别比较每个根与左孩子和有孩子的值

源码:

bool isUnivalTree(struct TreeNode* root){
    if(root == NULL)
    {
        return true;
    }

    //若左子树中的值不等于根结点的值,则返回false
    //注:这里一定要注意限制左右孩子的节点,因为左右孩子有可能为NULL
    if(root->left && root->val != root->left->val)
    {
        return false;
    }

    //如果右子树中的值不等于根结点的值,则返回true
    if(root->right && root->val != root->right->val)
    {
        return false;
    }

    //如果都相等的话,则说明是单值二叉树
    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

# 对称二叉树

题目要求:

核心思想:在递归的基础上,将“左孩子的右孩子“  和”右孩子的左孩子进行比较“ 

源码:

bool isMirrorTree(struct TreeNode *p, struct TreeNode *q)
{
    if ((p == NULL) && (q == NULL)) {
        return true;
    } else if ((p == NULL) || (q == NULL)) {
        return false;
    }
    if (p->val != q->val) {
        return false;
    }
    return (isMirrorTree(p->left, q->right)) && (isMirrorTree(p->right, q->left));
}
 
bool isSymmetric(struct TreeNode* root){
    return isMirrorTree(root, root);
}

# 另一棵树的子树

题目要求:

核心思想:对root进行遍历比较,当某个结点的值和subroot的第一个值相同时,开始进行判定是否是相同的树,所以要先写一个判别两个数是否相同的树

源码:

bool issame(struct TreeNode* root, struct TreeNode* subRoot)
{
    if((root == NULL) &&(subRoot == NULL))
    {
        return true;
    }
    // 一个为空一个不为空,说明不相同,返回false
    if((root ==NULL) || (subRoot == NULL) )
    {
        return false;
    }
    if(root->val != subRoot->val)
    {
        return false;
    }
    return (issame(root->left,subRoot->left)) && (issame(root->right,subRoot->right));
}



//判断是否对称
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    if(root == NULL && subRoot == NULL)
    {
        return true;
    }
    if(root == NULL || subRoot == NULL)
    {
        return false ;
    }
    
    if(issame(root,subRoot))
    {
        return true ;
    }

    return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}

//本人为初学者,不足之处恳请指正。

猜你喜欢

转载自blog.csdn.net/WSK1454360679/article/details/129628166
今日推荐