欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java二叉樹面試題詳解

 更新時間:2021年07月19日 11:08:50   作者:吾仄lo咚鏘  
下面小編就為大家?guī)硪黄猨ava二叉樹的幾道面試題詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

二叉樹的深度

題目:輸入一顆二叉樹的根節(jié)點,求該樹的的深度。輸入一顆二叉樹的根節(jié)點,求該樹的深度。從根節(jié)點到葉節(jié)點依次經(jīng)過的節(jié)點(含根、葉節(jié)點)形成的一條路徑,最長路徑的長度為樹的深度。

如果一棵樹只有一個節(jié)點,那么它的深度是1.如果根節(jié)點只有左子樹,那深度是其左子樹的深度+1,同樣的只有右子樹的話,深度是其右子樹深度+1,如果既有左子樹又有右子樹,取兩個子樹的深度最大值+1即可。用遞歸很容易實現(xiàn)。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l=nullptr, node* r=nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
int getDepth(node* root) {//獲取樹深度
	if (root == nullptr)
		return 0; //為空返回0
	int l = getDepth(root->left);//左子樹深度
	int r = getDepth(root->right);//右子樹深度
	return max(l, r) + 1;//取最大的+1
}
int main() {
	node* root = new node(1);//構(gòu)建一顆二叉樹
	node* l1 = root->left = new node(2);
	node* r1 = root->right = new node(3);
	l1->left = new node(4);
	l1->right = new node(5);
	r1->left = new node(6);
	r1->right = new node(7);
	printf("%d", getDepth(root));
	return 0;
}
//運行結(jié)果:3

運行結(jié)果:

3

二叉搜索樹的第k大節(jié)點

題目:給定一顆二叉搜索樹,找出其中第k大節(jié)點。注意二叉搜索樹中,左節(jié)點比根節(jié)點小,右節(jié)點比根節(jié)點大。

對于二叉搜索樹來說,它的中序遍歷就是從小到大遞增的序列,因此只需要對二叉搜索樹中序遍歷,就能很容易找到它的第k大節(jié)點。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l=nullptr, node* r=nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
node* Kth(node* root, int &k) {
	node* ans = nullptr;
	if (root->left != nullptr)
		ans = Kth(root->left, k);
	if (ans == nullptr) {
		if (k == 1)
			ans = root;
		k--;
	}
	if (root->right != nullptr && ans == nullptr)
		ans = Kth(root->right, k);
	return ans;
}
node* check(node* root, int k) {//遞歸前先判斷極端條件
	if (k <= 0 || root == nullptr)
		return nullptr;
	return Kth(root, k);
}
int main() {
	node* root = new node(4);//構(gòu)建一顆二叉搜索樹
	node* l1 = root->left = new node(2);
	node* r1 = root->right = new node(6);
	l1->left = new node(1);
	l1->right = new node(3);
	r1->left = new node(5);
	r1->right = new node(7);
	node* test = check(root, 1);
	printf("第一個節(jié)點:%d\n", test == nullptr ? -1 : test->val);
	test = check(root, 5);
	printf("第五個節(jié)點:%d\n", test == nullptr ? -1 : test->val);
	return 0;
}

運行結(jié)果:

第一個節(jié)點:1 第五個節(jié)點:5

從上到下打印二叉樹

題目:不分行從上到下打印二叉樹。從上到下打印二叉樹的那個節(jié)點,同一層的節(jié)點按照從左到右的順序打印。

在這里插入圖片描述

不同于熟悉的前中后序遍歷或按層遍歷。每次打印一個節(jié)點的時候,如果該節(jié)點有子節(jié)點,則把該子節(jié)點放到一個隊列的隊尾。接下來到隊列的頭部取出最早進入隊列的幾點,重復(fù)前面的打印操作,直到隊列中所有節(jié)點都被打印出來。即就是一個bfs。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l=nullptr, node* r=nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
void PrintFromTopToBottom(node* root) {//從上到下打印
	if (root == nullptr)return;
	queue<node*>q;
	q.push(root);
	while (!q.empty()) {
		node* cur = q.front();
		q.pop();
		printf("%d ", cur->val);
		if (cur->left != nullptr)//從左到右
			q.push(cur->left);
		if (cur->right != nullptr)
			q.push(cur->right);
	}
	printf("\n");
}
int main() {
	node* root = new node(1);//構(gòu)建一顆二叉樹
	node* l1 = root->left = new node(2);
	node* r1 = root->right = new node(3);
	l1->left = new node(4);
	l1->right = new node(5);
	r1->left = new node(6);
	r1->right = new node(7);
	PrintFromTopToBottom(root);//調(diào)用
	return 0;
}

