剑指offer 27 - 二叉搜索树与双向链表
来源:互联网 发布:家装平面模板软件 编辑:程序博客网 时间:2024/05/17 02:21
一、问题描述
输入一棵二叉搜索树,现在要将该二叉搜索树转换成一个排序的双向链表。而且在转换的过程中,不能创建任何新的结点,只能调整树中的结点指针的指向来实现。
二、实现思路
在二叉搜索树中,每个结点都有两个分别指向其左、右子树的指针,左子树结点的值总是小于父结点的值,右子树结点的值总是大于父结点的值。而在双向链表中,每个结点也有两个指针,它们分别指向前一个结点和后一个结点。所以这两种数据结构的结点是一致,二叉搜索树之所以为二叉搜索树,双向链表之所以为双向链表,只是因为两个指针的指向不同而已,通过改变其指针的指向来实现是完全可能的。
例如如下的二叉搜索树,
若采用中序遍历,其遍历顺序为1-2-3-4-5-6-7,通过适当的指针变换操作,可变成的双向有序链表如下:
从上图,我们可以看出,为了减少指针的变换次数,并让操作更加简单,在转换成排序双向链表时,原先指向左子结点的指针调整为链表中指向前一个结点的指针,原先指向右子结点的指针调整为链表中指向下一个结点的指针。例如对于上面的值为2的指点,调整后,它的前一个结点为1,后一个结点为3,而结点2的左子结点本来就为1,右子结点本来就为3.
对于树的操作,通常是在遍历树的各个结点的过程中,通过对结点实施某些操作来完成的,这个算法也不例外。由于要求转换后的双向链表也是有序的,而我们从上面也可以看到,当我们以中序遍历二叉搜索树时,其遍历的结点就是有序的,所以在这里我位采用的遍历顺序应该是中序。
那么我们应该如何调整指针,让二叉搜索树变成一个双向有序链表呢?当遍历到根结点时,我们可以把树看成三个部分:根结点,根的左子树和根的右子树。如上图的二叉排序树,就分成了根结点4、以结点2为根的左子对和以结点6为根的右子树。从变换的链表中我们可以看到,应当把结点4的left指针指向结点3,把结点3的right指针指向结点4,而由于我们采用的是中序遍历,所以当我们遍历到结点4时,结点4的左子树已经转化为一个有序的双向链表,而结点3是这个已经转化的双向链表的尾结点,所以我们应该用一个变量last_node来保存最后一个结点的指针,以便在与根结点连续时使用。然后把这个变量last_node的值更新为指向根结点4。对于结点4的右子树,采取相似的操作。至于具体的实现,我们只需要对所有的子树递归地执行上述操作即可。其操作过程如下:
#include<iostream>#include<fstream>using namespace std;struct BinaryTreeNode { int m_nValue; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight; }; BinaryTreeNode* CreateBinaryTreeNode(int value) { BinaryTreeNode* node = new BinaryTreeNode[sizeof(BinaryTreeNode)]; node->m_nValue = value; node->m_pLeft = node->m_pRight = NULL; return node; } void ConnectTreeNodes(BinaryTreeNode* pRoot,BinaryTreeNode* pLeft,BinaryTreeNode* pRight) { if(pRoot!=NULL) { pRoot->m_pLeft = pLeft; pRoot->m_pRight = pRight; } } void PrintTree(BinaryTreeNode* node) { if(node!=NULL) { if(node->m_pLeft) PrintTree(node->m_pLeft); cout<<node->m_nValue<<" "; if(node->m_pRight) PrintTree(node->m_pRight); } } void DestroyList(BinaryTreeNode* pHeadOfList){ BinaryTreeNode* pNode = pHeadOfList; while(pNode != NULL) { BinaryTreeNode* pNext = pNode->m_pRight; delete pNode; pNode = pNext; }}void PrintDoubleLinkedList(BinaryTreeNode* pHeadOfList){ BinaryTreeNode* pNode = pHeadOfList; printf("\nThe nodes from left to right are:\n"); while(pNode != NULL) { printf("%d\t", pNode->m_nValue); if(pNode->m_pRight == NULL) break; pNode = pNode->m_pRight; } printf("\nThe nodes from right to left are:\n"); while(pNode != NULL) { printf("%d\t", pNode->m_nValue); if(pNode->m_pLeft == NULL) break; pNode = pNode->m_pLeft; } printf("\n\n");}void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList){if(pNode==NULL)return; BinaryTreeNode* pCurr = pNode;if(pCurr ->m_pLeft)ConvertNode(pCurr ->m_pLeft,pLastNodeInList);pCurr->m_pLeft=*pLastNodeInList; if((*pLastNodeInList)!=NULL)(*pLastNodeInList)->m_pRight=pCurr;*pLastNodeInList = pCurr;if(pCurr ->m_pRight)ConvertNode(pCurr ->m_pRight,pLastNodeInList);}BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree){BinaryTreeNode *pLastNodeInList = NULL; ConvertNode(pRootOfTree, &pLastNodeInList);BinaryTreeNode * node = pLastNodeInList;while(node!=NULL && node->m_pLeft!=NULL){ node = node->m_pLeft;}return node;}void Test(char* testName, BinaryTreeNode* pRootOfTree){ if(testName != NULL) printf("%s begins:\n", testName); PrintTree(pRootOfTree); BinaryTreeNode* pHeadOfList = Convert(pRootOfTree); PrintDoubleLinkedList(pHeadOfList);}// 10// / \// 6 14// /\ /\// 4 8 12 16void Test1(){ BinaryTreeNode* pNode10 = CreateBinaryTreeNode(10); BinaryTreeNode* pNode6 = CreateBinaryTreeNode(6); BinaryTreeNode* pNode14 = CreateBinaryTreeNode(14); BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4); BinaryTreeNode* pNode8 = CreateBinaryTreeNode(8); BinaryTreeNode* pNode12 = CreateBinaryTreeNode(12); BinaryTreeNode* pNode16 = CreateBinaryTreeNode(16); ConnectTreeNodes(pNode10, pNode6, pNode14); ConnectTreeNodes(pNode6, pNode4, pNode8); ConnectTreeNodes(pNode14, pNode12, pNode16); Test("Test1", pNode10); DestroyList(pNode4);}// 5// /// 4// /// 3// /// 2// /// 1void Test2(){ BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5); BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4); BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3); BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2); BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1); ConnectTreeNodes(pNode5, pNode4, NULL); ConnectTreeNodes(pNode4, pNode3, NULL); ConnectTreeNodes(pNode3, pNode2, NULL); ConnectTreeNodes(pNode2, pNode1, NULL); Test("Test2", pNode5); DestroyList(pNode1);}// 1// \// 2// \// 3// \// 4// \// 5void Test3(){ BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1); BinaryTreeNode* pNode2 = CreateBinaryTreeNode(2); BinaryTreeNode* pNode3 = CreateBinaryTreeNode(3); BinaryTreeNode* pNode4 = CreateBinaryTreeNode(4); BinaryTreeNode* pNode5 = CreateBinaryTreeNode(5); ConnectTreeNodes(pNode1, NULL, pNode2); ConnectTreeNodes(pNode2, NULL, pNode3); ConnectTreeNodes(pNode3, NULL, pNode4); ConnectTreeNodes(pNode4, NULL, pNode5); Test("Test3", pNode1); DestroyList(pNode1);}// 树中只有1个结点void Test4(){ BinaryTreeNode* pNode1 = CreateBinaryTreeNode(1); Test("Test4", pNode1); DestroyList(pNode1);}// 树中没有结点void Test5(){ Test("Test5", NULL);}int main(int argc, char* argv[]){ Test1(); Test2(); Test3(); Test4(); Test5(); return 0;}
0 0
- 剑指offer 27 - 二叉搜索树与双向链表
- 剑指offer-27二叉搜索树与双向链表
- 剑指Offer 27 二叉搜索树与双向链表
- 剑指offer 27 二叉搜索树与双向链表
- 剑指Offer二叉搜索树与双向链表
- 【剑指offer:】Q27:二叉搜索树与双向链表
- 剑指offer--二叉搜索树与双向链表
- 剑指offer-二叉搜索树与双向链表
- 《剑指offer》二叉搜索树与双向链表
- 【剑指Offer】二叉搜索树与双向链表
- 剑指offer—二叉搜索树与双向链表
- 剑指offer:二叉搜索树与双向链表
- 剑指offer-二叉搜索树与双向链表
- 剑指Offer--027-二叉搜索树与双向链表
- 剑指offer:二叉搜索树与双向链表
- [剑指offer]二叉搜索树与双向链表
- 《剑指offer》-二叉搜索树与双向链表
- 剑指offer题解 二叉搜索树与双向链表
- 关于Linux内核学习
- 2015061707 - 工具类的要求
- Ogre基础教程4:监听器类与无缓冲输入处理
- centos6.5 lnmp、lamp、lnmpa一键安装包
- Find the element that appears once
- 剑指offer 27 - 二叉搜索树与双向链表
- PHP:PDOStatement::rowCount()方法参数说明
- java实现——8硬币问题(算法)
- Upgrading to Subversion 1.7
- 计算机网络(10)网络层
- MySql索引的学习
- java 动态代理
- CF 6C Alice, Bob and Chocolate
- SMO算法