2019-1-2

三叉树

题目描述
Time Limit: 1000 ms
Memory Limit: 256 mb
一个关于三叉树的题目,小于100的值代表树叶,大于100的值为分支点,
建树的过程是水平方向建树,

输入格式:

先输入n,代表有n组数据,接下来n行,输入4个数,
第一个数代表根节点,
接下来分别代表三个子节点,-1代表子节点不存在,输入的顺序按照层次遍历的次序。
接下来,要求寻找叶子节点的最短路径,最短路径是指不经过重复的边。
输入方式,首先输入一个值m,代表m行,接下来m行输入m个叶子节点和对应的优先级,要求按优先级输出从上次到达的位置到该节点的最短路径,每条路径的最后一个节点要求输出目标叶子节点,最后要求回到根节点。

输入样例#

10
100 101 108 107
101 1 102 2
108 103 104 105
107 17 109 18
102 3 4 5
103 7 8 9
104 10 106 11
105 15 16 -1
109 19 20 21
106 12 13 14
5
8 1
14 3
16 2
5 0
19 4

输出样例#:

100 101 102 5
102 101 100 108 103 8
103 108 105 16
105 108 104 106 14
106 104 108 100 107 109 19
109 107 100
  • 关键点:
    *** 使用sort函数对数据预处理
    *** 根据给定的条件建树
    *** 根据给定的值,寻找在树中的位置
    *** 寻找公共祖先节点(带有父指针)
    1.方案一、寻找第一个相交的点(层数高的先走几步,直至层数相同,然后判断每走一步是否有公共的祖先节点)
    2.方案二、利用后序遍历求解公共祖先节点
    *** 先序遍历输出路径
#include<stdio.h>
#include<stdlib.h>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;

int input[100][4];

struct prior
{
    int id;
    int pri;
}ssd[100];
int n,m;

bool cmp(prior a,prior b)
{
    if(a.pri < b.pri) return true;
    else return false;
}

typedef struct node
{
    int id;
    int layer;//用于寻找公共祖先节点
    node* parent;
    node* lchild;
    node* mchild;
    node* rchild;
}Node,*Tree;

Node* newNode(int id)
{
    Node* temp = (Node*)malloc(sizeof(Node));
    temp->id = id;
    temp->layer = 0;
    temp->parent = temp->lchild = temp->mchild = temp->rchild = NULL;
    return temp;
}

/*
递归建树:
初始状态  层数和父节点已经建立
*/
void createTree(Node* root)
{
    int i;
    for(i = 0;i<n;i++)
    {
        if(root->id == input[i][0])
            break;
    }
    if(i == n)
        return ;

    if(input[i][1]!=-1)
    {
        Node* temp1 = newNode(input[i][1]);
        temp1->layer = root->layer + 1;

        root->lchild = temp1;
        temp1->parent = root;

        createTree(temp1);
    }
    if(input[i][2] != -1)
    {
        Node* temp2 = newNode(input[i][2]);
        temp2->layer = root->layer + 1;

        temp2->parent = root;
        root->mchild = temp2;

        createTree(temp2);
    }
    if(input[i][3]!=-1)
    {
        Node* temp3 = newNode(input[i][3]);
        temp3->layer = root->layer + 1;

        temp3->parent = root;
        root->rchild = temp3;

        createTree(temp3);
    }
}

void preOrder(Node* root)
{
    if(root)
    {
        if(root->id == input[0][0])
            printf("%d %d\n",root->id,root->layer);
        else
            printf("%d %d %d\n",root->id,root->layer,root->parent->id);
        preOrder(root->lchild);
        preOrder(root->mchild);
        preOrder(root->rchild);
    }
}

