【数据结构】树和二叉树总结

二叉树

指针实现二叉树

#include<bits/stdc++.h>
using namespace std;

typedef int TElemType;
struct node
{
	TElemType data;
	node* lchild;
	node* rchild;
};

// 二叉树建树前根节点不存在
node* root = NULL;

// 建立节点
node* newNode(int v) // v为节点权值 
{
	node* Node = new node; // 申请内存 
	Node->data = v;
	Node->lchild = Node->rchild = NULL;
	return Node; 
}

// 查找值为x的结点并将其值修改为newdata 
void search(node* root, int x, int newdata)
{
	if(root == NULL)	return;
	if(root->data == x)	root->data = newdata;
	search(root->lchild, x, newdata);
	search(root->rchild, x, newdata);
}

// 插入结点 
void insert(node* &root, int x)
{
	if(root == NULL){
		root = newNode(x);
		return;
	}
	if(Judge())	insert(root->lchild, x);
	else	insert(root->rchild, x);
}

// 建树 
node* Create(int data[], int n)
{
	node* root = NULL;
	for(int i = 0; i < n; i++)	insert(root, data[i]);
	return root;
}

// 先序遍历 
void preorder(node* root)
{
	if(root == NULL)	return;
	printf("%d\n", root->data);
	preorder(root->lchild);
	preorder(root->rchild);
}

// 中序遍历 
void inorder(node* root)
{
	if(root == NULL)	return;
	inorder(root->lchild);
	printf("%d\n", root->data);
	inorder(root->rchild);
}

// 后序遍历 
void postorder(node* root)
{
	if(root == NULL)	return;
	postprder(root->lchild);
	postorder(root->rchild);
	printf("%d\n", root->data);
}

// 层序遍历 
void layerorder(node* root)
{
	queue<node*> q;
	q.push(root);
	while(!q.empty){
		node* now = q.front();
		q.pop();
		printf("%d", now->data);
		if(now->lchild != MULL)	q.push(now->lchild);
		if(now->rchild != NUll)	q.push(now->rchild);
	}
}

// 求二叉树深度 
int find_depth(node* root, int depth, int maxn) // 初始时depth为1,maxn为0 
{
	if(root == NULL && ){
		maxn = depth;
		depth --;
		return;
	}
	depth ++;
	find_depth(root->lchild, depth, maxn);
	find_depth(root->rchild, depth, maxn);
	return maxn;
}

结构数组模拟二叉树

#include <bits/stdc++.h>

using namespace std;

typedef char TElemType;

const int maxn = 100010;

struct node{
	TElemType data;
	int lch;
	int rch;
}Node[maxn];

int idx = 0;

// 模拟创建结点(静态指定) 
int newNode(int v)
{
	Node[idx].data = v;
	Node[idx].lch = -1;
	Node[idx].rch = -1;
	return idx ++;
}

// 查找和修改 
void search(int root, int x, int newdata)
{
	if(root == -1)	return;
	if(Node[root].data == x)	Node[root].data = newdata;
	search(Node[root].lch, x, newdata);
	search(Node[root].rch, x, newdata);
} 

// 插入 
void insert(int &root, int x)
{
	if(root == -1){
		root == newNode(x);
		return;
	}
	if(Judge())	insert(Node[root].lch, x);
	else	insert(Node[root].rch, x);
}

int Create(int data[], int n)
{
	int root = -1;
	for(int i = 0; i < n; i ++)	insert(root, data[i]);
	return root;
}

// 先序遍历 
void preorder(int root)
{
	if(roor == -1)	return;
	printf("%d\n",Node[root].data);
	preorder(Node[root].lch);
	inorder(Node[root].rch);
}

// 中序遍历 
void inorder(int root)
{
	if(roor == -1)	return;
	inorder(Node[root].lch);
	printf("%d\n",Node[root].data);
	inorder(Node[root].rch);
}

// 后序遍历 
void postorder(int root)
{
	if(roor == -1)	return;
	postorder(Node[root].lch);
	postorder(Node[root].rch);
	printf("%d\n",Node[root].data);
}

