題目:將二叉搜尋樹轉換成一個排序的雙向鏈表。提示:要求不能建立任何新的結點,只能調整樹中結點指標的指向,也就是left當prev,right當next。–中序線索化的變型。
1、由於要求鏈表是有序的,可以藉助二叉樹中序遍曆,因為中序遍曆演算法的特點就是從小到大訪問結點。當遍曆訪問到根結點時,假設根結點的左側已經處理好,只需將根結點與上次訪問的最近結點(左子樹中最大值結點)的指標串連好即可。進而更新當前鏈表的最後一個結點指標。
2、由於中序遍曆過程正好是轉換成鏈表的過程,即可採用遞迴處理。
中序遍曆該二叉樹的結果:
把二叉搜尋樹看成三部分:根節點,左子樹和右子樹。在把左,右子樹都轉換成排序的雙向鏈表之後再和根節點連結起來,整棵二叉搜尋也就轉換成了排序的雙向鏈表。
二叉搜尋樹的結點:
template<class K, class V> //索引值隊struct BSTNode{ BSTNode(const K& key, const V& value) : _pLeft(NULL) , _pRight(NULL) ,_pParent(NULL) , _key(key) , _value(value) {} BSTNode<K, V>* _pLeft; BSTNode<K, V>* _pRight; BSTNode<K, V>* _pParent; K _key; V _value;};
template<class K, class V>class BinarySearchTree{ typedef BSTNode<K, V> Node; typedef BinarySearchTree<K, V> Self;public: BinarySearchTree() : _pRoot(NULL) {} //拷貝建構函式 //BinarySearchTree(const Self& bst); //賦值運算子多載 //Self& operator=(const Self& bst); //解構函式 ~BinarySearchTree() { _DestroyTree(_pRoot); } // 尋找--非遞迴 bool Find_Nor(const K& key) { Node* pCur = _pRoot; while (pCur) //二叉樹存在 { if (pCur->_key == key) return true; else if (key < pCur->_key) return pCur = pCur->_pLeft; else pCur = pCur->_pRight; } return false; } //遞迴尋找 bool Find(const K& key) { return _Find(_pRoot, key); } // 插入--非遞迴 bool Insert_Nor(const K& key, const V& value) //插入某元素 { if (NULL == _pRoot) { _pRoot = new Node(key, value); return true; } //找元素插入位置 Node* pCur = _pRoot; Node* pParent = NULL; //標記 while (pCur) { if (key < pCur->_key) { pParent = pCur; pCur = pCur->_pLeft ; //新插入的結點儲存在左子樹 } else if (key > pCur->_key) { pParent = pCur; pCur = pCur->_pRight; //新插入的結點儲存在右子樹 } else return false; } pCur = new Node(key, value); if (key < pParent->_key) //pParent = pParent->_pLeft ; pParent->_pLeft = pCur; else if (key > pParent->_key) //pParent = pParent->_pRight; pParent->_pRight = pCur; else return false; }// 遞迴--插入 bool Insert(const K& key, const V& value) { return _Insert(_pRoot, key, value); // } void InOrder() { cout << "InOrder(): " << endl; _InOrder(_pRoot); cout << endl; } //二叉搜尋樹與雙向鏈表 Node* Convert() //_pRoot { Node* pLastNodeInList = NULL; ConvertNode(_pRoot, &pLastNodeInList); //pLastNodeInList-->雙向鏈表的尾結點 //返回頭結點 Node* pHeadOfList = pLastNodeInList; while (pHeadOfList != NULL && pHeadOfList->_pLeft != NULL) pHeadOfList = pHeadOfList->_pLeft; return pHeadOfList; } private: bool _Find(Node* pRoot, const K& key) { if (pRoot) //二叉樹存在 { if (key == pRoot->_key) //尋找的值在左子樹中 return true; else if (key < pRoot->_key) return _Find(pRoot->_pLeft, key); // 尋找的值在左子樹中 else return _Find(pRoot->_pRight, key); //尋找的值在右子樹中 } return false; //樹不存在 } bool _Insert(Node* &pRoot, const K& key, const V& value) //--- { if (NULL == pRoot) //1)、樹為空白,插入結點作為根結點 { pRoot = new Node(key, value); return true; } else //二叉樹存在--插入的結點在左右子樹中 { if (key < pRoot->_key) return _Insert(pRoot->_pLeft, key, value); // else if (key > pRoot->_key) return _Insert(pRoot->_pRight, key, value); // else return false; } } void _InOrder(Node* pRoot) //Node* pRoot--中序遍曆 { if(pRoot) { //遍曆左子樹 _InOrder(pRoot->_pLeft); cout<<pRoot->_key<<" "; _InOrder(pRoot->_pRight); //遍曆右子樹 } } //二叉搜尋樹與雙向鏈表 void ConvertNode(Node* pRoot, Node** pLastNodeInList) { if (NULL == pRoot) return; Node* pCur = pRoot; if (NULL != pCur->_pLeft) //遞迴處理左子樹 ConvertNode(pCur->_pLeft, pLastNodeInList); //pCur--處理當前結點,將當前結點的左指標指向鏈表的尾結點 pCur->_pLeft = *pLastNodeInList; //pLastNodeInList-->雙向鏈表的尾結點 if (NULL != *pLastNodeInList) (*pLastNodeInList)->_pRight = pCur; //更新已經轉換好的鏈表的尾結點 *pLastNodeInList = pCur; //遞迴處理右子樹 if (NULL != pCur->_pRight) ConvertNode(pCur->_pRight, pLastNodeInList); } void _DestroyTree(Node*& pRoot) { if (pRoot) { _DestroyTree(pRoot->_pLeft); _DestroyTree(pRoot->_pRight); delete pRoot; pRoot = NULL; } }private: Node* _pRoot;};