树形结构及二叉树

基本概念

结点:结点包括一个数据元素及若干指向其他子树的分支(指针(索引))。

结点的度:结点所拥有子树的个数为该结点的度。

叶子结点(终端结点):度为0的结点。

分支结点(非终端结点):度不为0的结点。一般树中除了叶子结点外都是分支结点。

祖先结点:从根结点到该结点所经分支上的所有结点。

子孙结点:以某结点为根结点的子树中所有结点。

双亲结点:树中某结点有孩子结点,则这个结点称为他孩子结点的双亲结点,双亲结点也称为前驱结点。

孩子结点:树中一个结点的子树的根结点,孩子结点也称后继结点。

兄弟结点:具有相同双亲结点的结点。

树的度:树中所有结点的度的最大值称为该树的度。

结点的层次:从根结点到树中某结点所经路径上的分支数为该结点的层次。根结点的层次为1,其他结点层次是双亲层次加1.

树的深度:树中所有结点的层次的最大值。

有序树:树中结点的各棵树T0,T1,T2.....是有序的,即为有序树.

无序树:树中节点的各棵子树之间的次序不重要,可以相互交换位置。

森林:树M棵树的集合(M>=0).在自然界中树和森林是两个不同的概念,但是在数据结构中,它们之间的差别很小。删去          一棵非空树的根结点,树就会变成森林;反之,若增加一个根结点,让森林中每一棵树的根结点都变成他 子女,森林就变 成一棵树

二叉树的特点

        1.每个结点最多有两棵子树,即二叉树不存在度大于2的结点。

        2.二叉树的子树有左右之分,其子树的次序不能颠倒。

满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子结点都在同一层上。如下图所示。

             

完全二叉树:如果一棵树具有N个结点的二叉树的结构与满二叉树的前N个结点的结构相同,称为完全二叉树。如上图所示。

二叉树的性质

    1.若规定根结点的层数为1,则一颗非空二叉树的第i层上最多有2^(i-1) ( i>0) 个结点。

    2.若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点树是(2^k)-1 ( k>=0)。

    3.具有n个结点的完全二叉树的深度k为log2(n+1)向上取整。

    4.对任何一棵二叉树,如果其叶子结点个数为n0,度为2的非叶子节点个数为n2,则有n0=n2+1;

二叉树的基本操作

    二叉树的遍历:前序(根左右)

                            中序(左根右)

                            后序(左右根)

                            层序(从上到下,从左到右)

                    

二叉树的层序遍历算法

        a. 初始化一个队列。

        b. 将根结点的指针入队列。

        c. 当队列非空时,循环执行以下步骤:

            >  取队头元素并访问。

            >  若该结点的左子树非空,将该结点的左子树入队列。

            >  若该结点的右子树非空,将该结点的右子树入队列。

        d.结束

二叉树代码:

Tree.h:

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<windows.h>
#include"Queue.h"
#include"stack.h"

typedef char DataType;

typedef struct TreeNode{
	struct TreeNode *pLeft;
	struct TreeNode *pRight;
	DataType data;
}TreeNode;

TreeNode* CreateRoot(DataType data)
{
	TreeNode *pRoot = (TreeNode*)malloc(sizeof(TreeNode));
	assert(pRoot);
	pRoot->data = data;
	pRoot->pLeft = NULL;
	pRoot->pRight = NULL;
	return pRoot;
}
//例如:前序是:ABD###CE##F还原二叉树
//还原二叉树
TreeNode* CreateTree(DataType preOrder[], int size, int *pIndex)
{
	if (*pIndex >= size){
		return NULL;
	}
	if (preOrder[*pIndex] == '#'){
		*pIndex += 1;
		return NULL;
	} 
	TreeNode* pRoot = CreateRoot(preOrder[*pIndex]);
	(*pIndex)++;//用了1个字符;
	pRoot->pLeft = CreateTree(preOrder, size, pIndex);
	pRoot->pRight = CreateTree(preOrder, size, pIndex);
	return pRoot;
}
//前序遍历(递归)
void PreOrder(TreeNode* pRoot)
{
	if (pRoot == NULL){
		return;
	}
	printf("%c ", pRoot->data);
	PreOrder(pRoot->pLeft);
	PreOrder(pRoot->pRight);
}

//前序(非递归)
void PreOrderLoop(TreeNode *pRoot)
{
	TreeNode *pCur = pRoot;
	TreeNode *pTop = NULL;
	Stack stack;
	StackInit(&stack);
	while (pCur != NULL || !StackIsEmpty(&stack)){
		while (pCur != NULL){
			printf("%c", pCur->data);
			StackPush(&stack, pCur);
			pCur = pCur->pLeft;
		}
		//整棵树的左边都遍历
		//没有遍历的还剩栈里节点的右子树
		pTop = StackTop(&stack);
		StackPop(&stack);

		//遍历Top的右子树,用子问题的办法
		pCur = pTop->pRight;
	}
}
//中序遍历(递归)
void InOrder(TreeNode* pRoot)
{
	if (pRoot == NULL){
		return;
	}
	InOrder(pRoot->pLeft);
	printf("%c ", pRoot->data);
	InOrder(pRoot->pRight);
}