void layerOrder(Node* root)
{
    queue<Node*> q;
    q.push(root);

    while(!q.empty())
    {
        Node* qhead = q.front();
        if(qhead->id == input[0][0])
            printf("%d %d\n",qhead->id,qhead->layer);
        else
            printf("%d %d %d\n",qhead->id,qhead->layer,qhead->parent->id);

        if(qhead->lchild)
            q.push(qhead->lchild);
        if(qhead->mchild)
            q.push(qhead->mchild);
        if(qhead->rchild)
            q.push(qhead->rchild);

        q.pop();
    }
}


vector<Node*> tempPath,ansPath;
/*
实际问题:给定的孩子节点,肯定能够找到
*/

//******
Node* findChildPosition(Node* root,int childId)//有返回值的情况下只需要找到一条路径即可返回,一般情况下题目中只有一条路径
{
    if(root == NULL)
        return NULL;

    if(root->id == childId)
        return root;//找到了,或者到达终点没找到

    /*
    Node* temp = findChildPosition(root->lchild,childId);
    if(temp!= NULL)//通过左子树找到
        return temp;
    else
        temp = findChildPosition(root->mchild,childId);
    if(temp != NULL)//通过中子树找到
        return temp;
    else
        temp = findChildPosition(root->rchild,childId);
    if(temp!=NULL)//通过右子树找到
        return temp;
    else//通过所有的子树均找不到
        return NULL;
    */
    Node *tmp1,*tmp2,*tmp3;
	tmp1 = findChildPosition(root->lchild,childId);
	if(tmp1)
		return tmp1;
	tmp2 = findChildPosition(root->mchild,childId);
	if(tmp2)
		return tmp2;
	tmp3 = findChildPosition(root->rchild,childId);
	if(tmp3)
		return tmp3;

    return NULL;//通过左子树,中子树,右子树均为找到孩子节点

/*
下面的这种写法值得自己仔细的思考
以前的认识是错误的,哈哈哈哈非常的开心啊
思考:下面的这种方法就本题而言,打印路径是绝对没有问题的,但是在返回ChildId的位置的时候发生错误
tempPath.push_back()和tempPath.pop_back()的位置,是输出多有能够到达指定终点的路径
就本题而言,只有一条路径所以只会打印一条;
但是作为返回值:下面这种写法是错误的,因为在某一条子节点找到之后并不会这个节点的位置
而是继续寻找,这样的话就丢失了这个位置。返回值就是错误的。
*/
    /*
    Node* temp = NULL;
    if(root->id == childId)
    {
        tempPath.push_back(root);
        for(int i = 0;i<tempPath.size();i++)
        {
            if(i == tempPath.size()-1)
                printf("%d\n",tempPath[i]->id);
            else
                printf("%d ",tempPath[i]->id);
        }
        tempPath.pop_back();
        return root;
    }

    if(root->lchild == NULL && root->mchild == NULL && root->rchild == NULL)
        return NULL;

    tempPath.push_back(root);//首先将当前节点加入tempPath
    if(root->lchild)//访问其相邻的子节点
    {
        temp = findAndPrintChild(root->lchild,childId);
    }
    if(root->mchild)
    {
        temp = findAndPrintChild(root->mchild,childId);
    }
    if(root->rchild)
    {
        temp = findAndPrintChild(root->rchild,childId);
    }
    tempPath.pop_back();//到达这一步说明通过root的子节点到达不了目的节点,将root节点删除
    return temp;
    */
}


Node* findSameAncient(Node *root,int id1,int id2)
{
    Node *temp1,*temp2;
    int layer1,layer2;

    temp1 = findChildPosition(root,id1);
    temp2 = findChildPosition(root,id2);
    layer1 = temp1->layer;
    layer2 = temp2->layer;

    if(layer1 > layer2)
    {
        int c = layer1 - layer2;
        while(c--)
        {
            temp1 = temp1->parent;
        }
    }

    if(layer1<layer2)
    {
        int d = layer2 - layer1;
        while(d--)
        {
            temp2 = temp2->parent;
        }
    }

    if(temp1 == temp2) return temp1;

    while(temp1->parent->id != temp2->parent->id)
    {
        temp1 = temp1->parent;
        temp2 = temp2->parent;
    }

    return temp1->parent;
}


