作者:云梦泽
日期:2013.11.13
地点:软件大楼211
心情:复杂
1、题目
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
比如:
10
/ \
6 14
/ \ / \
4 8 12 16
转换成双向链表为
4=6=8=10=12=14=16
2.基础知识
先来复习一下什么是二叉查找树和双向链表
二叉查找树也叫二叉排序树(Binary Sort Tree)或者是一个空树,空树总是符合任何树的定义。
性质:1.它的左子树不空,则左子树上的所有节点值均小于它的根节点值
2.它的右子树不空,则右子树上的所有节点值均大于它的根节点值
3.它的左右子树也分别为二叉排序树
中序遍历二叉排序树可得一个有序序列,一个无序序列可通过构造一颗二叉树而变为有序序列不仅如此,每次插入新节点时都是二叉树上的叶子节点,因而不必移动其它节点,仅需要改变某个节点的指针,由空变为非空。
双向链表,简单来说就是前驱后继都有的链表。
3.思路
1、构建二叉树,递归算法:对于每个数值,先进行树的访问比较,找到合适的位置,开辟空间放置和链接节点,调整指针指向,如下。
void AddBSTreeNode(BSTNode *&pCurrent,int inputValue)
{
if (pCurrent==nullptr) //当前树(子树)根为空,添加树节点
{
BSTNode *pTreeNode=new BSTNode(); //开辟空间
pTreeNode->iValue=inputValue;
pTreeNode->pLeft=nullptr;
pTreeNode->pRight=nullptr;
pCurrent=pTreeNode; //开始为根节点,递归调用时设为树的左或右链接
}
else if (pCurrent->iValue>inputValue) //访问左子树
{
AddBSTreeNode(pCurrent->pLeft,inputValue);
}
else if(pCurrent->iValue<inputValue) //访问右子树
{
AddBSTreeNode(pCurrent->pRight,inputValue);
}
else //相等不做处理
{
return;
}
}
2.构造好二叉排序树后对树进行遍历,以一个根节点为基础,遍历左子树到底,然后退出一层递归对当前根节点转换,然后再深入去遍历右子树,由此而完成转换
void TraceBSTree(BSTNode *&pCurrent,DoubleList *&pDoubleListHead,DoubleList *&pListIndex)
{//遍历二叉查找树,将得到的节点添加到双向二叉链表上
if (pCurrent==nullptr) //为空,返回,在多层递归中,退出当前层继续,有点类似多层循环的味道
{
return;
}
if (pCurrent->pLeft!=nullptr) //二叉树有左子树,访问左子树
{
TraceBSTree(pCurrent->pLeft,pDoubleListHead,pListIndex);
}
ConvertToDoubleList(pCurrent,pDoubleListHead,pListIndex);//没有将当前左节点转换为双向链表节点
if (pCurrent->pRight!=nullptr) //接着访问右子树
{
TraceBSTree(pCurrent->pRight,pDoubleListHead,pListIndex);
}
}
3.转换即对节点调整指针指向
4.下面给出标准代码:
void ConvertToDoubleList(BSTNode *pCurrent,DoubleList *pDoubleListHead,DoubleList *pListIndex)
{
//对于一个二叉查找树节点转换为链表节点
pCurrent->pLeft=pListIndex;
if(pListIndex==nullptr)//左链接为空,此时为头节点
pDoubleListHead=pCurrent;
else //否则非头结点,右向链接
pListIndex->pRight=pCurrent;
pListIndex=pCurrent; //链表索引指向当前节点
cout<<pCurrent->iValue<<endl;
}
4.下面给出标准代码:
1.头文件
//Author:云梦泽
//DateTime:2013.11.13
//湖南大学软件大楼211
#ifndef FUNCTION_DEFINE_H
#define FUNCTION_DEFINE_H
struct BSTNode
{
int iValue;
BSTNode *pLeft;
BSTNode *pRight;
};
typedef BSTNode BSTree;
typedef BSTNode DoubleList;
void ConvertToDoubleList(BSTNode *pCurrent);
void AddBSTreeNode(const BSTNode *&pCurrent,int inputValue);
void TraceBSTree(BSTNode *&pCurrent,DoubleList *&pDoubleListHead,DoubleList *&pListIndex);
#endif
2.源文件
//Author:云梦泽
//DateTime:2013.11.13
//湖南大学软件大楼211
#include <iostream>
#include "functiondefine.h"
using namespace std;
void AddBSTreeNode(BSTNode *&pCurrent,int inputValue)
{
if (pCurrent==nullptr) //当前树(子树)根为空,添加树节点
{
BSTNode *pTreeNode=new BSTNode(); //开辟空间
pTreeNode->iValue=inputValue;
pTreeNode->pLeft=nullptr;
pTreeNode->pRight=nullptr;
pCurrent=pTreeNode; //开始为根节点,递归调用时设为树的左或右链接
}
else if (pCurrent->iValue>inputValue) //访问左子树
{
AddBSTreeNode(pCurrent->pLeft,inputValue);
}
else if(pCurrent->iValue<inputValue) //访问右子树
{
AddBSTreeNode(pCurrent->pRight,inputValue);
}
else //相等不做处理
{
return;
}
}
void ConvertToDoubleList(BSTNode *pCurrent,DoubleList *pDoubleListHead,DoubleList *pListIndex)
{
//对于一个二叉查找树节点转换为链表节点
pCurrent->pLeft=pListIndex;
if(pListIndex==nullptr)//左链接为空,此时为头节点
pDoubleListHead=pCurrent;
else //否则非头结点,右向链接
pListIndex->pRight=pCurrent;
pListIndex=pCurrent; //链表索引指向当前节点
cout<<pCurrent->iValue<<endl;
}
void TraceBSTree(BSTNode *&pCurrent,DoubleList *&pDoubleListHead,DoubleList *&pListIndex)
{//遍历二叉查找树,将得到的节点添加到双向二叉链表上
if (pCurrent==nullptr) //二叉树为空,返回
{
return;
}
if (pCurrent->pLeft!=nullptr) //二叉树有左子树,访问左子树
{
TraceBSTree(pCurrent->pLeft,pDoubleListHead,pListIndex);
}
ConvertToDoubleList(pCurrent,pDoubleListHead,pListIndex);//没有将当前左节点转换为双向链表节点
if (pCurrent->pRight!=nullptr) //接着访问右子树
{
TraceBSTree(pCurrent->pRight,pDoubleListHead,pListIndex);
}
}
int main()
{
BSTree *pBSTreeRoot=nullptr; //二叉查找树根节点
DoubleList *pDoubleListHead=nullptr; //双链表头节点
BSTNode *pListIndex=nullptr; //指向链表节点的指针
int inData=0;
cout<<"请输入一串数字,并以 / 结束"<<endl;
while(cin>>inData) //界面交互输入数据
{
AddBSTreeNode(pBSTreeRoot,inData); //数据添加到二叉查找树
}
BSTree *pBSTreeRoo1=pBSTreeRoot;
TraceBSTree(pBSTreeRoot,pDoubleListHead,pListIndex);
return 0;
}