树与二叉树(二)

1.树的遍历

一般意义上的树子结点个数不限,子结点之间没有先后次序。
(1)树的静态写法
子结点个数无法确定,所以用vector存放所有子结点下标

struct node{
	int data;
	vector<int> child;
}Node[maxn];

创建新结点:

int index=0;
int newNode(int data){
	Node[index].data=data;
	Node[index].child.clear();    //vector的clear()方法清空子结点
	return index++;
}

(2)先根遍历
树的先根遍历类似于二叉树的先序遍历,先访问根结点,再依次访问所有子树。

void pre_order(int root){
	printf("%d\n",Node[root].data);
	for(int i=0;i<Node[root].child.size();i++)
		pre_order(Node[root].child[i]);
}

(3)层序遍历

void layer_order(int root){
	queue<int> q;
	q.push(root);
	while(!q.empty()){
		int t=q.front();
		q.pop();
		printf("%d\n",Node[t].data);
		for(int i=0;i<Node[t].child.size();i++){
			q.push(Node[t].child[i]);   
		}
	}
}

如果需要计算层号:

struct node{
	int data;
	vector<int> child;
	int layer; 
}Node[maxn];

void layer_order(int root){
	queue<int> q;
	q.push(root);
	Node[root].layer=1;
	while(!q.empty()){
		int t=q.front();
		q.pop();
		printf("%d\n",Node[t].data);
		for(int i=0;i<Node[t].child.size();i++){
			q.push(Node[t].child[i]);
			Node[Node[t].child[i]].layer=Node[t].layer+1;
		}
	}
}

实例:
PAT 1053 Path of Equal Weight

Given a non-empty tree with root R, and with weight Wi
​​ assigned to each tree node Ti. The weight of a path from R to L is defined to be the sum of the weights of all the nodes along the path from R to any leaf node L.

Now given any weighted tree, you are supposed to find all the paths with their weights equal to a given number. For example, let’s consider the tree showed in the following figure: for each node, the upper number is the node ID which is a two-digit number, and the lower number is the weight of that node. Suppose that the given number is 24, then there exists 4 different paths which have the same given weight: {10 5 2 7}, {10 4 10}, {10 3 3 6 2} and {10 3 3 6 2}, which correspond to the red edges in the figure.
在这里插入图片描述
Input Specification:
Each input file contains one test case. Each case starts with a line containing 0<N≤100, the number of nodes in a tree, M (<N), the number of non-leaf nodes, and 0<S<2​30 , the given weight number. The next line contains N positive numbers where Wi (<1000) corresponds to the tree node Ti​​ . Then M lines follow, each in the format:

ID K ID[1] ID[2] ... ID[K]

where ID is a two-digit number representing a given non-leaf node, K is the number of its children, followed by a sequence of two-digit ID’s of its children. For the sake of simplicity, let us fix the root ID to be 00.

Output Specification:
For each test case, print all the paths with weight S in non-increasing order. Each path occupies a line with printed weights from the root to the leaf in order. All the numbers must be separated by a space with no extra space at the end of the line.
Note: sequence {A1,A​2​​ ,⋯,A​n} is said to be greater than sequence {B​1 ,B2 ,⋯,B​m​​ } if there exists 1≤k<min{n,m} such that A​i=B​i for i=1,⋯,k, and A​k+1​​ >Bk+1.

​​ Sample Input:

20 9 24
10 2 4 3 5 10 2 18 9 7 2 2 1 3 12 1 8 6 2 2
00 4 01 02 03 04
02 1 05
04 2 06 07
03 3 11 12 13
06 1 09
07 2 08 10
16 1 15
13 3 14 16 17
17 2 18 19

Sample Output:

10 5 2 7
10 4 10
10 3 3 6 2
10 3 3 6 2

题意:给出一棵树和所有结点上的权值,要求找出所有从根结点到叶结点并且权值之和等于指定值的路径,多条路径之间按照路径权值递减顺序输出。第一行输入结点个数n、非叶结点个数m和指定权值和s;第二行输入所有结点的权值;接下来m行,每行先输入每个非叶结点的编号、该结点的子结点个数以及所有子结点的编号。

