【微软100题】001把二元查找树转变成排序的双向链表(树)

时间:2022-09-13 22:08:58
/**
 * 题目:
 * 1.把二元查找树转变成排序的双向链表(树)
 题目:
 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
 要求不能创建任何新的结点,只调整指针的指向。
 10
 / /
 6  14
 / / / /
 4  8 12 16
 转换成双向链表
 4=6=8=10=12=14=16。
 */

/*
 * 想法:如果采用中序遍历,那么就是从小到大排序的输出,但是这里要求不能创建任何新的节点,只能调整指针的指向
 * 每遍历一个节点,实际上要做两件事:①让前一个节点的右指针指向当前节点 ②让当前节点的左指针指向前一个节点
 *
 * 那么势必要记录前一个节点,而且还需要处理头指针的问题
 *
 * 骨架为中序遍历,但是在之前输出中序遍历值的位置,并不是输出值,而是做上面①和②两点的操作
 *
 */

#include <iostream>
#include <stack>

using namespace std;

/*
 * 类的成员变量以m_开头
 */
struct BSTreeNode {

	int m_iValue;
	BSTreeNode* m_pLeft;
	BSTreeNode* m_pRight;

	BSTreeNode(int key) :
			m_iValue(key), m_pLeft(), m_pRight() {

	}
};

struct BSTree {

	BSTreeNode* root;

	BSTree() :
			root(NULL) { //初始的时候给一个空指针给root,因为是空树
	}

	void BSTree_Insert(int key); //申明

	void BSTree_Travel_1(BSTreeNode* t);

	void BSTree_Travel_2(BSTreeNode* t);

};

/*
 * 实现插入函数
 */
void BSTree::BSTree_Insert(int key) {

	BSTreeNode* x = this->root;
	BSTreeNode* y = NULL;
	BSTreeNode* n = new BSTreeNode(key);

	while (x != NULL) {

		y = x;
		if (key < x->m_iValue) {
			x = x->m_pLeft;
		} else {
			x = x->m_pRight;
		}
	}

	if (y == NULL) {
		this->root = n;
	} else if (key < y->m_iValue) {
		y->m_pLeft = n;
	} else {
		y->m_pRight = n;
	}

}

//递归中序遍历
void BSTree::BSTree_Travel_1(BSTreeNode* t) {
	if (t != NULL) {
		BSTree_Travel_1(t->m_pLeft);
		cout << t->m_iValue << ' ';
		BSTree_Travel_1(t->m_pRight);
	}
}

//非递归中序遍历
void BSTree::BSTree_Travel_2(BSTreeNode* t) {
	stack<BSTreeNode*> s;
	while (t != NULL || !s.empty()) {
//		if (t != NULL) {
		while (t != NULL) { //这里要用while,因为要一口气将左边的路径上的节点全部入栈
			s.push(t);
			t = t->m_pLeft;
		}

		if (!s.empty()) {
			t = s.top();
			cout << t->m_iValue << ' ';
			s.pop();
			t = t->m_pRight;
		}
	}
}

typedef struct BSTreeNode pDoubleList;

pDoubleList* pHead = NULL;

pDoubleList* pListTmp = NULL;

/*
 * 转换过程
 */
void conversion(BSTreeNode*& pCurrent) {

	pCurrent->m_pLeft = pListTmp; //指向前

	if (pCurrent->m_pLeft != NULL) {
		pCurrent->m_pLeft->m_pRight = pCurrent; //前一个的指向后,也就是指向当前
	} else {
		pHead = pCurrent;
	}

	pListTmp = pCurrent; //决定下一个的指向前目标

}

/*
 * 将二叉搜索树转换为双向链表
 */
pDoubleList* convert_To_Double_List(BSTreeNode* pCurrent) {

	if (pCurrent == NULL) {
		return NULL;
	}

	if (pCurrent->m_pLeft != NULL) {
		convert_To_Double_List(pCurrent->m_pLeft);
	}

	conversion(pCurrent);

	if (pCurrent->m_pRight != NULL) {
		convert_To_Double_List(pCurrent->m_pRight);
	}
	return pHead;
}

/*
 * 简洁版
 */
void change(BSTreeNode *p, BSTreeNode *&last) //中序遍历
		{
	if (!p)					//为空则返回
		return;

	change(p->m_pLeft, last);					//处理左

	if (last)					//处理当前
		last->m_pRight = p;
	p->m_pLeft = last;

	last = p;

	change(p->m_pRight, last);	//处理右
}

int main() {

	pHead = NULL;
	pListTmp = NULL;

	BSTree* bst = new BSTree();

	bst->BSTree_Insert(5);
	bst->BSTree_Insert(8);
	bst->BSTree_Insert(1);
	bst->BSTree_Insert(99);
	bst->BSTree_Insert(-2);

	bst->BSTree_Travel_1(bst->root);

	cout << endl;

	bst->BSTree_Travel_2(bst->root);

	cout << endl;

	pHead = convert_To_Double_List(bst->root);

	while (pHead != NULL) {
		cout << pHead->m_iValue << ' ';
		pHead = pHead->m_pRight;
	}
	cout << endl;

	return 0;
}