二叉搜索树

结点的度:结点拥有子树的数目

叶子:度为0的节点

分支结点:度不为0的结点

树的度:树中结点最大的度

层次:根节点层次为1,其余结点的层次等于该结点的双亲层次加1

树的高度:树中结点的最大层次

无序树:树中结点的各子树之间次序不重要,可以交换位置

有序树:树中结点的各子树之间次序重要,不可以交换位置

若一个结点有子树,则该结点称为子树的双亲

有相同双亲的结点互为兄弟

一个结点的所有子树上的任意结点都是该结点的后裔

从根结点到某个结点路径上的所有结点都是该结点的祖先

二叉树

二叉树是每个节点最多有两个子树的结构,有五种形态

二叉树的性质

性质1:二叉树第N层节点数目最多为2^{N-1}

性质2:深度为k的二叉树最多有2^{k}-1个节点

性质3:包含n个节点的二叉树的高度至少为\log _{2}^{n+1}   

性质4:如果以数组形式存储二叉树,根节点下标为i,当从0开始时,左孩子为2i+1,右孩子为2i+2;当从1开始时,左孩子为2i,右孩子为2i+1

满二叉树:高度为h,并由2^{h}-1个的结点构成的二叉树称为满二叉树

二叉搜索树

 如图所示即为一棵二叉搜索树

任意节点的左子树不空,则左子树上所有节点均小于根节点的值;任意节点的右子树不空,则右子树上所有节点均大于根节点的值。

其优点为要存储到二叉搜索树中的原数据有序无序均可。

时间复杂度:O(\log _{2}^{n})

注:二叉搜索树不处理相同元素!!

树节点的创建

struct treenode
{
	int value;//存储的值
	treenode* lchild;//左孩子
	treenode* rchild;//右孩子
	treenode(int val)//构造函数
	{
		value = val;
		lchild = NULL;
		rchild = NULL;
	}
};

二叉搜索树的创建(用链表)

实现思路:

将vector数组的第一个元素设置为根节点。从根节点开始,如果下一个元素比根节点小,那么根节点的左孩子就放这个元素,如果下一个元素比根节点大,那么根节点的右孩子就放这个元素。当根节点不为空时,说明这个位置已经被放了元素了,所以需要一个troot作为当前根节点。如果当前根节点的左孩子或右孩子被放了元素,则把左孩子或右孩子赋给troot,使左孩子或右孩子成为新的根节点,以此类推,直到找到某个节点的左孩子或右孩子能放这个元素,这一次循环结束。当vector数组中的所有元素都已经被放到树中后,返回树的根节点root.

代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;

struct treenode
{
	int value;//存储的值
	treenode* lchild;//左孩子
	treenode* rchild;//右孩子
	treenode(int val)//构造函数
	{
		value = val;
		lchild = NULL;
		rchild = NULL;
	}
};
treenode* build_binarysearchtree(vector<int> a)
{
	treenode* root = new treenode(a[0]);//将第一个元素设置为根节点
	for (int i = 1; i < a.size(); i++)
	{
		treenode* troot = root;
		treenode* tmp = new treenode(a[i]);
		while (troot)
		{
			if (tmp->value < troot->value)
			{
				if (troot->lchild == NULL)
				{
					troot->lchild = tmp;
					break;
				}
				else
				{
					troot = troot->lchild;
				}
			}
			if (tmp->value > troot->value)
			{
				if (troot->rchild == NULL)
				{
					troot->rchild = tmp;
					break;
				}
				else
				{
					troot = troot->rchild;
				}
			}
		}
	}
	return root;
}
void postorder(treenode* root)
{
	if (root == NULL) return;
	postorder(root->lchild);
	postorder(root->rchild);
	cout << root->value<<" ";
}
int main()
{
	vector<int> a{ 7,4,9,2,6,8,10,1,3,5 };
	postorder(build_binarysearchtree(a));
	return 0;
}

