二叉树

二叉树

实现用线性结构表示非 线性结构

数---》二叉树---》满二叉树---》完全二叉树

一、二叉树的概念

二叉树也是树的一种,其存储结构及其算法都较为简单,因此二叉树显得特别重要。

二叉树:是每个节点的最多有两个子树的有序树--度最多为2的有序树

注意:在有序树中,虽然一个节点的孩子之间是有左右次序的,但是若该节点只有一个孩子,就无须区分左右次序,而在二叉树中,即使是一个孩子也有左右之分

一棵数变成二叉树:目的想去利用数组的方式保存(但是可能会存在浪费)

二、二叉树的五种表现形式

1.空树

2.只有一个根节点的二叉树

3.只有一个左子树的二叉树

4.只有一个右子树的二叉树

5.有左右子树的二叉树

三、二叉树的特性

1.二叉树的每个节点至多只有二棵子树(不存在度大于2的节点)

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

3.二叉树的第n层至多有2^(n-1)个节点

4.深度为k的二叉树至多有2^(k)-1个节点

5.任意一棵二叉树中,如果度为2的节点数为n,度为0的节点数为m,m=n+1

四、满二叉树

1.二叉树中第n层上的节点数必须为2^(n-1)个节点

2.二叉树如果高度为k,这个二叉树中的节点数必须为2^(k)-1个

3.在满二叉树中不存在度为1的节点,每一个分支节点都有2棵高度一致的子树所有叶节点都在最下一层

4.一棵二叉树如果变成了满二叉树,可以利用数组且,且没有空间浪费

五、完全二叉树

1.若一棵二叉树最多只有最下面的两层其节点的度可以小于2,并且最下一层上的节点都集中在该层最左边的若干位置上,则此二叉树称为完全二叉树

2.满二叉树是完全二叉树,完全二叉树不一定是满二叉树

完全二叉树的特性

1.从一棵满二叉树的最下一层(叶节点那一层),从右往左依次删除若干(0-n)叶节点后形成的数叫完全二叉树

2.在一棵完全二叉树中,如果一个节点没有左子树,这个节点必然没有右子树,这个节点是叶节点。但是可以有左子树,没有右子树

完全二叉树中的下标规律

1.根节点下标默认为0

2.树中的任意一个节点它的下标为i,那么这个节点的父节点下标必然为(i-1)>>1

3.树中的任意一个节点它的下标为i,那么这个节点的左子树下标必然是2*i+1,右子树的下标必然为2乘i+2

4.除开根节点,左子树的下标为奇数,右子树的下标为偶数

六、二叉树的遍历

1、先序(根)

先访问根节点,然后访问左孩子,最后访问右孩子

2、中序(根)

先访问左孩子,然后访问根节点,最后访问右孩子

3、后序(根)

先访问左孩子,再访问右孩子,最后访问根节点

七、完全二叉树的代码示例

类模板--binarytree.h

#pragma once
template<class T>
class mytree
{
	T* pbuff;
	int len;//动态数组当前元素个数
	int maxsize;//动态数组最大容量
public:
	mytree();
	~mytree();
	void clear();//清除树
public:
	bool find(T const&findval)const;//判断是否在树中找到这个数据
	void appendnode(T const&data);//申请内存扩容,并插入数据
	void inittree(T arr[], int length);//初始化树
	void printftree();//提供接口,打印树
	T getparentval(int elemval)const;//找父节点
	T getleftval(int elemval)const;//找左子树
	T getrightval(int elemval)const;//找右子树
	T getleftbrother(int elemval)const;//找左兄弟
	T getrightbrother(int elemval)const;//找右兄弟
private:
	int _find(T const& findval)const;//查找数据,返回下标
	void _printftree(int index);//打印树
};

template<class T>
mytree<T>::mytree()//构造函数
{
	pbuff = nullptr;
	len = maxsize = 0;
}