//中序(非递归)
void InOrderLoop(TreeNode *pRoot)
{
	TreeNode *pCur = pRoot;
	TreeNode *pTop = NULL;
	Stack stack;
	StackInit(&stack);
	while (pCur != NULL ||! StackIsEmpty(&stack)){
		while (pCur != NULL){
			StackPush(&stack, pCur);
			pCur = pCur->pLeft;
		}
		pTop = StackTop(&stack);
		StackPop(&stack);
		printf("%c", pTop->data);

		//遍历Top的右子树,用子问题的办法
		pCur = pTop->pRight;
	}
}
//后序遍历(递归)
void PostOrder(TreeNode* pRoot)
{
	if (pRoot == NULL){
		return;
	}
	PostOrder(pRoot->pLeft);
	PostOrder(pRoot->pRight);
	printf("%c ", pRoot->data);
}

//后序(非递归)
void PostOrderLoop(TreeNode *pRoot)
{
	TreeNode *pCur = pRoot;
	TreeNode *pTop = NULL;
	TreeNode *pLast = NULL;
	Stack stack;
	StackInit(&stack);
	while (pCur != NULL || !StackIsEmpty(&stack)){
		while (pCur != NULL){
			StackPush(&stack, pCur);
			pCur = pCur->pLeft;
		}
		//没有遍历的还剩栈里节点的右子树和根
		pTop = StackTop(&stack);
		if ((pTop->pRight == NULL) || (pTop->pRight = pLast)){
			//pTop无右子树,所以可以直接处理pTop的根节点
			//pTop有右子树,但是pTop的右子树已经遍历完了,所以可以处理pTop的根
			StackPop(&stack);
			printf("%c", pTop->data);
			pLast = pTop;
			continue;
		}
	}
}

//求二叉树节点总数(左节点数+右节点数+1(最后一个根节点))
int GetSize(TreeNode* pRoot)
{
	if (pRoot == NULL){
		return 0;
	}
	return GetSize(pRoot->pLeft) + GetSize(pRoot->pRight) + 1;
}
//此处也可以这样写(因为线程问题,所以不推荐)
//int count = 0;
//int GetSize(TreeNode* pRoot)
//{
//	if (pRoot == NULL){
//		return;
//	}
//	PreOrder(pRoot->pLeft);
//	PreOrder(pRoot->pRight);
//}

//求二叉树中叶子节点的个数
int GetLeafSize(TreeNode* pRoot)
{
	if (pRoot == NULL){
		return 0;
	}
	if (pRoot->pLeft == NULL && pRoot->pRight == NULL){
	//pRoot是叶子节点
		return 1;
	}
	return GetSize(pRoot->pLeft) + GetSize(pRoot->pRight);
}

//求二叉树的第k层节点个数(k:层数,先有左子树,后产生(k-1)层)
int GetkLevelSize(TreeNode* pRoot, int k)
{
	assert(k>= 1);
	if (pRoot == NULL){
		return 0;//空树
	}
	if (k== 1){
		return 1;
	}
	return GetkLevelSize(pRoot->pLeft, k - 1) + GetkLevelSize(pRoot->pRight, k - 1);
}

//判断一个节点是否在二叉树中。找到返回节点地址,否则,返回NULL;
TreeNode*Find(TreeNode* pRoot, DataType data)
{
	if (pRoot == NULL){
		return  NULL;
	}
	if (pRoot->data == data){
		return pRoot;
	}
	TreeNode* pFound = Find(pRoot->pLeft, data);//定义一个指针,保存找到的地址
	if (pFound != NULL){
		return pFound;
	}
	return Find(pRoot->pRight, data);//可能找到,可能找不到
}

//求二叉树的高度(深度)
#define MAX(x,y)  ((x)>(y) ? (x) :(y))
int GetHeight(TreeNode *pRoot)
{
	if (pRoot == NULL){
		return 0;
	}
	//可要可不要
	if (pRoot->pLeft == NULL && pRoot->pRight == NULL){
		return 1;
	}
	int left = GetHeight(pRoot->pLeft);
	int right = GetHeight(pRoot->pRight);
	return MAX(left, right) + 1;
}

//层序遍历二叉树
void LevelOrder(TreeNode *pRoot)
{
	if (pRoot == NULL){
		printf("\n");
		return;
	}
	Queue queue;
	TreeNode *pFront;
	QueueInit(&queue);
	QueuePush(&queue, pRoot);

	while (!QueueIsEmpty(&queue)){
		pFront = QueueFront(&queue);
		QueuePop(&queue);

		printf("%c", pFront->data);
		if (pFront->pLeft != NULL){
			QueuePush(&queue, pFront->pLeft);
		}
		if (pFront->pRight != NULL){
			QueuePush(&queue, pFront->pRight);
		}
	}
	printf("\n");
}

