首页 > 试题广场 >

二叉树

[编程题]二叉树
  • 热度指数:16630 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
      1
      / \
    2   3
    / \ / \
  4 5 6 7
  /\ /\ /\ /\
如上图所示,由正整数 1, 2, 3, ...组成了一棵无限大的二叉树。从某一个结点到根结点(编号是1的结点)都有一条唯一的路径,比如从5到根结点的路径是(5, 2, 1),从4到根结点的路径是(4, 2, 1),从根结点1到根结点的路径上只包含一个结点1,因此路径就是(1)。对于两个结点x和y,假设他们到根结点的路径分别是(x1, x2, ... ,1)和(y1, y2,...,1),那么必然存在两个正整数i和j,使得从xi 和yj 开始,有xi = yj,xi + 1 = yj + 1,xi + 2 = yj + 2,...
现在的问题就是,给定x和y,要求他们的公共父节点,即xi(也就是 yj)。

输入描述:
输入包含多组数据,每组数据包含两个正整数x和y(1≤x, y≤2^31-1)。


输出描述:
对应每一组数据,输出一个正整数xi,即它们的首个公共父节点。
示例1

输入

10 4

输出

2

先统一了两个数所在的层数,再根据int(n/2)寻找上一个节点的值进行比较

#include<cmath>
using namespace std;

int main(){
    int a, b;
    while(cin >> a >> b){
        int a_layer, b_layer;
        a_layer = (int)(log(a) / log(2)) + 1;
        b_layer = (int)(log(b) / log(2)) + 1;
        //cout << a_layer << ' ' << b_layer << endl;
        while(a_layer > b_layer){
            a = (int)(a / 2);
            a_layer--;
            //cout << a << endl;
        }
        while(b_layer > a_layer){
            b = (int)(b / 2);
            b_layer--;
        }
        while(a != b){
            a = (int)(a / 2);
            b = (int)(b / 2);
            //cout << a << ' ' << b << endl;
        }
        cout << a << endl;
    }
    return 0;
}
发表于 2019-03-11 17:29:29 回复(0)
这题也要智商嘛。。。
#include<iostream>
using namespace std;
int main(){
	int a,b;
	while(cin>>a>>b){
		while(a!=b){
			a>b?a/=2:b/=2;
		}cout<<a<<endl;
	}
	return 0;
} 


发表于 2020-03-03 17:49:45 回复(0)
#include<iostream>
#include<cmath>
using namespace std;
int main(){
    int x,y;
    int k1,k2;    
    while(cin>>x>>y){
        k1=x;
        k2=y;
        while(k1!=k2){
            if(k1>k2){
                k1=k1/2;
            }else if(k1<k2){
                k2=k2/2;
            }        
        }
        cout<<k2<<endl;
    }
    return 0;
}
发表于 2018-12-30 11:19:41 回复(0)
try:
    while True:
        a,b = list(map(int,input().split()))
        while a != b:
            if a < b:
                b //= 2
            else:
                a //= 2
        print(a)
except Exception:
    pass
编辑于 2018-10-08 15:32:34 回复(0)
先判断两个节点是否在同一层,不是的话,让下面的节点往上走,直到在同一层。如果此时已经两个节点相等,直接返回结果。否则,让两个节点同时往上走,直到相遇。
简单做法当然就是直接让大数除2,直到相遇。

import java.util.*;
 
public class Main {
    public static double getLevel(int a)  {
        return Math.log(a)/Math.log(2);
    }
    
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        while (reader.hasNext()) {
            int x = reader.nextInt();
            int y = reader.nextInt();
            int levelx = (int)getLevel(x);
            int levely = (int)getLevel(y);
            while (levelx != levely) {
                if (levelx > levely) {
                    x /= 2;
                    levelx = (int)getLevel(x);
                } else {
                    y /= 2;
                    levely = (int)getLevel(y);
                }
            }
            while (x != y && x > 1 && y > 1) {
                x = x / 2;
                y = y / 2;
            }
            System.out.println(x);
        }
    }
}

