数据结构复习笔记5.2:二叉树

1.二叉树的概念

        ⼆叉树是每个结点最多有两个⼦树的树结构。也就是说⼆叉树不允许存在度⼤于2的树。它有五种最基本的形态:⼆叉树可以是空集。根可以有空的左⼦树或者右⼦树;或者左右⼦树都是空。其中只有 左⼦树或者右子树的叫做斜树。

为何要重点研究每结点最多只有两个“叉” 的树?

二叉树的结构最简单,规律性最强;

可以证明,所有树都能转为唯一对应的二叉树,不失一般性。

普通树(多叉树)若不转化为二叉树,则运算很难实现。

2.二叉树的性质

3.几个特殊的二叉树

1.满二叉树

一棵深度为k且有2^k-1个结点的二叉树。叶子只能出现在最后⼀层,内部结点的度都为2,如图所示。

特点:1.叶子只能出现在最下一层   2.只有度为0和度为2的结点  3.在同样深度的二叉树中叶子结点(结点)个数最多

2.完全二叉树

深度为k的,有n个结点的二叉树,当且仅当其每一个 结点都与深度为k 的满二叉树中编号从1至n的结点一 一对应。只有最后一层叶子不满,且 叶子全部集中在左边,如图所示。

特点:1.叶子结点只能出现在最下两层,且最下层的叶子结点都集中在二叉树的左部; 2.完全二叉树中如果有度为1的结点,只可能有一个,且该结点只有左孩子。 3.深度为k的完全二叉树在k-1层上 一定是满二叉树。满二叉树也是完全二叉树,而完全二叉树不一定是满二叉树。

3.二叉排序树

左子树上所有结点的关键字均小于根结点的关键字;右子树上的所有结点的关键字均大于根结点的关键字;左子树和右子树又各是一棵二叉排序树。

4.平衡二叉树

树上任一结点的左子树和右子树的深度之差不超过1。

后面的两棵树我会在下一个复习笔记中详细介绍。

4.树的存储结构

1.顺序存储

实现:按满二叉树的结点层次编号,依次存放二叉树中的数据元素(由性质5,标号存在特征)

特点: 点间关系蕴含在其存储位置中浪费空间(尤其是斜树最为明显),适于存满二叉树和完全二叉树

代码实现:

#include <stdlib.h>
#include <stdio.h>
# include <string.h>
char data[1005];
int size;
int flag;//=0 左孩子, =1 右孩子 

int find(char fx)//查找fx的下标 
{
	for(int i=1;i<=size;i++)
	{
		if(data[i]==fx)
		{
			return i;
		}
	 } 
	 return -1;
}

int main()
{
	int n,fx_i,x_i;
	char x,fx;
	scanf("%d",&n);
	for(int i=0;i<=n;i++)
	{//初始化为' ';空格 
		data[i]=' ';
	}
	getchar();
	scanf("%c",&x);
	data[1]=x;
	size=1;
	for(int i=2;i<=n;i++)
	{   
		getchar();
		scanf("%c %c %d",&x,&fx,&flag);
		fx_i=find(fx);
		if(fx_i!=-1)
		{
			if(flag==0)
			{
				x_i=fx_i*2;
			}
			else{
				x_i=fx_i*2+1;
			}
			data[x_i]=x;
			size++;
		}
	}
	getchar();
	scanf("%c",&x);
	x_i=find(x);
	printf("孩子节点:%c %c\n",data[2*x_i],data[2*x_i+1]);
		
	return 0;
	 
}
2.链式存储

        由于⼆叉树的每个结点最多只能有两个⼦树,因此我们就不需要使⽤上述的3种表达法来做。可以直接设置⼀个结点具有两个指针域与⼀个数据域,那么这样就可以建好⼆叉树链表。

代码实现:

