把二元查找树转换成排序的双向链表

    题目:输入一颗二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整指针的指向。

例如,将图1中的二叉搜索树转换成一个排序的双向链表:4=6=8=10=12=14=16。


图1 二叉搜索树

    我们先来看一下这个题目该如何求解,然后再给出相应的源码。首先题目要求不能创造新的结点,那么,我们就只能使用树本身的结点,但是双向链表还有前驱和后继两个指针怎么办?答案是使用树的左孩子来做前驱指针,右孩子来做后继指针。又因为链表需要有序,所以使用中序遍历。

    解体思路:

    1)构造二叉查找树

    2)定义一个全局指针变量,指向双向链表的首元素。

    3)中序遍历二叉查找树,对于每次根节点的访问,修改其左孩子为链表的最后一个元素,修改其右孩子为NULL,那么这个元素的后继怎么办?由下一个元素来设置。

    具体代码如下:

BSTree.h:

#ifndef _BSTREE_H_
#define _BSTREE_H_
typedef struct _tagBSTreeNode
{
    int m_nVal;
    _tagBSTreeNode * m_pLeft;
    _tagBSTreeNode * m_pRight;
}BSTreeNode;
extern BSTreeNode * pHead;
//追加树结点
int AppendNode(BSTreeNode **, int nNum);
//打印树结点
void PrintTree(BSTreeNode ** ppTree);
//释放树
void Clear(BSTreeNode ** ppTree);
//转换为有序双链表
void InOrderTree(BSTreeNode ** ppTree);
//销毁链表
void ClearList(BSTreeNode * pHead);
//打印链表
void PrintList(BSTreeNode * pHead);
//打印路径
void PrintPath(BSTreeNode * pHead, int nSum);
#endif
BSTree.cpp:

#include <stdlib.h>
#include <stdio.h>
#include "BSTree.h"

//追加树结点
int AppendNode(BSTreeNode ** ppTree, int nNum)
{
	BSTreeNode * pNewNode = NULL;
	if (!ppTree)
		return 0;
	if (*ppTree == NULL)
	{
		pNewNode = (BSTreeNode *)malloc(sizeof(BSTreeNode));
		if (!pNewNode)
			return 0;
		pNewNode->m_nVal = nNum;
		pNewNode->m_pLeft = NULL;
		pNewNode->m_pRight = NULL;
		*ppTree = pNewNode;
		return 1;
	}
	if ((*ppTree)->m_nVal > nNum)
	{
		AppendNode(&((*ppTree)->m_pLeft), nNum);
	}
	else if ((*ppTree)->m_nVal < nNum)
	{
		AppendNode(&((*ppTree)->m_pRight), nNum);
	}
	else
	{
		printf("树结点已经存在.\n");
		return 0;
	}
	return 1;
}
//打印树结点
void PrintTree(BSTreeNode ** ppTree)
{
	if (!ppTree)
		return;
	if (*ppTree == NULL)
	{
		return;
	}
	if ((*ppTree)->m_pLeft)
		PrintTree(&((*ppTree)->m_pLeft));
	if (*ppTree)
		printf("%d", (*ppTree)->m_nVal);
	if ((*ppTree)->m_pRight)
		PrintTree(&((*ppTree)->m_pRight));
}

//释放树
void Clear(BSTreeNode ** ppTree)
{
	BSTreeNode * pLeftTree = NULL;
	BSTreeNode * pRightTree = NULL;
	if (!ppTree)
		return;
	if (*ppTree == NULL)
		return;
	if ((*ppTree)->m_pLeft)
	{
		pLeftTree = (*ppTree)->m_pLeft;
		Clear(&pLeftTree);
	}
	if ((*ppTree)->m_pRight)
	{
		pRightTree = (*ppTree)->m_pRight;
		Clear(&pRightTree);
	}
	if (*ppTree)
	{
		free(*ppTree);
		*ppTree = NULL;
	}
	return;
}

//以左孩子为前驱
//以右孩子为后继
BSTreeNode * pHead = NULL;

void AppendNode2List(BSTreeNode * pInput)
{
	BSTreeNode * pCurNode = NULL;
	if (pInput == NULL)
		return;
	if (!pHead)
	{
		pHead = pInput;
		pInput->m_pLeft = NULL;
		pInput->m_pRight = NULL;
		return;
	}
	pCurNode = pHead;
	while (pCurNode->m_pRight)
	{
		pCurNode = pCurNode->m_pRight;
	}
	pCurNode->m_pRight = pInput;
	pInput->m_pLeft = pCurNode;
	pInput->m_pRight = NULL;
	return ;
}

//打印树结点
void InOrderTree(BSTreeNode ** ppTree)
{
	if (!ppTree)
		return;
	if (*ppTree == NULL)
	{
		return;
	}
	if ((*ppTree)->m_pLeft)
		InOrderTree(&((*ppTree)->m_pLeft));
	if (*ppTree)
		AppendNode2List(*ppTree);
	if ((*ppTree)->m_pRight)
		InOrderTree(&((*ppTree)->m_pRight));
}

void PrintList(BSTreeNode * pHead)
{
	BSTreeNode * pCurNode = NULL;
	if (!pHead)
		return;
	pCurNode = pHead;
	printf("\n链表数据:\n");
	while (pCurNode)
	{
		printf("%d	", pCurNode->m_nVal);
		pCurNode = pCurNode->m_pRight;
	}
	return;
}

void ClearList(BSTreeNode * pHead)
{
	BSTreeNode * pCurNode = NULL;
	if (!pHead)
		return;
	while (pHead)
	{
		pCurNode = pHead->m_pRight;
		free(pHead);
		pHead = pCurNode;
	}
	return;
}
main.cpp:

//把二叉查找树转换为有序的双链表
//要求不可以创建新结点,只可以改变指针
//提示:
//可以将左孩子用于指向前驱结点
//可以将右孩子用于指向后继结点
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <stdio.h>
#include <crtdbg.h>
#include "BSTree.h"

void main()
{
	BSTreeNode * pTree = NULL;
	if (AppendNode(&pTree, 5) == NULL)
	{
		printf("追加失败.\n");
		return;
	}
	if (AppendNode(&pTree, 4) == NULL)
	{
		printf("追加失败.\n");
		return;
	}
	if (AppendNode(&pTree, 3) == NULL)
	{
		printf("追加失败.\n");
		return;
	}
	if (AppendNode(&pTree, 2) == NULL)
	{
		printf("追加失败.\n");
		return;
	}
	if (AppendNode(&pTree, 1) == NULL)
	{
		printf("追加失败.\n");
		return;
	}
	PrintTree(&pTree);
	InOrderTree(&pTree);
	PrintList(pHead);
	ClearList(pHead);
	_CrtDumpMemoryLeaks();
	system("pause");
	return;
}
运行效果如图1所示:

图1 运行效果

    图1是代码的运行效果,希望大家能够回去实践一下,加深体会。

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值