编辑于 2018-04-28 18:27:20 回复(1)
还以为是一个二叉树的题目。。。没想到只是一个找规律的题。。。
思路如下:
1.输入n1和n2要确保n1是较大的,如果n2>n1则需要交换
2.获取n1和n2一开始所在层数:
        设置一个从0开始的for循环,当满足2^(i+1)-1>=n>=2^i时获取i并退出。
3.使得n1和n2一开始在同一层:
        设置一个循环,以n1_depth和n2_depth不相等为循环可执行条件,在循环中使n1_depth每次减1,n1每次除以2(n1/2就是向上走一层)
4.获取公共父结点:
        设置一个循环,以n1和n2不相等为可执行条件,循环中两者都除以2(也就是都往上一层,直到相等)

还有就是注意输入组数,使用while(cin>>n1>>n2)

这个应该算入门题目,中等也太看得起了。
// write your code here cpp
#include<iostream>
#include<cmath>
using namespace std;
int get_depth(int n1){
    //得到当前数字所在的层数,用于n1
    for(int i=0;;++i){
        if(n1>=pow(2, i)&&n1<=pow(2,i+1)-1)
            return i;
    }
    return -1;//-1代表出错
}
void makeSameDepth(int &n1,int &n2){
    //n1>=n2
    //使得n1和n2在同一层
    int n1_depth=get_depth(n1);
    int n2_depth=get_depth(n2);
    while(n1_depth!=n2_depth){
        //n2是在上面的,因此n1要往上走
        n1_depth--;
        n1/=2;
    }
}
int main(){
    int n1,n2;
   while(cin>>n1>>n2){
       //确保n1最大
    if(n2>n1)swap(n1, n2);
    //令n1和n2位于同一层,再两者一起除以2直到相等
    makeSameDepth(n1, n2);
    while(n1!=n2){
        n1/=2;n2/=2;
    }
    cout<<n1<<endl; 
   } 
   
    return 0;
    
}

喜欢的话记得点个赞哈~ 考研之路我们一起努力
发表于 2021-03-22 16:59:47 回复(0)
#include<stdio.h>
int main()
{
    int x,y;
    while(scanf("%d%d",&x,&y)!=EOF)
    {
        while(x!=y)//一直循环到相等为止
        {
            if(x>y)//大的数要找上一个节点
                x/=2;
            else
                y/=2;
        }
        printf("%d\n",x);
    }
}

发表于 2020-04-23 14:04:45 回复(0)
#include <iostream>
#include <cmath>
using namespace std;
int main(){
    int x,y;
    while(cin>>x>>y){
        int ma=x>y? x:y;    int mi=x<y? x:y;
        while(ma>mi)
            ma/=2;
        if(ma==mi)    cout<<mi<<endl;
        else{    //    统一层数再同时往下找
            if(floor(log(ma)/log(2))!=floor(log(mi)/log(2)))
                mi/=2;
            while(ma!=mi){
                mi/=2;    ma/=2;
            }
            cout<<ma<<endl;
        }
    }
    return 0;
}
编辑于 2019-03-23 00:01:12 回复(0)
while True:
    try:
        x,y=list(map(int,raw_input().strip().split()))
        while True:
            if x==y:
                break
            elif x>y:
                x//=2
            else:
                y//=2
        print(x)
    except:
        break
发表于 2018-05-30 11:14:02 回复(0)
#include<stdio.h>
int main(){
    int a,b;
    while(scanf("%d%d",&a,&b)!=EOF){
        while(a-b)
            if(a>b) a/=2;
            else b/=2;
        printf("%d\n",a);
    }
}

发表于 2017-11-06 16:28:11 回复(0)
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<functional>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <exception>
#include <iomanip>
#include <memory>
#include <sstream>

#define INF 1000000
using namespace std;