運行結(jié)果:

1 2 3 4 5 6 7

二叉樹的鏡像

題目:輸入一顆二叉樹,輸出它的鏡像。

在這里插入圖片描述

通過畫圖分析,兩棵樹根節(jié)點相同,但左右子節(jié)點交換了位置,現(xiàn)在交換左右子節(jié)點,然后發(fā)現(xiàn)這兩個節(jié)點的左右子節(jié)點位置還是不同,如此遞歸下去一直交換即可。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l=nullptr, node* r=nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
void PrintFromTopToBottom(node* root) {//從上到下打印
	if (root == nullptr)return;
	queue<node*>q;
	q.push(root);
	while (!q.empty()) {
		node* cur = q.front();
		q.pop();
		printf("%d ", cur->val);
		if (cur->left != nullptr)//從左到右
			q.push(cur->left);
		if (cur->right != nullptr)
			q.push(cur->right);
	}
	printf("\n");
}
void Mirror(node* root) {//鏡像二叉樹
	if (root == nullptr)
		return;
	if (root->left == nullptr && root->right == nullptr)
		return;
	swap(root->left, root->right);//交換左右子節(jié)點
	Mirror(root->left);//遞歸下去
	Mirror(root->right);
}
int main() {
	node* root = new node(1);//構(gòu)建一顆二叉樹
	node* l1 = root->left = new node(2);
	node* r1 = root->right = new node(3);
	l1->left = new node(4);
	l1->right = new node(5);
	r1->left = new node(6);
	r1->right = new node(7);
	PrintFromTopToBottom(root);
	Mirror(root);
	PrintFromTopToBottom(root);
	return 0;
}

運行結(jié)果:

1 2 3 4 5 6 7 1 3 2 7 6 5 4

對稱的二叉樹

題目:實現(xiàn)一個函數(shù),用來判斷一顆二叉樹是不是對稱的。如果一顆二叉樹和它的鏡像一樣,那么它就是對稱的。

在這里插入圖片描述

在三種遍歷方法中(前序、中序和后序)都是先遍歷左節(jié)點在遍歷右節(jié)點,如果我們先遍歷右節(jié)點再遍歷左節(jié)點,然后再和前序的先左后右比較,就可以判斷是否對稱了。

比如第一棵樹前序先左后右:{1,2,3,2,4,3},前序先右后左:{1,2,3,4,2,4,3},兩序列一樣,即可判為對稱。

如第二棵樹前序先左后右:{1,2,3,4,2,4,5},前序先右后左:{1,2,5,4,2,4,3},兩序列不同,即不對稱。

但注意第三棵樹情況,兩者都是{1,2,2,2}但明顯是不對成的,故需要加上空指針來判斷。前序先左后右:{1,2,2,null,null,2,null,null},前序先右后左:{1,2,null,null,2,null,2},然后判斷為不對稱。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l=nullptr, node* r=nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
bool isSymmetrical(node* r1, node* r2) {//即兩棵樹是否互為鏡像
	if (r1 == nullptr && r2 == nullptr)
		return true;
	if (r1 == nullptr || r2 == nullptr)
		return false;
	if (r1->val != r2->val)
		return false;
	return isSymmetrical(r1->left, r2->right)
		&& isSymmetrical(r1->right, r2->left);
}
bool isSymmetrical(node* root) {//判斷一棵樹是否對稱
	return isSymmetrical(root, root);
}
int main() {
	node* root = new node(1);//構(gòu)建一顆對稱二叉樹
	node* l1 = root->left = new node(2);
	node* r1 = root->right = new node(2);
	l1->left = new node(3);
	l1->right = new node(4);
	r1->left = new node(4);
	r1->right = new node(3);
	if (isSymmetrical(root))
		printf("對稱");
	else 
		printf("不對稱");
	return 0;
}

運行結(jié)果:

對稱

樹的子結(jié)構(gòu)

題目:輸入兩顆二叉A和B,判斷B是不是A的子結(jié)構(gòu)。