思路:由题意得结点下标是0,1,…N-1,因此题目中的编号可以直接作为Node数组的下标。在读入时对每个非叶结点的子结点按照权值从大到小排序,方便输出。DFS过程传入当前结点编号index、当前路径上结点个数num和当前权值和sum三个参数,如果sum>s或者sum=s但还没有到达叶结点就直接返回,如果sum=s并且当前结点为叶结点就将整条路径输出。对于当前结点枚举所有子结点,将每个子结点加入路径中并递归进入下一层。

AC代码:

#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn=101;
int n,m,s;
int path[maxn];
struct node{
    int weight;
    vector<int> child;
}Node[maxn];

void DFS(int index,int num,int sum){
    if(sum>s)
        return;
    if(sum==s){
        if(Node[index].child.size()!=0)
            return;
        for(int i=0;i<num;i++){
            if(i==num-1)
                printf("%d\n",Node[path[i]].weight);
            else
                printf("%d ",Node[path[i]].weight);
        }
    }
    for(int i=0;i<Node[index].child.size();i++){
        int child=Node[index].child[i];
        path[num]=child;
        DFS(child,num+1,sum+Node[child].weight);
    }
}

bool cmp(int a,int b){
    return Node[a].weight>Node[b].weight;
}

int main(){
    scanf("%d%d%d",&n,&m,&s);
    for(int i=0;i<n;i++)
        scanf("%d",&Node[i].weight);
    for(int i=0;i<m;i++){
        int id,num;
        scanf("%d%d",&id,&num);
        for(int j=0;j<num;j++){
            int child;
            scanf("%d",&child);
            Node[id].child.push_back(child);
        }
        sort(Node[id].child.begin(),Node[id].child.end(),cmp);
    }
    path[0]=0;
    DFS(0,1,Node[0].weight);
    return 0;
}

2.二叉查找树(BST)

(1)二叉查找树的定义
二叉查找树(Binary Search Tree)是一种特殊的二叉树,又称为二叉搜索树、排序二叉树。二叉查找树的数据域有序,对于树上的每一个结点都满足:左子树上所有结点的数据域小于等于根结点数据域,右子树左右结点的数据域大于根结点数据域。
在这里插入图片描述

(2)二叉查找树的基本操作
1.查找

void search(node *root,int x){
	if(root==NULL){
		printf("failed.\n");
		return;
	}
	if(root->data==x)
		printf("%d\n",root->data);
	else if(x<root->data)
		search(root->lchild,x);
	else
		search(root->rchild,x);
}

2.插入

//插入一个数据域为x的新结点
void insert(node* &root,int x){
	if(root==NULL){
		root=newNode(x);
		return;
	}
	if(root->data==x)
		return;    //结点已存在
	else if(x<root->data)
		insert(root->lchild,x);
	else
		insert(root->rchild,x);
}

3.创建

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

同一组数字如果插入的顺序不同,那么生成的二叉查找树也可能不同。

4.查找最值

//查找最大值
node *findMax(node *root){
	while(root->rchild!=NULL)
		root=root->rchild;
	return root;
}
//查找最小值
node *findMin(node *root){
	while(root->lchild!=NULL)
		root=root->lchild;
	return root;
}

5.删除
要想保证删除一个结点后仍然是一颗二叉查找树,有两种方法:用小于改结点的最大结点(左子树的最右结点)覆盖该结点或者用大于改结点的最小结点(右子树的最左结点)覆盖该结点。

void deleteNode(node* &root,int x){
	if(root==NULL)
		return;
	if(root->data==x){
		if(root->lchild==NULL && root->rchild==NULL)
			root=NULL;
		else if(root->lchild!=NULL){
			node *pre=findMax(root->lchild);
			root->data=pre->data;
			deleteNode(root->lchild,pre->data);
		}
		else{
			node *next=findMin(root->rchild);
			root->data=next->data;
			deleteNode(root->rchild,next->data);
		}
	}
	else if(x<root->data)
		deleteNode(root->lchild,x);
	else
		deleteNode(root->rchild,x);
}

