二叉树的理解和基本操作

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

   (2.) 二叉树的特点:
              1.每个节点最多有两棵子树(也就是说二叉树中不存在度大于2的节点)

             2.二叉树的子树没有左右之分,其次序不能任意颠倒
   (3.) 二叉树的基本形态:
                 1.空二叉树
               2.只有根结点的二叉树
               3.右子树为空的二叉树
               4.左右子树均不为空的二叉树
               5.左子树为空的二叉树

      (4.)满二叉树和完全二叉树
           1.满二叉树:在一棵二叉树中,如果所有分支节点都存在左子树和右子树,并且所有叶子节点都在同一曾上(一棵深度为K且有个节点的二叉树)
              2.完全二叉树:如果一棵具有N个节点的二叉树的结构与满二叉树的前N个节点的结构相同,则为完全二叉树。

二.二叉树的性质
          1.在二叉树的第i层上至多有 个节点(i>=1
           2.深度为k的二叉树之多有 个节点(k>=1)
       3.对于任何一棵二叉树T,如果其终端节点为n(0),度为2的节点数为n(2),则
                  n(0) = n(2) + 1

           4.具有n个节点的完全二叉树的深度为
         5.对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序 对所有节点从0开始编号,则对于序号为i的结点有:  
            1.  若i>0,双亲序号:(i-1)/2;  i=0,i为根节点编号,无双亲结点
            2.  若2i+1<n,左孩子序号:2i+1,否则无左孩子 
            3.  若2i+2<n,右孩子序号:2i+2,否则无右孩子 
          6.有n个节点的树则有n+1个指针域  

三.二叉树的存储结构

    二叉树的存储结构有顺序存储结构和链式存储结构(和队列,栈相同)

          顺序存储结构:对于一棵完全二叉树所有结点按照层序自顶向下,同一层自左向右顺 序编号,就得到一个节点的顺序序列

                 优点:存储完全二叉树,简单省空间  
                 缺点:存储一般二叉树尤其单支树,存储空间利用不高 

              链式存储结构:
        
typedef int DataType;
struct BinTreeNode
{

	struct BinTreeNode* pLeft;         //当前节点的左孩子
	struct BinTreeNode* pRight;        //当前孩子的右孩子

	DataType data;                     //当前节点的值域

};

typedef int DataType;
struct BinTreeNode {
	struct BinTreeNode* _pParent; // 指向当前节点的双亲     
	struct BinTreeNode* _pLeft;   // 指向当前节点左孩子     
	struct BinTreeNode* _pRight;  // 指向当前节点右孩子    
	DataType _data;               // 当前节点值域 
}; 

四.二叉树的基本操作
     1.二叉树的遍历
  •  先序遍历:根结点--->左子树--->右子树
  •  中序遍历:左子树--->根结点--->右子树
  •  后续遍历:左子树--->右子树--->根结点
  •  层序遍历:按照二叉树的层序次序(即从根节点层到叶结点层),同一层中按先左 子树再右子树的次序遍历二叉树     

          因此:在所有未被访问结点的集合中,排列在已访问结点集合中最前 面结点的左子树的根节点将最先被访问,然后是该结点的右子树的根 节点。  
               层序遍历的方法:
                      1.初始化一个队列
                       2.将根结点的指针入队列
                       3.当队列非空时,循环执行以下操作:
                               1.取队头元素并访问
                               2.若该节点的左子树非空则左子树入队列
                               3.若该节点的右子树非空则右子树入队列
                       4.结束


  •  其他遍历方法:遍历左子树

            2.二叉树的基本操作
              1.创建二叉树

                2.前序遍历(递归和非递归)
               3.中序遍历

                4.后序遍历
                5.层序遍历

                6.其他遍历方法
                7.二叉树的镜像(递归)
                8.拷贝二叉树
                9.销毁二叉树
                10.二叉树的镜像(递归和非递归)(交换左右子树)
                11.求二叉树中结点的个数

                12.获取二叉树中叶子结点的个数
                13.求二叉树中K层结点的个数
                14.求二叉树的高度

 实现的代码:
 BinTreeNode.h
#pragma once
#include<stdio.h>
#include<Windows.h>
#include<assert.h>
#include<malloc.h>
#include<string.h>

#include"stack.h"
#include"queue.h"

typedef char DataType;
typedef struct BinTreeNode
{
	
	struct BinTreeNode* pLeft;    //指向当前节点的左孩子
	struct BinTreeNode* pRight;   //指向当前节点的有孩子
	DataType data;

}BinTreeNode, *PBinTreeNode;

//创建二叉树(利用前序遍历,递归的方法)
void _CreateBinTreeNode(PBinTreeNode* pRoot,int* array,int size,int index,DataType Invalid);

//创建二叉树结点
PBinTreeNode BuyBinTreeNode(DataType data);

//遍历二叉树(前序遍历)
void PreOrder(PBinTreeNode pRoot);

//前序遍历(非递归)
void PreOrderNor(PBinTreeNode pRoot);

//后序遍历(递归)
void PostOrder(PBinTreeNode pRoot);

//中序遍历(递归)
void InOrder(PBinTreeNode pRoot);

//拷贝二叉树
PBinTreeNode CopyBinTree(PBinTreeNode pRoot);

//销毁二叉树
void DestroyBinTree(PBinTreeNode pRoot);

//层序遍历
void LevelOrder(PBinTreeNode pRoot);

//前序遍历非递归
void OtherOrder(PBinTreeNode pRoot);

//二叉树的镜像(递归)
void MirrorBinTree(PBinTreeNode pRoot);

//二叉树的镜像(循环)
void MirrorBinTreeNor(PBinTreeNode pRoot);

// 求二叉树中结点的个数 
int BinTreeSize(PBinTreeNode pRoot);

// 获取二叉树中叶子结点的个数 
int GetLeafCount(PBinTreeNode pRoot);

// 求二叉树中K层结点的个数 
int GetKLevelNode(PBinTreeNode pRoot, int K);

// 求二叉树的高度 
int Height(PBinTreeNode pRoot);

queue.h


#pragma once 
#include<stdio.h>
#include<Windows.h>
#include<assert.h>

typedef int DataType;
extern struct BinTreeNode;
typedef struct BinTreeNode* QDataType;

#define SIZE 10

typedef struct Queue
{
	DataType arry[SIZE];
	int front;
	int rear;

}Queue;


//初始化队列
void QueueInit(Queue* q);

// 入队列
void QueuePush(Queue* q, DataType data);

// 出队列
void QueuePop(Queue* q);

// 获取队列顶元素 
DataType QueueTop(Queue* q);

// 获取队列中元素个数 
int QueueSize(Queue* q);

// 检测队列是否为空 
int QueueEmpty(Queue* q);

queue.c

//初始化队列
void QueueInit(Queue*q)
{
	
	
	//初始化队列只需让队头指针和队尾指针都指向0
	q->front = q->rear = 0;
	return;

}


// 入队列
void QueuePush(Queue* q, DataType data)
{
	assert(q);
	if (SIZE == q->rear)
	{
		printf("栈溢出!!!");
			return;
	}
	else
	{
		q->rear++;

		q->arry[q->rear] = data;
		



	}

	return;
}

// 出队列
void QueuePop(Queue* q)
{
	if (q->front == q->rear )
	{
		printf("队列已空!!!");
		return;
	}
	else
	q->front++;


}

// 获取队列顶元素 
DataType QueueTop(Queue* q)
{
	if (q->front == q->rear)
	{
		printf("队列已空!!!");

		return 0;
	}

	return (q->arry[q->front]);

}

// 获取队列中元素个数 
int QueueSize(Queue* q)
{
	if (q->front == q->rear)
	{
		printf("队列已空!!!");

		return 0;
	}

	return (q->rear - q->front);

}

// 检测队列是否为空 
int QueueEmpty(Queue* q)
{
	if (q->front == q->rear)
	
		printf("队列已空!!!");

		return  0;


}

stack.h


#pragma once

#include<stdio.h>
#include<Windows.h>

typedef int DataType;
extern struct BinTreeNode;
typedef struct BinTreeNode* QDataType;
#define MAX_SIZE 100 

typedef struct Stack
{
	DataType _array[MAX_SIZE];
	int _top;
}Stack;

// 栈的初始化 
void StackInit(Stack* s);

// 入栈 
void StackPush(Stack* s, DataType data);

// 出栈 
void StackPop(Stack* s);

// 获取栈顶元素 
DataType StackTop(Stack* s);

// 获取栈中元素个数 
int StackSize(Stack* s);

// 检测栈是否为空 
int StackEmpty(Stack* s);

stack.c


//初始化栈
void StackInit(Stack* s)
{
	if (NULL == s)
	{
		return;
	}
	s->_top = (Stack*)malloc(sizeof(Stack));
	s->_top = 0;
}

//入栈
void StackPush(Stack* s, DataType data)
{
	if (NULL == s)
	{
		printf("栈已空!!!");
		return;
	}

	s->_array[s->_top] = data;
	++s->_top;

}

//出栈
void StackPop(Stack* s)
{
	if (NULL == s)
	{
		printf("栈已空!!!");
		return;
	}
	if (s->_top == 0)
	{
		printf("栈已空!!!");
		return;
	}
	s->_top--;


}

//打印栈顶元素
DataType StackTop(Stack* s)
{
	if (NULL == s)
	{
		printf("栈已空!!!");
		return 0;
	}
	return s->_array[s->_top - 1];

}

//打印栈的元素个数
int StackSize(Stack* s)
{
	if (NULL == s)
	{
		printf("栈已空!!!");
		return 0;
	}
	return s->_top;
}

//判断元素是否为空
int StackEmpty(Stack* s)
{
	if (NULL == s)
	{
		printf("栈已空!!!");
		return 0;
	}
	if (s->_top == 0)
	{
		printf("栈已空!!!");
		return 0;
	}

	return 1;

}
BinTreeNode.c
#include"stack.h"
#include"queue.h"

//创建二叉树(利用前序遍历和递归思想)
void _CreateBinTreeNode(PBinTreeNode* pRoot , DataType* array, int size, int* index,DataType Invalid)
{
	   assert(pRoot);

	   if (index < size && array[*index] != Invalid)
	{
		//创建根节点
		*pRoot = BuyBinTreeNode(array[*index]);
		
		//索引向后走
		++(*index);

		//创建左子树
		_CreateBinTreeNode(&(*pRoot)->pLeft, array, size, index, Invalid);
		

		++(*index);
		//创建右子树
		_CreateBinTreeNode(&(*pRoot)->pRight, array, size, index, Invalid);
	}

}

void CreateBinTreeNode(PBinTreeNode* pRoot, DataType* array, int size,DataType Invalid)
{

	int index = 0;
	_CreateBinTreeNode(&pRoot, array, size, &index, Invalid);



}

//创建新节点
PBinTreeNode BuyBinTreeNode(DataType data)
{

	PBinTreeNode NewNode = (PBinTreeNode)malloc(sizeof(BinTreeNode));
	if (NULL == NewNode)
	{
		printf("申请失败!!!\n");
		return NULL;

	}

	NewNode->pLeft = NULL;
	NewNode->pRight = NULL;
	NewNode->data = data;
	return NewNode;
}


//遍历二叉树(递归的方法,前序遍历)
void PreOrder(PBinTreeNode pRoot)
{
	assert(pRoot);
	if (pRoot)
	{
		printf("%c-->", pRoot->data);   //先遍历根
		PreOrder(pRoot->pLeft);         //再遍历左子树
		PreOrder(pRoot->pRight);        //最后遍历右子树
	}

}

//拷贝二叉树
PBinTreeNode CopyBinTree(PBinTreeNode pRoot)
{
	assert(pRoot);
	PBinTreeNode NewRoot = NULL;
	if (pRoot)
	{
		NewRoot = BuyBinTreeNode(pRoot->data);
		if (pRoot->pLeft)
		{
			NewRoot->pLeft = BuyBinTreeNode(pRoot->pLeft);
		}
		if (pRoot->pRight)
		{

			NewRoot->pRight = BuyBinTreeNode(pRoot->pRight);
		}
	}

	return NewRoot;

}

//后序遍历
void PostOrder(PBinTreeNode pRoot)
{
	assert(pRoot);
	if (pRoot)
	{
		
		PreOrder(pRoot->pLeft);        //再遍历左子树
		PreOrder(pRoot->pRight);         //再遍历右子树
		printf("%c-->", pRoot->data);    //最后遍历根
	}

}

//中序遍历
void InOrder(PBinTreeNode pRoot)
{

	assert(pRoot);
	if (pRoot)
	{
		PreOrder(pRoot->pLeft);         //再遍历左子树
		printf("%c-->", pRoot->data);   //先遍历根
		PreOrder(pRoot->pRight);        //最后遍历右子树
	}


}

//销毁二叉树(利用后序遍历,递归方法)
void DestroyBinTree(PBinTreeNode* pRoot)
{
	assert(pRoot);
	if (pRoot)
	{
		DestroyBinTree(&(*pRoot)->pLeft);
		DestroyBinTree(&(*pRoot)->pRight);
		free(*pRoot);
		(*pRoot)->data = NULL;
	}
}


//层序遍历
void LevelOrder(PBinTreeNode pRoot)
{
	if (NULL == pRoot)
		return;
	PBinTreeNode pcur = NULL;
	Queue q;
	QueueInit(&q);
    QueuePush(&q,pRoot);
	while (!QueueEmpty(&q));
	{
	
		pcur = QueueTop(&q);
		printf("%c--->", pcur->data);
		//QueuePop(&q);
		if (pcur->pLeft)
			QueuePush(&q, pcur->pLeft);

		if (pcur->pRight)
			QueuePush(&q,pcur->pRight);
		QueuePop(&q);                     //先出队列和后出队列都行
	}

}


//前序遍历(非递归)
void PreOrderNor(PBinTreeNode pRoot)
{
	if (NULL == pRoot)
		return;
	Stack s;
	StackInit(&s);
	StackPush(&s, pRoot);       //先把头节点放入栈中  

	while (!StackEmpty(&q));
	{
		PBinTreeNode pcur = NULL;

		
		pcur = StackTop(&q);
		printf("%c--->", pcur->data);
		QueuePop(&q);          //必须先出栈


		//先将右子树进栈
		if (pcur->pRight)
			QueuePush(&q, pcur->pRight);

		//再将左子树进栈
		if (pcur->pLeft)
			QueuePush(&q, pcur->pLeft);
		
	}

}

//前序遍历非递归
void OtherOrder(PBinTreeNode pRoot)
{
	Stack s;
	StackInit(&s);
	PBinTreeNode pcur = NULL;
	StackPush(&s, pRoot);             //先把头节点放入栈中防止栈为空

	while (!StackEmpty)
	{
		//栈顶元素就是右子树
		pcur = StackTop(&s);
		StackPop(&s);

		while (pcur)
		{
			printf("%c-->", pcur->data);

			//如果有右子树则保存在栈中
			if (pcur->pRight)
				StackPush(&s, pcur->pRight);

			//一直向左走
			if (pcur->pLeft)
			{
				pcur = pcur->pLeft;
			}

		}

	}
}

//二叉树的镜像(递归)
void MirrorBinTree(PBinTreeNode pRoot)
{
	if (NULL == pRoot)
		return;
	if (pRoot)
	{
		Swap(&pRoot->pLeft, &pRoot->pRight);
		MirrorBinTree(pRoot->pLeft);
		MirrorBinTree(pRoot->pRight);
	}

}

//二叉树的镜像(循环)
void MirrorBinTreeNor5(PBinTreeNode pRoot)
{
	if (NULL == pRoot)
		return;
	Queue q;
	QueueInit(&q);
	QueuePush(&q, pRoot);
	PBinTreeNode	pcur = NULL;
	while (!QueueEmpty(&q));
	{
	    pcur = QueueTop(&q);

		Swap(pcur->pLeft, pcur->pRight);
		
		if (pcur->pLeft)
			QueuePush(&q, pcur->pLeft);

		if (pcur->pRight)
			QueuePush(&q, pcur->pRight);
		QueuePop(&q);                     

	}

}

//交换左右子树
void Swap(PBinTreeNode* pLeft, PBinTreeNode* pRight)
{
	PBinTreeNode pcur = NULL;
	assert(pLeft);
	assert(pRight);

	pcur = *pLeft;
	*pLeft = *pRight;
	*pRight = pcur;

}

// 求二叉树中结点的个数 
int BinTreeSize(PBinTreeNode pRoot)
{
	if (NULL == pRoot)
		return 0;

	//利用递归的方法将左子树个数和右字数个数相加
	return BinTreeSize(pRoot->pLeft) + BinTreeSize(pRoot->pRight);

}

// 获取二叉树中叶子结点的个数 
int GetLeafCount(PBinTreeNode pRoot)
{
	if (NULL == pRoot)
		return 0;

	//只要是叶子节点就返回1
	if (pRoot->pLeft == NULL && pRoot->pRight == NULL)
		return 1;

	//利用递归的方法
	return GetLeafCount(pRoot->pLeft) + GetLeafCount(pRoot->pRight);

}

// 求二叉树中K层结点的个数 
int GetKLevelNode(PBinTreeNode pRoot, int K)
{
	assert(pRoot);
	if (NULL == pRoot)
		return 0;

	if (1 == K)
		return 1;

	//利用递归的方法数第K层的节点数
	return GetKLevelNode(pRoot->pLeft, K - 1) + GetKLevelNode(pRoot->pRight, K - 1);

}

// 求二叉树的高度 
int Height(PBinTreeNode pRoot)
{
	int HeightLeft = 0;
	int HeightRight = 0;

	if (NULL == pRoot)
		return 0;
	HeightLeft = Height(pRoot->pLeft);
	HeightRight = Height(pRoot->pRight);
	if (HeightLeft > HeightRight)
		return HeightLeft + 1;
	else if (HeightLeft < HeightRight)
		return HeightRight + 1;
	else
		return HeightLeft + 1;
}

test.c

#include"BinTreeNode.h"

#include"stack.h"
#include"queue.h"

void TestBinTreeNode()
{
	
	const char* str = "ABD###CE##F";
    
	
	
	PBinTreeNode pRoot =NULL;
	CreateBinTreeNode(&pRoot, str, strlen(str),'#');

	//前序递归遍历
	PreOrder(&pRoot);

	//前序非递归遍历
	PreOrderNor(&pRoot);

	//后续遍历递归
	PostOrder(&pRoot);

	//中序遍历递归
	InOrder(&pRoot);

	//拷贝二叉树
	CopyBinTree(&pRoot);

	//层序遍历递归
	LevelOrder(&pRoot);

	//其他遍历方法
	OtherOrder(&pRoot);

	//二叉树镜像递归法
	MirrorBinTree(&pRoot);

	//二叉树镜像非递归
	MirrorBinTreeNor(&pRoot);
	printf("size= %d",BinTreeSize(&pRoot));
	printf("leafcount= %d",GetLeafCount(&pRoot));
	printf("kleafcount= %d",GetKLevelNode(&pRoot, 3));
	printf("height= %d",Height(&pRoot));

	//销毁列表
	DestroyBinTree(&pRoot);





}
int main()
{
	
	TestBinTreeNode();
	system("pause");
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/alidada_blog/article/details/80448723