我們可以分成兩步,首先找到根節(jié)點值一樣的節(jié)點,然后判斷以該節(jié)點為根節(jié)點的子樹是否包含一樣的結(jié)構(gòu)。其實主要還是考察樹的遍歷,用遞歸即可完成。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l=nullptr, node* r=nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
bool check(node* r1, node* r2) {
	if (r2 == nullptr)
		return true; //注意空指針
	if (r1 == nullptr)
		return false;
	if (r1->val != r2->val)
		return false;
	return check(r1->left, r2->left) && check(r1->right, r2->right);
}
bool HasSubtree(node* r1, node* r2) {
	bool ans = false;
	if (r1 != nullptr && r2 != nullptr) {
		if (r1->val == r2->val) //找到值相同的節(jié)點
			ans = check(r1, r2);//然后判斷是否包含一樣結(jié)構(gòu)
		if (ans == false) //剪枝,是子結(jié)構(gòu)就不必再繼續(xù)找了
			ans = HasSubtree(r1->left, r2);
		if (ans == false)
			ans = HasSubtree(r1->right, r2);
	}
	return ans;
}
int main() {
	node* root = new node(1);//構(gòu)建一顆二叉樹
	node* l1 = root->left = new node(2);
	node* r1 = root->right = new node(1);
	l1->left = new node(4);
	l1->right = new node(3);
	r1->left = new node(2);
	r1->right = new node(3);
	node* part = new node(1);//構(gòu)建子樹
	part->left = new node(2);
	part->right = new node(3);
	if (HasSubtree(root, part))
		printf("是子樹");
	else
		printf("不是子樹");
	return 0;
}

運行結(jié)果:

是子樹

重建二叉樹

題目:輸入某二叉樹的前序遍歷和中序遍歷結(jié)果,請重建該二叉樹,假設(shè)輸入的前序遍歷和中序遍歷的結(jié)果中不含重復(fù)的數(shù)字。

在前序遍歷中,第一個數(shù)字總是樹的根節(jié)點的值,而在中序遍歷中,根節(jié)點的值在序列中間,左子樹節(jié)點的值位于根節(jié)點值得左邊,右子樹節(jié)點的值位于根節(jié)點值得右邊,因此需要掃描中序遍歷序列,才能找到根節(jié)點得值。

在這里插入圖片描述

分別找到左、右子樹的前序和中序遍歷序列后,我們可以用同樣的方法分別構(gòu)建左右子樹,即可以用遞歸完成。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l=nullptr, node* r=nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
//四個參數(shù):前序開始位置、前序結(jié)束位置、中序開始位置、中序結(jié)束位置
node* Construct(int* startPre,int* endPre,int* startIn,int* endIn) {//根據(jù)前中序建樹
	int rootVal = startPre[0];//根節(jié)點是前序遍歷第一個
	node* root = new node(rootVal);
	if (startPre == endPre) { //遞歸出口:只一個節(jié)點
		if (startIn == endIn && *startPre == *startIn)
			return root;
		//else throw exception();//若輸入不確保正確則拋出異常
	}
	int* rootIn = startIn; //在中序遍歷中找到根節(jié)點的值
	while (rootIn <= endIn && *rootIn != rootVal)
		rootIn++;
	//if (rootIn == endIn && *rootIn != rootVal)
	//	throw exception();//找不到拋異常
	int leftLen = rootIn - startIn;//左子樹長度
	int* leftPreEnd = startPre + leftLen;
	if (leftLen > 0) { //構(gòu)建左子樹
		root->left = Construct(startPre + 1, leftPreEnd, startIn, rootIn - 1);
	}
	if (leftLen < endPre - startPre) {//構(gòu)建右子樹
		root->right = Construct(leftPreEnd + 1, endPre, rootIn + 1, endIn);
	}
	return root;
}
void post(node* root) {//后序遍歷打印
	if (root == nullptr)return;
	post(root->left);
	post(root->right);
	printf("%d ", root->val);
}
int main() {
	int pre[10] = { 1,2,4,3,5,7,6,8 };
	int in[10] = { 2,4,1,7,5,3,6,8 };
	node* p = Construct(pre, pre + 7, in, in + 7);
	post(p);//打印后序檢查
	return 0;
}

運行結(jié)果:

4 2 7 5 8 6 3 1

二叉樹的下一個節(jié)點

題目:給定一顆二叉樹和其中一個節(jié)點,如何找出中序遍歷序列的下一個節(jié)點?樹中的節(jié)點除了有兩個分別指向左右節(jié)點的指針,還有一個指向父節(jié)點的指針。

其實是考察對中序遍歷的理解。首先向下考慮,中序遍歷中它的下一個節(jié)點不可能在左子樹中考慮,所以如果一個節(jié)點有右子樹,那么它的下一個節(jié)點就是它右子樹中的最左節(jié)點。