在打印时使用的是后序遍历二叉树,结果即为 1 3 2 5 6 4 8 10 9 7.

 二叉搜索树的创建(用数组)

实现思路:

二叉搜索树用数组形式创建,需要采用递归。同时树的结构体也要发生变化,在存储的时候相当于放在一个结构体数组中存储。

下面是用数组表达树时,树的结构体定义

struct treenode//创建树节点
{
	int value;//存储值
	int lchild;//左孩子
	int rchild;//右孩子
};

用数组实现二叉搜索树需要用到递归,整个递归代码最难理解的地方在于,每个位置应该存储的值都在该层递归的下一层递归被填入,而这层递归只是找到这个所在位置的下标,并把这个下标当作参数传给下一次递归。这样在下一次递归的时候,在一开始的位置就可以对这个值进行存储。

在进行存储的时候,仍然按照二叉搜索树的定义去存储,每次从根节点开始比较,如果比根节点小,则判断根节点的左孩子是否是-1(相当于链表中的空指针),如果是则找到了这个值的左孩子位置并将其作为下一次递归的参数传进去,如果没有,则需要按照二叉树中性质4继续搜索直至找到左孩子为-1的位置,右孩子同理,将元素依次放入树的结构体数组中,以数组的的形式存储一棵二叉树。

代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;

struct treenode//创建树节点
{
	int value;//存储值
	int lchild;//左孩子
	int rchild;//右孩子
};
treenode tree[10001];//以数组的形式来存储二叉搜索树
vector<int> a{ 5,4,3,1,2,6,8,9,7 };
int index = 0;//数组元素下标
bool build_binarysearchtree(int k)
{
	tree[k].value = a[index++];
	if (index == a.size()) return true;//结束当前层递归
	int cur = 0;//cur相当于根节点,每次都从根节点开始遍历
	while (cur < pow(2, a.size()) - 1)
		//考虑最坏情况,当树高为n时,最后一个元素在数组中存储下标为2^n-2
	{
		if (a[index] < tree[cur].value)
		{
			if (tree[cur].lchild == -1)
			{
				tree[cur].lchild = 2 * cur + 1;//如果有位置,更新左孩子下标进行递归
				if (build_binarysearchtree(tree[cur].lchild) == true) return true;
			}
			else
			{
				cur = 2 * cur + 1;//如果没位置,寻找下一个左孩子
			}
		}
		else if (a[index] > tree[cur].value)
		{
			if (tree[cur].rchild == -1)
			{
				tree[cur].rchild = 2 * cur + 2;//如果有位置,更新右孩子下标进行递归
				if (build_binarysearchtree(tree[cur].rchild) == true) return true;
			}
			else
			{
				cur = 2 * cur + 2;//如果没位置,寻找下一个右孩子
			}
		}
	}
}
void Inorder(int k)//中序遍历
{
	if (k == -1) return;
	Inorder(tree[k].lchild);
	cout << tree[k].value << " ";
	Inorder(tree[k].rchild);
}
int main()
{
	for (int i = 0; i < 10001; i++)//将二叉搜索树数组清空
	{
		tree[i].value = 0;
		tree[i].lchild = -1;
		tree[i].rchild = -1;
	}
	build_binarysearchtree(0);
	Inorder(0);
	return 0;
}

为了方便理解,下面是每次递归时进行存储的值

第一层:tree[0].value=5;   a[1]=4;

第二层:tree[1].value=4;   a[2]=3;

第三层:tree[3].value=3;   a[3]=1;

第四层:tree[7].value=1;   a[4]=2;

第五层:tree[16].value=2;   a[5]=6;

第六层:tree[2].value=6;   a[6]=8;

第七层:tree[6].value=8;   a[7]=9;

第八层:tree[14].value=9;   a[8]=7;

第九层:tree[13].value=7  index++后与vector a的大小相等,结束这层递归,跳到上一层递归,之后依次结束上面的每层递归。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值