int main(int argc, char** argv)
{
	//freopen("in.txt", "r", stdin);
	int m,n;
	while (cin >> m >> n)
	{
		while (m != n)
		{
			if (m > n) m >>= 1;
			else n >>= 1;
		}

		cout << m << endl;
	}

	return 0;
}

发表于 2017-07-11 22:40:13 回复(0)
#include <iostream>
#include <vector>
#include <algorithm>
//思路:完全二叉树子节点x的父节点编号一定为x/2
using namespace std;
int main()
{
  int x = 0,y = 0;
  while(cin >> x >>y)
  {
      
/*
      vector<int> vec;
      int a = max(x,y);
      int b = min(x,y);
      while(a != 0)
      {
          vec.push_back(a);
          a /= 2;
      }
      
      while(b != 0)
      {   
          int i =0;
          for( ;i<vec.size();i++)
          {
              if(vec[i] == b)
              {
                  cout << vec[i] << endl;
                  break;
              }
          }
          if(i != vec.size())
          {
              break;
          }
          b /= 2;
      }
      if(b==0)
      {
          cout << 1 <<endl;
      }
      
*/
      while(x != y)
      {
          if(x > y)
          {
              x /= 2;
          }
          else
          {
              y /= 2;
          }
      }
      cout << (x ==0 ? 1 : x) <<endl; 
  }
}
发表于 2017-03-04 22:15:23 回复(0)
#include<iostream>
using namespace std;
int PubParent(int x,int y){
	if(x == y)
		return x;
	else if(x == (y+1) && y == (x+1))
		return x/2;
	else{
		if(y>x)
			return PubParent(x,y/2);
		else
			return PubParent(x/2,y);
	}
}

int main(){
	int x,y;
	while(scanf("%d %d",&x,&y)!=EOF)
		cout<<PubParent(x,y)<<endl;
	return 0;
}

发表于 2016-12-08 21:51:59 回复(0)
#include<iostream>
#include<deque>
using namespace std;
int main()
{
int a,b;
while(cin>>a>>b)
{
deque<int> d1;
while(a!=0)
{
d1.push_back(a);
a=a/2;
}
int flag=0;
    while(b!=0)
{
for(int i=0;i<d1.size();i++)
{
if(d1[i]==b)
{
flag=1;
cout<<b<<endl;
break;
}
if(d1[i]<b)
break;
}
if(flag==1)
break;
b=b/2;
}
}
return 0;
}
发表于 2016-11-27 15:30:55 回复(0)
这一题比较简单,由于二叉树很规则,完全二叉树,父子节点之间关系很明确,通过子节点不断遍历得到父节点,递归调用更好。
但是看了第一个答案,瞬间感觉高大上!很佩服,思路非常好。我使用java把两种解法都给出啦。
解法一
import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		/****************************解法一******************************/
		Scanner scanner = new Scanner(new BufferedInputStream(System.in));
		while (scanner.hasNext()) {
			int node1=scanner.nextInt();
			int node2=scanner.nextInt();
			ArrayList<Integer> list1=new ArrayList<>();
			GetParentNodeList(node1, list1);
			ArrayList<Integer> list2=new ArrayList<>();
			GetParentNodeList(node2, list2);
			int last=0;
			if (list1.size()>list2.size()) {
				for (int i = 0; i<list2.size(); i++) {
					if (list1.contains(list2.get(i))) {
						last=list2.get(i);
						break;
					}
				}
			}else {
				for (int i = 0; i<list1.size(); i++) {
					if (list2.contains(list1.get(i))) {
						last=list1.get(i);
						break;
					}
				}
			}
			System.out.println(last);
		}
		scanner.close();
	}
	
	private static List<Integer> GetParentNodeList(int node,List<Integer> list) {
		if (node==1) {
			list.add(1);
			return list;
		}else {
			list.add(node);
			list=GetParentNodeList(node/2, list);
		}
		return list;
	}
}

