1. 程式人生 > >二叉搜尋樹(搜尋二叉樹)轉換成一個雙向連結串列

二叉搜尋樹(搜尋二叉樹)轉換成一個雙向連結串列

1.題目描述:

將一個二叉搜尋樹轉換成一個雙向連結串列;

2.二叉搜尋樹,直接看圖:


如圖就是一個二叉搜尋樹的模型,也就是轉換函式的入口資料,也是下邊函式中即將用到的例子,既然有輸入,肯定有輸出,先面在看一張圖(第三條):

3.輸入輸出模型:


右邊就是最終的輸出結果,5後邊是空,下邊來分析一下:

1.在二叉搜尋樹中,每個節點都有兩個孩子,即左和右,而在雙向連結串列中,每個節點也有兩個指標,前驅和後繼指標,二叉樹和雙向連結串列很有相似性;

2.改變二叉搜尋樹的左右孩子指標指向,就可完成二叉搜尋樹到雙向連結串列的轉換;

3.由於最終雙向連結串列的遍歷結果就是二叉搜尋樹中序的遍歷結果;

4.開始中序線索化二叉樹(即改變二叉樹指標指向)

如果對中序線索化二叉樹還有疑問,請看下圖:


如圖葉子節點的左右孩子指標指向都按中序線索的方式改變了;

4.看程式碼說話:

第一部分:

首先需要儲存最後雙向連結串列的頭,即二叉樹的最左節點:

Node* _BinaryToDoubleList(Node* root)
	{
		//1.找到雙向連結串列的頭;
		Node* head = root;
		while(head->_left != nullptr)
		{
			head = head->_left;
		}

		Node* prev = nullptr;
		_Change(root,prev);    //轉換函式

		return head;
	}
第二部分:

轉換函式:一個遞迴過程,按照中序線索化走的

	void _Change(Node* cur,Node*& prev)
	{
		if (cur == nullptr)
			return;
		//1.找到最左邊
		_Change(cur->_left,prev);
		cur->_left = prev;  //此時prev為空

		if (prev != nullptr)
			prev->_right = cur;

		prev = cur;

		_Change(cur->_right, prev);
	}
完整測試程式碼:
#pragma once

template<class K, class V>
struct SBTNode
{
	K key;
	V value;

	SBTNode<K, V> *_left;
	SBTNode<K, V> *_right;

	SBTNode(const K& key, const V& value)
		:key(key)
		, value(value)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

template<class K, class V>
class SBTree
{
	typedef SBTNode<K, V> Node;
public:
	SBTree()
		:_root(nullptr)
	{}

	~SBTree()
	{}

public:
	//非遞迴插入
	bool Insert(const K& key, const V& value)
	{
		return _Insert(key, value);
	}

	//遞迴插入
	bool Insert_R(const K& key, const V& value);

	//非遞迴查詢節點
	SBTNode<K, V>* Find(const K& key)
	{
		if (_root == nullptr)
		{
			return nullptr;
		}

		SBTNode<K, V> *cur = _root;
		while (cur->_left || cur->_right)
		{
			if (cur->key == key)
			{
				return cur;
			}
			else if (cur->key > key)
			{
				cur = cur->_left;
			}
			else if (cur->key < key)
			{
				cur = cur->_right;
			}
			else
			{
				return nullptr;
			}
		}
	}

	bool _Insert(const K& key, const V& value)
	{
		if (_root == nullptr)
		{
			_root = new SBTNode<K, V>(key, value);
			return true;
		}

		SBTNode<K, V> *parent = nullptr; //指向cur 的前驅
		SBTNode<K, V> *cur = _root;
		while (cur)
		{
			if (cur->key > key)  //插左邊
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		if (parent->key < key)
		{
			SBTNode<K, V> *node = new SBTNode<K, V>(key, value);
			parent->_right = node;
			return true;
		}

		else if (parent->key > key)
		{
			SBTNode<K, V> *node = new SBTNode<K, V>(key, value);
			parent->_left = node;
			return true;
		}
		else
		{
			return false;
		}
	}

	Node* BinaryToDoubleList()
	{
		return _BinaryToDoubleList(_root);
	}

	Node* _BinaryToDoubleList(Node* root)
	{
		//1.找到雙向連結串列的頭;
		Node* head = root;
		while(head->_left != nullptr)
		{
			head = head->_left;
		}

		Node* prev = nullptr;
		_Change(root,prev);    //轉換函式

		return head;
	}

	void _Change(Node* cur,Node*& prev)
	{
		if (cur == nullptr)
			return;
		//1.找到最左邊
		_Change(cur->_left,prev);
		cur->_left = prev;  //此時prev為空

		if (prev != nullptr)
			prev->_right = cur;

		prev = cur;

		_Change(cur->_right, prev);
	}

	//中序遍歷
	void InOrder(SBTNode<K, V>* root)
	{
		if (root == nullptr)
		{
			return; //遞迴結束出口
		}

		SBTNode<K, V> *cur = root;
		InOrder(cur->_left);
		cout << cur->key << " ";
		InOrder(cur->_right);
	}

	//順序遍歷雙向連結串列
	void TreaveList()
	{
		Node* cur = BinaryToDoubleList();
		while (cur)
		{
			cout << cur->key<< " ";
			cur = cur->_right;
		}
		cout << endl;
	}

public:
	SBTNode<K, V> *_root;
};
畫圖不容易,幫頂,賜教!