其次向上考慮(即無右子樹),如果節(jié)點是它父節(jié)點的左子節(jié)點,那么它的下一個節(jié)點就是它的父節(jié)點。如果節(jié)點是它父節(jié)點的右子節(jié)點,這時就需要沿著指向父節(jié)點的指針一直向上遍歷,直到找到一個是它父節(jié)點的左子節(jié)點的節(jié)點。如果存在則這個節(jié)點的父節(jié)點是答案,否則他就是最后一個節(jié)點,無下一個節(jié)點。

同樣的前序、后序的下一個節(jié)點同理,舉一反三。

在這里插入圖片描述

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node* parent;//父節(jié)點
	node(int v,node*p=nullptr) {
		val = v;
		left = nullptr;
		right = nullptr;
		parent = p;
	}
};
node* getnext(node* p) {
	if (p == nullptr)
		return nullptr;
	node* next = nullptr;
	if (p->right != nullptr) {//有右子樹
		node* r = p->right;//找最左
		while (r->left != nullptr)
			r = r->left;
		next = r;
	}
	else if(p->parent!=nullptr){//無右子樹且有父節(jié)點
		node* cur = p;
		node* par = p->parent;
		while (par != nullptr && cur == par->right) {
			cur = par; //向上找到一個節(jié)點是它父節(jié)點的左節(jié)點
			par = par->parent;
		}
		next = par;
	}
	return next;
}
int main() {
	node* root = new node(1);//建樹
	node* p2 = new node(2,root);
	node* p4 = new node(4, p2);
	p2->right = p4;
	node* p7 = new node(7, p4);
	node* p8 = new node(8, p4);
	p4->left = p7, p4->right = p8;
	node* p3 = new node(3, root);
	root->left = p2, root->right = p3;
	node* p5 = new node(5, p3);
	node* p6 = new node(6, p3);
	p3->left = p5, p3->right = p6;
	node* test = getnext(p4);
	printf("節(jié)點4的下一個節(jié)點:%d\n", test == nullptr ? -1 : test->val);
	test = getnext(p5);
	printf("節(jié)點5的下一個節(jié)點:%d\n", test == nullptr ? -1 : test->val);
	test = getnext(p8);
	printf("節(jié)點8的下一個節(jié)點:%d\n", test == nullptr ? -1 : test->val);
	test = getnext(p6);
	printf("節(jié)點6的下一個節(jié)點:%d\n", test == nullptr ? -1 : test->val);
	return 0;
}

運行結(jié)果如下:

節(jié)點4的下一個節(jié)點:8 節(jié)點5的下一個節(jié)點:3 節(jié)點8的下一個節(jié)點:1 節(jié)點6的下一個節(jié)點:-1

二叉搜索樹的后序遍歷路徑

題目:輸入一個整數(shù)數(shù)組,判斷該數(shù)組是不是某二叉搜索樹的后序遍歷結(jié)果。假設(shè)輸入的數(shù)組任意兩個數(shù)字不相同。

在后序遍歷中,最后一個節(jié)點是根節(jié)點,而且因為是二叉搜索樹,左子樹比它小,右子樹比它大,所以又可以劃分出左右子樹兩部分,然后在劃分出來的子樹中,同樣是最后一個是根節(jié)點,遞歸處理即可。

其實通過二叉搜索樹隱含條件來判斷,相當于給一個二叉樹的后序和中序求是否能建樹,同前面重建二叉樹那題,換湯不換藥。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l = nullptr, node* r = nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
bool verify(int s[], int len) {
	if (len <= 0 || s == nullptr)
		return false;
	int root = s[len - 1];//根節(jié)點
	int i = 0;
	while (i < len - 1) {//找左子樹中小于根節(jié)點的值
		if (s[i] > root)
			break;
		i++;
	}
	int j = i;
	while (j < len - 1) {
		if (s[j++] < root)
			return false;
	}
	bool l = true, r = true;
	if (i > 0)//驗證左子樹
		l = verify(s, i);
	if (i < len - 1)//驗證右子樹
		r = verify(s + i, len - i - 1);
	return (l && r);
}
int main() {
	int a[10] = { 1,3,2,5,7,6,4 };
	printf("數(shù)組a%s二叉搜索樹的后序序列\(zhòng)n", verify(a,7) ? "是" : "不是");
	int b[10] = { 3,4,1,2 };
	printf("數(shù)組b%s二叉搜索樹的后序序列\(zhòng)n", verify(b, 4) ? "是" : "不是");
	return 0;
}

運行結(jié)果如下:

數(shù)組a是二叉搜索樹的后序序列數(shù)組b不是二叉搜索樹的后序序列

二叉樹中和為某一值的路徑