#include <stdlib.h>
#include <stdio.h>
# include <string.h>
typedef struct BTNode{
	char data;
	struct BTNode* left;
	struct BTNode* right;
	//父亲指针 
}BTNode,*BTree; 
int flag;//=0 左孩子, =1 右孩子 
BTree initTree(char x)
{
	BTNode* r=(BTNode*)malloc(sizeof(BTNode));
	if(r==NULL)
	{
		printf("分配失败\n"); 
		return NULL;
	}
	else{
		r->data=x;
		r->left = r->right=NULL;
		return r; 
	}
	
}
BTNode* find(BTree ro,char fx)//查找fx所在的节点 
{//递归
	if(ro==NULL||ro->data==fx)
	{
		return ro;
	 } 
	 if(ro->left!=NULL)
	 {
	 	BTNode* f=find(ro->left ,fx); 
	 	if(f!=NULL&&f->data==fx)
	 	{
	 		return f;
		 }
	 }
	 if(ro->right !=NULL)
	 {
	 	BTNode* f=find(ro->right ,fx); 
	 	if(f!=NULL&&f->data==fx)
	 	{
	 		return f;
		 }
	 }
	 return NULL;
	
}
void insert(BTree ro,char x,char fx,int flag)
{
	BTNode* f=find(ro,fx); 
	if(f!=NULL)
	{
		BTNode* s=(BTNode*)malloc(sizeof(BTNode));
		s->data=x;
		s->left=s->right=NULL;
		if(flag==0)
		{
			f->left=s;
		}
		else{
			f->right=s;
		}
	}
}
int main()
{
	int n;
	char x,fx;
	BTree ro=NULL;
	scanf("%d",&n);
	getchar();
	scanf("%c",&x);
	ro=initTree(x);
	for(int i=2;i<=n;i++)
	{   
		getchar();
		scanf("%c %c %d",&x,&fx,&flag);
		insert(ro,x,fx,flag);
	}
	getchar();
	scanf("%c",&x);
	BTNode* p=find(ro,x); 
	if(p!=NULL)
	{
		if(p->left!=NULL)
		{
			printf("左%c\n",p->left->data );
		}
		if(p->right !=NULL)
		{
			printf("右%c\n",p->right ->data );
		}
	}
	return 0;
	 
}

5.遍历二叉树

1.概念

遍历定义:指以一定的次序访问二叉树中的每个结点,并且每个 结点仅被访问一次。

“访问”的含义:输出结点的信息

遍历用途:是树结构插入、删除、修改、查找和排序运算的前提 ,是二叉树一切运算的基础和核心。

一次完整的遍历可产生树中结点的一个线性序列。

2.遍历规则

二叉树由根、左子树、右子树构成

D、L、R的组合定义了六种可能的遍历方案: LDR, LRD, DLR, DRL, RDL, RLD

若限定先左后右,则有三种实现方案: DLR先序遍历    LDR中序遍历    LRD后序遍历

3.遍历代码展示

首先,不管是先序,中序,后序都属于深度遍历,有递归版本和非递归版本(运用栈)

1.递归版本
#include <iostream>
using namespace std;