template<class T>
 mytree<T>::~mytree()
{
	 clear();
}

template<class T>
void mytree<T>::clear()
{
	if (pbuff)
		delete[]pbuff;
	pbuff = nullptr;
	len = maxsize = 0;
}

template<class T>
bool mytree<T>::find(T const & findval) const
{
	return _find(findval) != -1;
}

template<class T>
void mytree<T>::appendnode(T const & data)
{
	if (len >= maxsize)
	{
		maxsize = maxsize + ((maxsize >> 1) ? (maxsize >> 1) : 1);
		T* ptemp = new T[maxsize];
		memcpy(ptemp, pbuff, sizeof(T)*len);
		if (pbuff)
		{
			delete[]pbuff;
		}
		pbuff = ptemp;
	}
	pbuff[len++] = data;
}

template<class T>
void mytree<T>::inittree(T arr[], int length)//传一个数组进来
{
	clear();//先将树中的内容清除掉
	if (length > 0)
	{
		maxsize = len = length;
		pbuff = new T[maxsize];
		for (int i = 0; i < maxsize; i++)
		{
			pbuff[i] = arr[i];//用这个数组来初始化动态数组
		}
	}
}

template<class T>
void mytree<T>::printftree()
{
	_printftree(0);//从根节点开始打印
}

template<class T>
T mytree<T>::getparentval(int elemval) const//打印传进来的数据的父节点
{
	int index = _find(elemval);
	if (index < 0)
		throw "发生错误";
	return pbuff[(index - 1) >> 1];
}

template<class T>
T mytree<T>::getleftval(int elemval) const//找这个数据的左子树
{
	int index = _find(elemval);
	if (2 * index + 1 >= len || index < 0)
	{
		throw "out_range";
	}
	return pbuff[2 * index + 1];
}

template<class T>
T mytree<T>::getrightval(int elemval) const
{
	int index = _find(elemval);
	if (2 * index + 2 >= len && index < 0)
	{
		throw "发生错误";
	}
	return pbuff[2 * index + 2];
}

template<class T>
T mytree<T>::getleftbrother(int elemval) const
{
	int index = _find(elemval);
	if (index < 0)
	{
		throw "发生错误";
	}
	if (index % 2 != 0)
	{
		throw "this is left";
	}
	return pbuff[index - 1];
}

template<class T>
T mytree<T>::getrightbrother(int elemval) const
{
	int index = _find(elemval);//先找到这个元素的下标
	if (index < 0)
	{
		throw "发生错误";
	}
	if (index % 2 == 0)
	{
		throw "this is right";
	}
	return pbuff[index + 1];
}

template<class T>
int mytree<T>::_find(T const & findval) const
{
	for (int i = 0; i < len; i++)
	{
		if (findval == pbuff[i])
		{
			return i;
		}
	}
	return -1;
}

template<class T>
void mytree<T>::_printftree(int index)
{
	if (index < len)
	{
		//先序的打印方法
		printf("%d\n", pbuff[index]);//打印根节点
		_printftree(2 * index + 1);//打印左子树
		_printftree(2 * index + 2);//打印右子树

		//中序打印
		//_printftree(2 * index + 1);//打印左子树
		//printf("%d\n", pbuff[index]);//打印根节点
		//_printftree(2 * index + 2);//打印右子树

		//后序打印
	//	_printftree(2 * index + 1);//打印左子树
	//	_printftree(2 * index + 2);//打印右子树
	//	printf("%d\n", pbuff[index]);//打印根节点
	}
}

main.cpp

#include<iostream>
#include"binarytree.h"
using namespace std;
int main()
{
	mytree<int> ms;
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9};
	ms.inittree(arr, 10);
	for (int i = 0; i <5; i++)
	{
		ms.appendnode((i+1)*10);
	}
	ms.printftree();
	return 0;
}
posted @ 2021-04-09 10:25  kisfly  阅读(243)  评论(0编辑  收藏  举报