6.性质
对一颗二叉查找树中序遍历,遍历的结果是有序的。

实例:
PAT 1043 Is It a Binary Search Tree

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:
1.The left subtree of a node contains only nodes with keys less than the node’s key.
2.The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
3.Both the left and right subtrees must also be binary search trees.
If we swap the left and right subtrees of every node, then the resulting tree is called the Mirror Image of a BST.
Now given a sequence of integer keys, you are supposed to tell if it is the preorder traversal sequence of a BST or the mirror image of a BST.

Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤1000). Then N integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:
For each test case, first print in a line YES if the sequence is the preorder traversal sequence of a BST or the mirror image of a BST, or NO if not. Then if the answer is YES, print in the next line the postorder traversal sequence of that tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:

7
8 6 5 7 10 8 11

Sample Output 1:

YES
5 7 6 8 11 10 8

Sample Input 2:

7
8 10 11 8 6 7 5

Sample Output 2:

YES
11 8 10 7 5 6 8

Sample Input 3:

7
8 6 8 5 10 9 11

Sample Output 3:

NO

题意:给定一串序列,将其构建二叉查找树后判断这串序列是不是这棵二叉树的先序遍历或镜像树的先序遍历(镜像树是指所有结点的左右子结点互换的二叉树),是的话输出YES 并打印二叉树的后续遍历,否则输出NO。

思路:输入序列用一个vector存放,按照序列顺序插入结点创建二叉树。写树和镜像树的先序和后序遍历四个函数(镜像树只需将左右结点的递归顺序调换一下即可),将四种遍历完的序列存放在四个vector中,与输入序列比较后按题意输出即可。

注意点:
1.判断两个vector是否相等直接用==
2.二叉查找树可以存在两个值相等的结点,在insert函数中不需要将root->data==x这种情况特殊处理
3.插入结点函数传入参数root时要使用引用&;遍历函数传入参数vector时也要使用引用&

AC代码:

#include <stdio.h>
#include <vector>
using namespace std;

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

node* newNode(int x){
    node *p=new node;
    p->data=x;
    p->lchild=NULL;
    p->rchild=NULL;
    return p;
}

void Insert(node* &root,int x){
    if(root==NULL){
        root=newNode(x);
        return;
    }
    else if(x<root->data)
        Insert(root->lchild,x);
    else
        Insert(root->rchild,x);
}

void pre_order(node *root,vector<int> &v){
    if(root==NULL)
        return;
    v.push_back(root->data);
    pre_order(root->lchild,v);
    pre_order(root->rchild,v);
}

void pre_order_mirror(node *root,vector<int> &v){
    if(root==NULL)
        return;
    v.push_back(root->data);
    pre_order_mirror(root->rchild,v);
    pre_order_mirror(root->lchild,v);
}

void post_order(node *root,vector<int> &v){
    if(root==NULL)
        return;
    post_order(root->lchild,v);
    post_order(root->rchild,v);
    v.push_back(root->data);
}

void post_order_mirror(node *root,vector<int> &v){
    if(root==NULL)
        return;
    post_order_mirror(root->rchild,v);
    post_order_mirror(root->lchild,v);
    v.push_back(root->data);
}

vector<int> data,pre,prem,post,postm;
int main(){
    int n,t;
    scanf("%d",&n);
    node *root=NULL;
    for(int i=0;i<n;i++){
        scanf("%d",&t);
        data.push_back(t);
        Insert(root,t);
    }
    pre_order(root,pre);
    pre_order_mirror(root,prem);
    post_order(root,post);
    post_order_mirror(root,postm);
    if(data==pre){
        printf("YES\n");
        for(int i=0;i<post.size();i++){
            if(i<post.size()-1)
                printf("%d ",post[i]);
            else
                printf("%d\n",post[i]);
        }
    }
    else if(data==prem){
        printf("YES\n");
        for(int i=0;i<postm.size();i++){
            if(i<post.size()-1)
                printf("%d ",postm[i]);
            else
                printf("%d\n",postm[i]);
        }
    }
    else
        printf("NO\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值