Node* prePrint(Node* root,int id)//树中只存在一条路径,不需要寻找所有的路径
{
    if(root == NULL) return NULL;
    if(root->id == id)
    {
        tempPath.push_back(root);
        for(int i = 0;i<tempPath.size();i++)
        {
            if(i == tempPath.size()-1)
                printf("%d\n",tempPath[i]->id);
            else
                printf("%d ",tempPath[i]->id);
        }
        tempPath.pop_back();

        return root;
    }

    tempPath.push_back(root);
    Node* tempNode = prePrint(root->lchild,id);
    tempPath.pop_back();
    if(tempNode)
        return tempNode;

    tempPath.push_back(root);
    tempNode = prePrint(root->mchild,id);
    tempPath.pop_back();
    if(tempNode)
        return tempNode;

    tempPath.push_back(root);
    tempNode = prePrint(root->rchild,id);
    tempPath.pop_back();
    if(tempNode)
        return tempNode;

    return NULL;//表示通过三个子节点之后没有找到,返回NULL
}

void print_out(Node* root)
{
    prePrint(root,ssd[0].id);

    Node *child1,*sameParent,*child2;
    for(int i = 0;i<m-1;i++)
    {
        child1 = findChildPosition(root,ssd[i].id);
        child2 = findChildPosition(root,ssd[i+1].id);
        sameParent = findSameAncient(root,ssd[i].id,ssd[i+1].id);
        while(child1->parent!=sameParent)
        {
            printf("%d ",child1->parent->id);
            child1 = child1->parent;
        }
        prePrint(sameParent,ssd[i+1].id);
    }

    child1 = findChildPosition(root,ssd[m-1].id);
    while(child1->parent!=sameParent)
    {
        printf("%d ",child1->parent->id);
        child1 = child1->parent;
    }
    printf("%d\n",root->id);

}

int main()
{
    /*
    数据输入
    */
    int i;

    scanf("%d",&n);
    for(i = 0;i<n;i++)
    {
        scanf("%d%d%d%d",&input[i][0],&input[i][1],&input[i][2],&input[i][3]);
    }
    scanf("%d",&m);
    for(i = 0;i<m;i++)
    {
        scanf("%d%d",&ssd[i].id,&ssd[i].pri);
    }

    /*
    初始化变量
    */

    /*
    数据处理
    */

    //建树
    Node* root = newNode(input[0][0]);
    root->layer = 1;
    root->parent = NULL;
    createTree(root);

    sort(ssd,ssd + m,cmp);
    print_out(root);

    return 0;
}
/*
IN:
10
100 101 108 107
101 1 102 2
108 103 104 105
107 17 109 18
102 3 4 5
103 7 8 9
104 10 106 11
105 15 16 -1
109 19 20 21
106 12 13 14
5
8 1
14 3
16 2
5 0
19 4
OUT:
100 101 102 5
102 101 100 108 103 8
103 108 105 16
105 108 104 106 14
106 104 108 100 107 109 19
109 107 100
*/

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

int n;
int input[100][4];
int m;
struct data
{
    int id;
    int priority;
}pri[100];

bool cmp(data a,data b)
{
    if(a.priority<b.priority) return true;
    else return false;
}

typedef struct node
{
    int id;
    int layer;
    node* parent;
    node* lchild;
    node* mchild;
    node* rchild;
}Node,*Tree;