題目:輸入一顆二叉樹和一個整數(shù),打印出二叉樹中節(jié)點值的和為輸入整數(shù)的所有路徑。從樹的根節(jié)點開始往下一直到葉節(jié)點所經(jīng)過的節(jié)點形成一條路徑。

首先由于路徑的定義是從根節(jié)點到葉節(jié)點,而只有前序遍歷中是先訪問根節(jié)點的。當前序遍歷訪問到某一節(jié)點時,我們把該節(jié)點添加到路徑上,并累加該節(jié)點的值。如果節(jié)點是葉節(jié)點,此時判斷累加值是否符合輸入整數(shù),符合則打印出路徑。當訪問結(jié)束后,要在路徑上刪除該節(jié)點,并減去該節(jié)點的值。即一個簡單的dfs。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l = nullptr, node* r = nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
void dfs(node* root, vector<int>path,int sum,int cur) {
	if (root == nullptr)
		return;
	cur += root->val;
	path.push_back(root->val);
	if (cur == sum && root->left == nullptr && root->right == nullptr) {
		//值相同且是葉節(jié)點
		for (int i = 0; i < path.size(); i++)
			printf("%d ", path[i]);
		printf("\n");
	}
	dfs(root->left, path, sum, cur);
	dfs(root->right, path, sum, cur);
	path.pop_back();//回溯
}
int main() {
	node* root = new node(10);
	node* l = root->left = new node(3);
	root->right = new node(5);
	l->left = new node(-2);
	l->right = new node(2);
	vector<int>v;
	dfs(root, v, 15, 0);
	return 0;
}

運行結(jié)果如下:

10 3 2 10 5

二叉搜索樹與雙向鏈表

題目:輸入一顆二叉搜索樹,將該二叉樹轉(zhuǎn)換成一個排序的雙向鏈表。要求不能創(chuàng)建任何新的節(jié)點,只能調(diào)整書中節(jié)點指針的指向。

在這里插入圖片描述

二叉搜索樹的左節(jié)點小于父節(jié)點,右節(jié)點大于父節(jié)點,所以可以將原先指向左子節(jié)點的指針調(diào)整為列表中指向前一個節(jié)點的指針,原先指向右節(jié)點的指針調(diào)整為指向后一個節(jié)點的指針。

由于轉(zhuǎn)換后的鏈表是排好序的,所以我們可以中序遍歷樹的節(jié)點,當遍歷到根節(jié)點是,可以把樹拆成三部分,4號節(jié)點、根節(jié)點為2的左子樹、根節(jié)點為6的右子樹。同時根據(jù)定義,將它與左子樹最大節(jié)點鏈接起來,與右子樹最小節(jié)點鏈接起來。而此時的左子樹儼然就是一個排序的鏈表,接著去遍歷右子樹即可,可不還是遞歸嗎。

#include<bits/stdc++.h>
using namespace std;
struct node {//樹節(jié)點定義
	int val;
	node* left;//左子節(jié)點
	node* right;//右子節(jié)點
	node(int v, node* l = nullptr, node* r = nullptr) {
		val = v;
		left = l;
		right = r;
	}
};
void dfs(node* p, node** t) {
	if (p == nullptr)
		return;
	node* cur = p;//備份
	if (cur->left != nullptr)//中序
		dfs(cur->left, t);
	cur->left = *t;//根節(jié)點左指針指向左子樹最后一個節(jié)點
	if (*t != nullptr)
		(*t)->right = cur;//左子樹最后一個節(jié)點右指針指向根節(jié)點
	*t = cur;//更新最后一個節(jié)點
	if (cur->right != nullptr)
		dfs(cur->right, t);
}
node* toList(node* root) {
	node* tail = nullptr;//指向雙向鏈表尾節(jié)點
	dfs(root, &tail);
	node* head = tail; //頭節(jié)點
	while (head != nullptr && head->left != nullptr)
		head = head->left; //left指向前一個
	return head;
}
int main() {
	node* root = new node(4);//構(gòu)建一顆二叉搜索樹
	node* l = root->left = new node(2);
	l->left = new node(1);
	l->right = new node(3);
	node* r = root->right = new node(6);
	r->left = new node(5);
	r->right = new node(7);
	node* list = toList(root);
	while (list->right != nullptr) {
		printf("%d ", list->val);
		list = list->right;
	}
	printf("%d\n",list->val);
	while (list != nullptr) {
		printf("%d ", list->val);
		list = list->left;
	}
	return 0;

運行結(jié)果:

1 2 3 4 5 6 7 7 6 5 4 3 2 1

總結(jié)

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

最新評論