// 层序遍历
void layeroeder(int root)
{
	queue<int> q;
	q.push(root);
	while(!q.empty()){
		int now = q.front();
		q.pop();
		printf("%d", Node[now].data);
		if(Node[now].lch != -1)	q.push(Node[now].lch);
		if(Node[now].rch != -1)	q.push(Node[now].rch);
	}
} 

二叉树还原

条件:已知中序序列和其他任意遍历序列,还原二叉树
思路:任意序找根,中序分左右,递归求解
方法:双指针法

例:给定一棵二叉树的先序遍历序列和中序遍历序列,重建这棵二叉树。
在这里插入图片描述

法一:真的双指针
在这里插入图片描述
用string的substr()方法取子串

法二:双指针思想,数组下标作指针

假设已知先序序列为 pre1, pre2, …, pren;
中序序列为in1, in2, …; inn;
在这里插入图片描述

  1. 由先序性质:pre1 是当前二叉树的根结点;
  2. 由中序性质:根结点将中序序列划分成左子树和右子树
  3. 因此:在中序序列中找到ink,使 ink == pre1,就找到根结点
  4. 故:左子树结点个数 numLeft = k - 1;
  5. 故:左子树先序序列区间为 [2, k],中序序列区间为 [1,k-1];
  6. 故:右子树先序序列区间为 [k+1, n],中序序列区间为 [k+1, n];
  7. 只需往左子树和右子树进行递归构建二叉树

在这里插入图片描述

  1. 如果递归过程中,当前先序序列的区间为 [preL, preR],中序序列的区间为 [inL, inR];
  2. 那么:左子树的结点个数为 numLeft = k - inL;
  3. 故:左子树先序序列区间为 [pre+1, pre+numLeft],中序序列区间为 [inL, k-1];
  4. 故:右子树先序序列区间为 [preL+numLeft+1, preR],中序序列区间为 [k+1, inR];
  5. 且:递归边界为先序序列的长度小于0,此时当前二叉树不存在。
// 当前先序序列区间为[preL, preR], 中序序列区间为[inL, inR] , 返回根结点地址
node* create(int preL, int preR, int inL, int inR)
{
	if(preL > preR)	return NULL; // 先序序列长度小千等千0时, 直接返回
	node* root = new node; // 新建一个新的结点, 用来存放当前二叉树的根结点
	root->data = pre[preL]; // 新结点的数据域为根结点的值
	
	int k;
	for(k = inL; k <= inR; k++)
		if (in[k] == pre[preL])	break; // 在中序序列中找到in[k] == pre[L]的结点
	int numLeft = k - inL; // 左子树的结点个数
	
	// 左子树的先序区间为[preL+l, preL+numLeft], 中序区间为[inL, k-1]
	// 返回左子树的根结点地址, 赋值给root的左指针
	root->lchild = create(preL + 1, preL + numLeft, inL, k - l);
	
	// 右子树的先序区间为(preL + numLeft + 1, preR], 中序区间为[k+l, inR)
	// 返回右子树的根结点地址, 赋值给root的右指针
	root->rchild = create(preL + numLeft + 1, preR, k + 1, inR);
	return root;
}

二叉查找树

树的静态实现

动态实现略了,原理一模一样。

双亲表示法:指针域只存双亲地址

struct tree{
	typename val;
	int par;
};

孩子表示法:指针域只存孩子地址,由于子结点个数无法预知,故使用vector存孩子

struct tree{
	typename val;
	vector<int> cld ;
};

双亲孩子表示法:指针域既存双亲地址,也存孩子地址

struct tree{
	typename val;
	int par;
	vector<int> cld;
};

孩子兄弟表示法:
在这里插入图片描述
不管有多少个孩子,只定义两个指针域,左指针域存长子地址,右指针域存第一个兄弟地址。

优点:将任意个子节点的存储简化为两个指针域的存储。

struct tree{
	typename val;
	int eld;
	int bro;
};

哈夫曼树/最优二叉树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值