现在的位置: 首页 > 综合 > 正文

面试100题系列之1将查找二叉树转换成有序的双向链表

2017年10月17日 ⁄ 综合 ⁄ 共 3040字 ⁄ 字号 评论关闭

1、将二元查找树转化成排序的双向链表,题目来源:http://blog.csdn.net/v_JULY_v/article/details/6057286
10
/ \
6 14
/ \ / \
4 8 12 16 => 4<=>6<=>8<=>10<=>12<=>16
要求:不能创建节点,只改变指针的指向
方法:其实就是树的中序遍历。用递归的方法build树,然后再将遍历到的节点一个一个的加到链表中去。

#include<stdio.h>
#include<string.h>
struct NODE
{
	int data;
	NODE *Left;
	NODE *Right;
};
const int N = 20;
NODE node[N];
int top;
void Add(NODE *root, int v)
{
	if(!root)
		return;
	if(root->data < v)
	{
		if(root->Right)
			Add(root->Right, v);
		else
		{
			root->Right = &node[++top];
			node[top].data = v;
		}
	}
	else if(root->data > v)
	{
		if(root->Left)
			Add(root->Left, v);
		else
		{
			root->Left = &node[++top];
			node[top].data = v;
		}
	}
	else
		printf("重复加入节点%d\n", v);	
}
//转化之后链表是降序排列的
NODE *TransTreeToLink(NODE *root)
{
	if(!root)
		return NULL;
	NODE *stack[N];
	int top = -1;
	NODE *p = root;
	NODE *head = NULL;
	while(p != NULL || top > -1)
	{
		while(p != NULL)
		{
			stack[++top] = p;
			p = p->Left;
		}
		if(top > -1)
		{
			p = stack[top]->Right;
			if(!head)
				head = stack[top];
			else
			{
				//实现与链表的链接,先连,后断
				stack[top]->Left = head;
				head->Right = stack[top];
				head = stack[top];
			}
			--top;		
		}
	}
	return head;
}
//打印链表
void Print(NODE *head)
{
	if(!head)
		return;
	NODE *p;
	p = head;
	while(p != NULL)
	{
		printf("%d ",p->data);
		p = p->Left;
	}
	printf("\n");
}

int main()
{
	int n,i,v;
	NODE *head;
	while(scanf("%d", &n) != EOF)
	{
		memset(node, 0, sizeof(node));
		top = 0;
		scanf("%d", &v);
		node[0].data = v;
		for(i = 1; i < n; ++i)
		{
			scanf("%d", &v);
			Add(&node[0], v);
		}
		head = TransTreeToLink(&node[0]);
		Print(head);
	}
}

PS:附上以前写得很挫的代码:两个关于NODE的定义都是一样的。

/*****************************************************************************
*1、将二元查找树转化成排序的双向链表
*			  10
*			 /  \
*			6	 4
*		   / \  / \
*		  4  8 12 16  => 4<=>6<=>8<=>10<=>12<=>16
*要求:不能创建节点,只改变指针的指向
*方法:递归和栈。其实就是树的中序遍历。
******************************************************************************/
//将节点加入树中间
bool AddNodeToTree(TREENODE* &pRoot, int Value)
{
	if(NULL == pRoot)
	{
		TREENODE *pTemp;
		pTemp = (TREENODE *)malloc(sizeof(TREENODE));
		if(NULL == pTemp)
		{
			printf("加入节点%d失败。", Value);
		}
		pTemp->Data = Value;
		pTemp->left = NULL;
		pTemp->right = NULL;
		pRoot = pTemp;
		return true;
	}
	if(Value < pRoot->Data)
	{
		AddNodeToTree(pRoot->left, Value);	
	}
	else if(Value > pRoot->Data)
	{	
		AddNodeToTree(pRoot->right, Value);
	}
	else
	{
		printf("重复加入节点%d\n", Value);
		return false;
	}
}
//将节点转化成有序链表
TREENODE *TransTreeToLink(TREENODE *pRoot)
{
	if(!pRoot)
	{
		return NULL;
	}

	TREENODE *pTemp;
	//记录链表中的头结点
	TREENODE *pList = NULL;
	TREENODE *Stack[MAX_SIZE];
	int top = -1;
	
	//将根节点的左、右及自己入栈
	if(pRoot->right != NULL)
	{
		Stack[++top] = pRoot->right;
	}
	Stack[++top] = pRoot;
	if(pRoot->left != NULL)
	{
		Stack[++top] = pRoot->left;
	}

	while(top > -1)
	{
		pTemp = Stack[top];
		--top;
		if(NULL == pTemp->left && NULL == pTemp->right)
		{
			//如果是第一个进入链表的节点
			pTemp->left = pList;
			if(pList != NULL)
			{
				pList->right = pTemp;
			}

			//判断是否栈中只有最后一个节点未入链表
			if(top >= 0)
			{
				//链表和树之间的连接
				pTemp->right = Stack[top];
				Stack[top]->left = pTemp;
				//更新链表头节点
				pList = Stack[top];
				--top;
			}
			else
			{
				pList = pTemp;
			}
		}//end if(NULL == pTemp->left && NULL == pTemp->right)
		//如果不是第一个入链表的节点
		else
		{
			if(pTemp->right != NULL)
			{
				Stack[++top] = pTemp->right;
			}
			Stack[++top] = pTemp;
			if(pTemp->left != NULL)
			{
				Stack[++top] = pTemp->left;
			}	
		}//end else
	}//end while(top > -1)
	return pList;
}
//打印链表
void Print(TREENODE *pList)
{
	if(pList ==NULL)
	{
		return;
	}
	TREENODE *pTemp;
	pTemp = pList;
	while(pTemp != NULL)
	{
		printf("%d\t", pTemp->Data);
		pTemp = pTemp->left;
	}
}
//销毁链表
void Destroy(TREENODE *pList)
{
	if(pList == NULL)
	{
		return;
	}
	TREENODE *pTemp;
	
	while(pList != NULL)
	{
		pTemp = pList;

		pList = pList->left;
		free(pTemp);
		pTemp = NULL;		
	}
}

抱歉!评论已关闭.