typedef struct BTNode
{
	char data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode, *Btree;

Btree initTree(char x)
{
	BTNode *r = new BTNode;
	if (r == NULL)
	{
		cout << "defate!" << endl;
		return NULL;
	}
	else
	{
		r->data = x;
		r->left = r->right = NULL;
		return r;
	}
}

BTNode *find(Btree r, char fx)
{
	if (r == NULL || r->data == fx)
	{
		return r;
	}
	if (r->left != NULL)
	{
		BTNode * f = find(r->left, fx);
		if (f != NULL && f->data == fx)
		{
			return f;
		}
	}
	if (r->right != NULL)
	{
		BTNode * f = find(r->right, fx);
		if (f != NULL && f->data == fx)
		{
			return f;
		}
	}
	return NULL;
}

void insert(BTNode * r, char x, char fx, int flag)
{
	BTNode * f = find(r, fx);
	if (f != NULL)
	{
		BTNode *s = new BTNode;
		s->data = x;
		s->left = s->right = NULL;
		if (flag == 0)
		{
			f->left = s;
		}
		else
		{
			f->right = s;
		}
	}
}
//递归调用
void preOrder(Btree r)
{
	if (r == NULL)
	{
		return;
	}
	cout << r->data << "  ";
	if (r->left != NULL)
	{
		preOrder(r->left);
	}
	if (r->right!= NULL)
	{
		preOrder(r->right);
	}
}

void inOrder(Btree r)
{
	if (r == NULL)
	{
		return;
	}
	if (r->left != NULL)
	{
		inOrder(r->left);
	}
	cout << r->data << "  ";
	if (r->right != NULL)
	{
		inOrder(r->right);
	}
}


int main()
{
	int n;
	char x, fx;
	int flag;
	cin >> n >> x;
	Btree root = initTree(x);
	for (int i = 2; i <= n; i++)
	{
		//getchar();
		cin >> x >> fx >> flag;
		insert(root, x, fx, flag);
	}

	cout << endl << "read" << endl;
	cin >> x;
	BTNode * p = find(root, x);
	if (p != NULL && p->left != NULL)
	{
		cout << p->left->data << endl;
	}
	else
	{
		cout << "defate" << endl;
	}

	//深度遍历:①先序遍历
	//preOrder(root);
	//②中序遍历
	//inOrder(root);
	//③后序遍历
	//befOrder(root);
	return 0;

}
2.非递归版本
#include <iostream>
using namespace std;
//运用栈
//树的结点结构
typedef struct BTNode
{
	char data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode, *Btree;

//栈的结点结构
typedef struct stackNode
{
	BTNode * data;
	struct stackNode * next;//结构体内变量想要初始化结构体本身需要加struct
}sstack;
sstack * s = NULL;//声明一个栈

void stack_init()
{
	s = new sstack;
	if (s == NULL)
	{
		cout << "defate" << endl;
		return;
	}
	s->next = NULL;
	return;
}

//入栈
void push_stack(BTNode * k)
{
	//头插
	sstack * p = new sstack;
	p->data = k;
	p->next = s->next;
	s->next = p;
}

//判空
bool empty()
{
	if (s->next == NULL)
	{
		return true;
	}
	return false;
}

//出栈
BTNode * popp()
{
	if (empty() == true)
	{
		cout << "栈空!" << endl;
		return NULL;
	}
	sstack * p = s->next;
	BTNode * k = p->data;
	s->next = p->next;
	delete p;
	p = NULL;
	return k;
}

//得到栈顶元素
BTNode * Get()
{
	if (empty() == true)
	{
		cout << "栈空!" << endl;
		return NULL;
	}

	return s->next->data;
}

Btree initTree(char x)
{
	BTNode *r = new BTNode;
	if (r == NULL)
	{
		cout << "defate!" << endl;
		return NULL;
	}
	else
	{
		r->data = x;
		r->left = r->right = NULL;
		return r;
	}
}

BTNode *find(Btree r, char fx)
{
	if (r == NULL || r->data == fx)
	{
		return r;
	}
	if (r->left != NULL)
	{
		BTNode * f = find(r->left, fx);
		if (f != NULL && f->data == fx)
		{
			return f;
		}
	}
	if (r->right != NULL)
	{
		BTNode * f = find(r->right, fx);
		if (f != NULL && f->data == fx)
		{
			return f;
		}
	}
	return NULL;
}

void insert(BTNode * r, char x, char fx, int flag)
{
	BTNode * f = find(r, fx);
	if (f != NULL)
	{
		BTNode *s = new BTNode;
		s->data = x;
		s->left = s->right = NULL;
		if (flag == 0)
		{
			f->left = s;
		}
		else
		{
			f->right = s;
		}
	}
}
//非递归调用

//1、先序遍历
void preOrder(Btree ro)
{
	if (ro == NULL)
	{
		cout << "树为空!" << endl;
		return;
	}
	stack_init();
	//根结点入栈
	push_stack(ro);
	while (empty() == false)
	{
		BTNode * k = popp();
		cout << k->data << "  ";
		if (k->right != NULL)
		{
			push_stack(k->right);
		}
		if (k->left != NULL)
		{
			push_stack(k->left);
		}
	}
	return;

}
//2、中序遍历
void inOrder(Btree ro)
{
	if (ro == NULL)
	{
		cout << "树空!" << endl;
		return;
	}
	stack_init();
	BTNode * n = ro;
	BTNode * k = NULL;
	while (n != NULL || empty() == false)
	{
		if (n != NULL)
		{
			push_stack(n);
			n = n->left;
		}
		else
		{
			k = popp();
			cout << k->data << "  ";
			n = k->right;//用n遍历k的右孩子
		}
	}

	return;
}
//3、后序遍历
void postOrder(Btree ro)
{
	if (ro == NULL)
	{
		cout << "树空!" << endl;
		return;
	}
	stack_init();
	BTNode * n = ro;
	BTNode * k = NULL;
	BTNode * pre = NULL;
	while (n != NULL || empty() == false)
	{
		if (n != NULL)
		{
			push_stack(n);
			n = n->left;
		}
		else
		{
			k = Get();
			if (k->right != NULL && pre != k->right)
			{
				n = k->right;//让n遍历右子树(孩子)
			}
			else
			{
				k = popp();
				cout << k->data << "  ";
				pre = k;
				n = NULL;//**********让n从右孩子转移到该子树左孩子尽头
			}
		}
	}
	return;
}

int main()
{
	int n;
	char x, fx;
	int flag;
	cin >> n >> x;
	Btree root = initTree(x);
	for (int i = 2; i <= n; i++)
	{
		//getchar();
		cin >> x >> fx >> flag;
		insert(root, x, fx, flag);
	}

	cout << endl << "read" << endl;
	cin >> x;
	BTNode * p = find(root, x);
	if (p != NULL && p->left != NULL)
	{
		cout << p->left->data << endl;
	}
	else
	{
		cout << "defate" << endl;
	}

	//深度遍历:①先序遍历
	//preOrder(root);
	//②中序遍历
	//inOrder(root);
	//③后序遍历
	postOrder(root);
	return 0;

}
/*
9 A
B A 0
E A 1
C B 1
D C 0
F E 1
G F 0
H G 0
K G 1

*/
3.层次遍历(广度遍历)

运用队列的存储

#include <iostream>
using namespace std;
//队列代码->链式
typedef struct qnode 
{
	char data;
	struct qnode* next;
}qnode,*lqueue;

lqueue front, rear;//队头指针和队尾指针

void initqueue()
{
	qnode * q = new qnode;
	if (q == NULL)
	{
		cout << "defate!" << endl;
		return;
	}
	front = rear = q;
	front->next = NULL;
}

void enqueue(char x)
{
	qnode * s = new qnode;
	s->data = x;
	s->next = NULL;
	rear->next = s;
	rear = s;
}//尾插

int empty()
{
	if (front->next == NULL)
	{
		return 1;//空
	}
	return 0;//非空
}

char dequeue()
{
	if (empty() == 0)
	{
		qnode * q = front->next;
		front->next = q->next;
		char x = q->data;
		if (front->next == NULL)
		{
			rear = front;
		}
		delete q;
		q = NULL;
		return x;
	}
	else
	{
		cout << "队空" << endl;
	}
}
///
//二叉链表的结点结构
typedef struct BTNode
{
	char data;
	struct BTNode* left;
	struct BTNode* right;
}BTNode, *Btree;

Btree initTree(char x)
{
	BTNode *r = new BTNode;
	if (r == NULL)
	{
		cout << "defate!" << endl;
		return NULL;
	}
	else
	{
		r->data = x;
		r->left = r->right = NULL;
		return r;
	}
}

BTNode *find(Btree r, char fx)
{
	if (r == NULL || r->data == fx)
	{
		return r;
	}
	if (r->left != NULL)
	{
		BTNode * f = find(r->left, fx);
		if (f != NULL && f->data == fx)
		{
			return f;
		}
	}
	if (r->right != NULL)
	{
		BTNode * f = find(r->right, fx);
		if (f != NULL && f->data == fx)
		{
			return f;
		}
	}
	return NULL;
}

void insert(BTNode * r, char x, char fx, int flag)
{
	BTNode * f = find(r, fx);
	if (f != NULL)
	{
		BTNode *s = new BTNode;
		s->data = x;
		s->left = s->right = NULL;
		if (flag == 0)
		{
			f->left = s;
		}
		else
		{
			f->right = s;
		}
	}
}

void levelOderBtree(Btree r)
{
	//初始化队列
	initqueue();
	//判断空树
	if (r == NULL)
	{
		cout << "空树" << endl;
		return;
	}
	enqueue(r->data);
	char x;
	BTNode * q = NULL;
	while (empty() == 0)
	{
		x = dequeue();
		cout << x << "  ";
		q = find(r, x);
		if (q->left != NULL)
		{
			enqueue(q->left->data);
		}
		if (q->right != NULL)
		{
			enqueue(q->right->data);
		}
	}

}

int main()
{
	int n;
	char x, fx;
	int flag;
	cin >> n >> x;
	Btree root = initTree(x);
	for (int i = 2; i <= n; i++)
	{
		cin >> x >> fx >> flag;
		insert(root, x, fx, flag);
	}

	cout << endl << "read" << endl;
	cin >> x;
	BTNode * p = find(root, x);
	if (p != NULL && p->left != NULL)
	{
		cout << p->left->data << endl;;
	}

	//层次遍历
	levelOderBtree(root);


	return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值