//判断二叉树是否是完全二叉树。是:返回1;不是:返回0
int IsComplete(TreeNode *pRoot)
{	
	//空树也是完全二叉树	
	if (pRoot == NULL){
		return 1;
	}

	Queue queue;
	TreeNode *pFront;
	QueueInit(&queue);
	QueuePush(&queue, pRoot);

	while (!QueueIsEmpty(&queue)){
		pFront = QueueFront(&queue);
		QueuePop(&queue);

		if (pFront == NULL){
			break;
		}
		QueuePush(&queue, pFront->pLeft);
		QueuePush(&queue, pFront->pRight);
	}
	while (!QueueIsEmpty(&queue)){
		pFront = QueueFront(&queue);
		QueuePop(&queue);

		if (pFront != NULL){
			return 0;
		}
	}
	return 1;
}

void Test()
{
	DataType *preOrder = "ABD###CE##F";
	//DataType *preOrder = "AB##C";
	int Index = 0;
	TreeNode* pRoot = CreateTree(preOrder, strlen(preOrder), &Index);

	PreOrder(pRoot);  printf("前序:\n ");
	InOrder(pRoot);   printf("中序:\n ");
	PostOrder(pRoot); printf("后序:\n ");

	printf("叶子节点数:%d\n", GetLeafSize(pRoot));

	int k = 2;
	printf("第 %d 层节点数: %d\n", k, GetkLevelSize(pRoot,k));

	printf("树的高度为:%d\n", GetHeight(pRoot));

	LevelOrder(pRoot);//层序遍历

	printf("%d\n", IsComplete(pRoot));
}

stack.h:

#pragma once

#include<stdlib.h>
#include<assert.h>
#include<string.h>

typedef struct Position{
	int x;
	int y;
}Position;

typedef void * SDataType;

#define MAX_SIZE (100)

typedef struct Stack{
	SDataType array[MAX_SIZE];
	int top;//含义和顺序表的size含义一样(1.表示有效数据个数 2.top下标表示当前可用位置)
}Stack;

//栈的初始化
void StackInit(Stack *pS)
{
	assert(pS != NULL);
	pS->top = 0;
}

//入栈
void StackPush(Stack *pS, SDataType data)
{
	assert(pS != NULL);
	assert(pS->top < MAX_SIZE);

	pS->array[pS->top++] = data;
}

//出栈
void StackPop(Stack *pS)
{
	assert(pS != NULL);
	assert(pS->top>0);

	pS->top--;
}

SDataType StackTop(Stack *pS)
{
	assert(pS != NULL);
	assert(pS->top > 0);

	return pS->array[pS->top - 1];
}

//判断是否为空:1.空  0.非空
int StackIsEmpty(Stack *pS)
{
	return pS->top == 0 ? 1 : 0;
}

//求栈的大小
int StackSize(Stack *pS)
{
	return pS->top;
}

//栈的复制
void StackCopy(Stack *pDest, Stack *pSrc)
{
	pDest->top = pSrc->top;
	memcpy(pDest->array, pSrc->array, sizeof(SDataType)*pSrc->top);
}

void TestStack()
{
	Stack stack;
	StackInit(&stack);
}

Queue.h:

#pragma once

#include<stdio.h>
#include<assert.h>
#include<string.h>

typedef void *QDataType;

typedef struct QNode{
	QDataType data;
	struct QNode *pNext;
}QNode;

typedef struct Queue{
	QNode *pFront;
	QNode *pRear;
	int size;
}Queue;

//队列初始化
void QueueInit(Queue *pQ)
{
	assert(pQ != NULL);
	pQ->pFront = pQ->pRear = NULL;
	pQ->size = 0;
}

//入队列
void	QueuePush(Queue *pQ, QDataType data)
{
	assert(pQ != NULL);

	pQ->size++;
	QNode *pNewNode = (QNode *)malloc(sizeof(QNode));
	assert(pNewNode);
	pNewNode->data = data;
	pNewNode->pNext = NULL;
	if (pQ->pRear == NULL){
		pQ->pFront = pQ->pRear = pNewNode;
		return;
	}
	//通常情况
	pQ->pRear->pNext = pNewNode;
	pQ->pRear = pNewNode;
}

//出队列
void QueuePop(Queue *pQ)
{
	assert(pQ != NULL);
	assert(pQ->size > 0);
	pQ->size--;

	//通常情况
	QNode *pOldFront = pQ->pFront;
	pQ->pFront = pQ->pFront->pNext;
	free(pOldFront);

	if (pQ->pFront == NULL){
		pQ->pRear = NULL;
	}
}

//更新队首
QDataType QueueFront(Queue *pQ){
	assert(pQ != NULL);
	assert(pQ != NULL);
	return pQ->pFront->data;
}

//判断队列是否为空: 1 空  ; 0 不空
int QueueIsEmpty(Queue *pQ){
	return pQ->size == 0 ? 1 : 0;
}

int QueueSize(Queue *pQ){
	return pQ->size;
}

结果显示:

猜你喜欢

转载自blog.csdn.net/ZY_20181010/article/details/81004203