Node* newNode(int id)
{
    Node* temp = (Node*)malloc(sizeof(Node));
    temp->id = id;
    temp->layer = 0;
    temp->parent = temp->lchild = temp->mchild = temp->rchild = NULL;
    return temp;
}
void createTree(Node* root)
{
    int i;
    for(i = 0;i<n;i++)
    {
        if(root->id == input[i][0])
            break;
    }
    if(i == n) return ;

    if(input[i][1] != -1)
    {
        Node* temp1 = newNode(input[i][1]);
        temp1->layer = root->layer + 1;
        temp1->parent = root;
        root->lchild = temp1;
        createTree(temp1);
    }
    if(input[i][2] != -1)
    {
        Node* temp2 = newNode(input[i][2]);
        temp2->layer = root->layer + 1;
        temp2->parent = root;
        root->mchild = temp2;
        createTree(temp2);
    }
    if(input[i][3] != -1)
    {
        Node* temp3 = newNode(input[i][3]);
        temp3->layer = root->layer + 1;
        temp3->parent = root;
        root->rchild = temp3;
        createTree(temp3);
    }
}

void preOrder(Node* root)
{
    if(root)
    {
        printf("%d\n",root->id);
        preOrder(root->lchild);
        preOrder(root->mchild);
        preOrder(root->rchild);
    }
}

Node* findChildPosition(Node* root,int id)
{
    if(root == NULL || root->id == id) return root;

    Node* temp = findChildPosition(root->lchild,id);
    if(temp) return temp;

    temp = findChildPosition(root->mchild,id);
    if(temp) return temp;

    temp = findChildPosition(root->rchild,id);
    if(temp) return temp;

    return NULL;
}

Node* leastCommonAncient(Node* root,Node* temp1,Node* temp2)
{
    int layer1 = temp1->layer;
    int layer2 = temp2->layer;
    if(layer1>layer2)
    {
        int t  = layer1 - layer2;
        while(t--)
        {
            temp1 = temp1->parent;
        }
    }
    if(layer1<layer2)
    {
        int t = layer2 - layer1;
        while(t--)
        {
            temp2 = temp2->parent;
        }
    }
    if(temp1 == temp2)
        return temp1;

    while(temp1->parent != temp2->parent)
    {
        temp1 = temp1->parent;
        temp2 = temp2->parent;
    }
    return temp1->parent;
}

vector<Node*> up,down;
void printUp(Node* high,Node* low)//high<-low
{
    printf("%d ",low->id);
    low = low->parent;
    while(low!=high)
    {
        printf("%d ",low->id);
        low = low->parent;
    }
    printf("%d",high->id);
}

void printDown(Node* high,Node* low)//high->low
{
    vector<Node*> path;
    path.push_back(low);
    low = low->parent;
    while(low != high)
    {
        path.push_back(low);
        low = low->parent;
    }
    //path.push_back(high);

    for(int i = path.size()-1;i>=0;i--)
    {
        if(i == 0)
        {
            printf("%d",path[i]->id);
        }
        else
        {
            printf("%d ",path[i]->id);
        }
    }
}

void printPath(Node* root)
{
    Node* child = findChildPosition(root,pri[0].id);
    //最开始
    printf("%d ",root->id);
    printDown(root,child);
    printf("\n");

    //中间
    for(int i = 0;i<m-1;i++)
    {
        Node* child1 = findChildPosition(root,pri[i].id);
        Node* child2 = findChildPosition(root,pri[i+1].id);
        Node* ancient = leastCommonAncient(root,child1,child2);
        printUp(ancient,child1->parent);
        printf(" ");
        printDown(ancient,child2);
        printf("\n");
    }

    //最后返回
    child = findChildPosition(root,pri[m-1].id)->parent;
    printUp(root,child);
    printf("\n");
}
int main()
{
    freopen("2019_2_2.txt","r",stdin);
    scanf("%d",&n);
    for(int i = 0;i<n;i++)
    {
        scanf("%d%d%d%d",&input[i][0],&input[i][1],&input[i][2],&input[i][3]);
    }
    scanf("%d",&m);
    for(int i = 0;i<m;i++)
    {
        scanf("%d%d",&pri[i].id,&pri[i].priority);
    }
    sort(pri,pri + m,cmp);

    Node* root = newNode(input[0][0]);
    root->layer = 1;
    createTree(root);
    printPath(root);

    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值