解法二
import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		/****************************解法二******************************/
		Scanner scanner = new Scanner(new BufferedInputStream(System.in));
		while (scanner.hasNext()) {
			int node1=scanner.nextInt();
			int node2=scanner.nextInt();
			while(node1!=node2){
				if (node1>node2) {
					node1/=2;
				}else {
					node2/=2;
				}
			}
			System.out.println(node1);
		}
		scanner.close();
	}
}

发表于 2016-09-08 15:38:42 回复(0)
设子节点序号为x,因为是完全二叉树,所以其父节点序号为int(x/2);
则有以下程序实现公共祖先节点
#include<stdio.h>
 
int main()
{
    int x,y;
    while(scanf("%d%d",&x,&y) != EOF){
        while(x != y){
            if(x<y){
                y = y/2;
            }else{
                x = x/2;
            }
        }
        printf("%d\n",x);
    }
    return 0;   
}  

发表于 2015-10-27 19:58:54 回复(5)
#include <iostream>
#include <stack>
using namespace std;

int main() {
    int x, y;
    while (cin >> x >> y) {
        stack<int>s1, s2;   //用堆栈存储x和y结点到根结点的路径
        while (x) {
            s1.push(x); //路径结点入栈
            x /= 2;     //追溯父节点
        }
        while (y) {
            s2.push(y); //路径结点入栈
            y /= 2;     //追溯父节点
        }
        int father = 1; //公共父节点
        //逆向遍历路径,找第一个非公共父节点,其前面一个结点即为首个公共父节点
        while (!s1.empty() && !s2.empty() && s1.top() == s2.top()) {
            father = s1.top();  //访问栈顶元素
            s1.pop();           //出栈
            s2.pop();           //出栈
        }
        cout << father << endl;
    }
    return 0;
}

发表于 2024-01-31 14:31:22 回复(0)
help!!!!本地测的结果没错 提交的时候总是前三个变成0了
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    long long x,y;

    while(scanf("%lld %lld",&x,&y)!=EOF)
    {
        vector<long long> a,b;
        a.push_back(x);
        b.push_back(y);
        while(x!=1) {
            x/=2;
            a.push_back(x);
        }
        while(y!=1) {
            y/=2;
            b.push_back(y);
        }
        long long gg=1;

        for(unsigned long long i=a.size()-1,j=b.size()-1;i>=0,j>=0;i--,j--){
            if(a[i]==b[j]) {
               gg=a[i];

            }
            if(a[i]!=b[j]) break;

        }
        printf("%lld ",gg);

    }
    return 0;
}

发表于 2023-03-25 20:28:43 回复(0)
//先让两个节点在同一层,在向上找父亲节点。但是应该直接大的除二,看与小的是否相等,不断循环。
//对二叉树的理解还是不深
#include "stdio.h"
#include "math.h"
int finHeight(int x){
    int height = 1;
    while (true){
        if(x >= pow(2,height-1) && x <= pow(2,height)-1)
            return height;
        else
            ++height;
    }
}

int main(){
    int x,y;int num_max,num_min;
    while (scanf("%d%d",&x,&y)!=EOF){
        int height_x = finHeight(x);
        int height_y = finHeight(y);
        int bigH = height_x>height_y?height_x:height_y;
        int minH = height_x<height_y?height_x:height_y;
        if(height_x == bigH){
            num_max = x;
            num_min = y;
        } else{
            num_max = y;
            num_min = x;
        }
        while (bigH != minH){//二者同一层
            num_max = num_max/2;
            --bigH;
        }
        while (num_max != num_min){
            num_max = num_max/2;
            num_min = num_min/2;
        }
        printf("%d\n",num_max);
    }
}

发表于 2023-03-08 18:03:48 回复(0)
#include <cstdio>

int main()
{
    int x, y;
    while (scanf("%d %d", &x, &y) != EOF)
    {
        while (true)
        {
            if (x == y)
                break;
            else if (x > y)
                x /= 2;
            else 
                y /= 2;
        } 
        printf("%d\n", x);
    }
    return 0;
}

发表于 2022-03-17 10:18:06 回复(0)