二叉搜索树和双向链表(剑指offer-36)

1、题目描述

    输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

2、解题思路

    一棵二叉搜索树,按照中序遍历为一个有序序列。我们可以按照中序遍历的思想,当我们遍历根节点时,先将左子树转换成一个有序链表,然后再将右子树转换成一个有序链表,接着用根节点将左子树和右子树串联起来。这是一个递归的过程,递归函数需要求出左子树的有序链表的头尾节点和右子树有序链表的头尾节点,然后修改节点的指针,串联在一起。代码如下:

struct TreeNode {
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}	
};

void conv(TreeNode *&head, TreeNode *&tail, TreeNode *root) {
	TreeNode *left_head = nullptr;                  //左子树头节点
	TreeNode *left_tail = nullptr;                  //左子树尾节点
	TreeNode *right_head = nullptr;                 //右子树头节点
	TreeNode *right_tail = nullptr;                 //右子树尾节点
	if (root->left == nullptr) {
		head = root;
	}
	else
		conv(left_head, left_tail, root->left);      //左子树不为空,则递归左
	if (root->right == nullptr) {
		tail = root;
	}
	else
		conv(right_head, right_tail, root->right);  //右子树不为空,则递归右

	if (head == nullptr) {		                    //调整左子树有序链表指针    
		left_tail->right = root;
		root->left = left_tail;
		head = left_head;
	}
	if (tail == nullptr) {                          //调整右子树有序链表指针
		root->right = right_head;
		right_head->left = root;
		tail = right_tail;
	}
}

TreeNode* Convert(TreeNode* pRootOfTree)
{
	TreeNode *head = nullptr;
	TreeNode *tail = nullptr;
	conv(head, tail, pRootOfTree);
	return head;

}

int main() {
	TreeNode *node10 = new TreeNode(10);         //创建二叉搜索树
	TreeNode *node6 = new TreeNode(6);
	TreeNode *node4 = new TreeNode(4);
	TreeNode *node8 = new TreeNode(8);
	TreeNode *node14 = new TreeNode(14);
	TreeNode *node12 = new TreeNode(12);
	TreeNode *node16 = new TreeNode(16);
	node10->left = node6;
	node10->right = node14;
	node6->left = node4;
	node6->right = node8;
	node14->left = node12;
	node14->right = node16;
	Convert(node10);                            //进行转换
	return 0;
}

3、函数的引用传递和指针传递

(1)引用传递

    当我们在函数中需要修改外部变量的值的时候,我们通常需要将变量的引用传递进去,此时修改的就是原变量的值:

  • 修改普通变量
void test(int &a) {
	a = 5;
}

int main() {
	int a = 10;
	cout << a << endl;
	test(a);
	cout << a << endl;
	return 0;
}

输出:
10
5
  • 修改指针变量
void test(int *&a) {
	int c = 5;
	a = &c;
}

int main() {
	int a = 10;
	int *b = &a;
	cout << *b << endl;
	test(b);
	cout << *b << endl;
	return 0;
}

输出:
10
5

注:如果我们只传递变量名到函数中,无论指针变量还是普通变量,那么我们是不能在函数中修改这个变量的值的。 如果我们传入变量的引用,那么我们可以修改这个变量的值。

(2)指针传递

    出了引用传递可以修改外部变量的值外,传递变量的地址也可以修改外部变量的值。如果我们要修改普通变量的值,则我们需要传入普通变量的地址,如果我们要修改指针变量的值,那么我们需要传入指针变量的地址,即指针的指针。

  • 修改普通变量:
void test(int *a) {
	*a = 5;
}

int main() {
	int a = 10;
	cout << a << endl;
	test(&a);
	cout << a << endl;
	return 0;
}
输出:
10
5
  • 修改指针变量:
void test(int **a) {
	int c = 5;
	*a = &c;
}

int main() {
	int a = 10;
	int *b = &a;
	cout << *b << endl;
	test(&b);
	cout << *b << endl;
	return 0;
}
输出:
10
5

 

点赞