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

题目选自http://zhedahht.blog.163.com/(何海涛--程序员面试题精选100题)

下面是按照书中分析的思路编写的code,或许看起来更简明

<span style="font-size:14px;">#include <stdio.h>
#include <stdlib.h> 

#define A 15

//二叉树前序遍历序列,-1表示空节点
int buffer[16]={10,6,4,-1,-1,8,-1,-1,14,12,-1,-1,16,-1,-1,-100};

//二叉树结构体
typedef struct binary_tree_node
{
	int data;
	struct binary_tree_node* ltree;
	struct binary_tree_node* rtree;
}Btnode;

//创建新节点
Btnode* create_node(void)
{
	Btnode* node;
	node=(Btnode*)malloc(sizeof(Btnode));
	return node;
}

//据前序序列创建二叉树
/*
	明确问题:

	(1)何时进行二叉树分支的切换

		①左分支遍历到叶子节点时

		②右分支有新的节点加入时

	(2)何时节点入栈

		新加入的非空节点

	(3)何时节点出栈

		某分支遍历到叶子节点时
*/
Btnode* create_tree(int* buf)
{
	Btnode* root;
	Btnode* pnode,*temp;
	Btnode* s[A];
	bool ltree=true;
	int index=0;
	int m=0;
	
	root=create_node();
	root->data=buf[index++];
	s[m++]=root;
	pnode=root;

	while(buf[index]!=-100)
	{
		if(ltree==true)
		{
			if(buf[index]==-1)
			{
				pnode->ltree=NULL;
				index++;
				ltree=false;
				pnode=s[--m];
			}
			else
			{
				temp=create_node();
				temp->data=buf[index++];
				pnode->ltree=temp;
				s[m++]=temp;
				pnode=temp;
			}
		}
		else
		{
			if(buf[index]==-1)
			{
				pnode->rtree=NULL;
				index++;
				pnode=s[--m];
			}
			else
			{
				temp=create_node();
				temp->data=buf[index++];
				pnode->rtree=temp;
				s[m++]=temp;
				pnode=temp;
				ltree=true;
			}
		}
	}

	return root;
}
/*
	基本思想:

	将左子树进行排序返回左子树的链尾,将右子树进行排序

	返回右子树的链首,将左子树链尾、根节点、右子树的链
	
	首进行连接

	明确问题:

	递归思想的实质也是栈操作,首先递归调用到一个不满足
	
	递归条件的状态,此时进行相应的操作并返回可能在回溯

	过程中用到的值,接下来进行回溯,回溯过程中进行相同
	
	的子任务处理。注:这里所说的相应操作是指->通过传入参
	
	数和返回值进行相应的操作。

	程序中parameter flag用于标记左子树还是右子树

*/
Btnode* tree2chain(Btnode* pnode,bool flag)
{
	Btnode* temp1,*temp2,*temp3;

	if(pnode->ltree==NULL && pnode->rtree==NULL)
	{
		return pnode;
	}

	if(pnode!=NULL)
	{
		temp1=tree2chain(pnode->ltree,true);
		temp2=pnode;
		temp3=tree2chain(pnode->rtree,false);
		temp1->ltree=temp2;
		temp2->ltree=temp3;
		temp3->rtree=temp2;
		temp2->rtree=temp1;
	}

	if(flag==true)
	{
		return temp3;
	}
	else
	{
		return temp1;
	}
}

int main(void)
{
	Btnode* root;
	Btnode* plist;

	root=create_tree(buffer);
	plist=root;
	while(plist->ltree!=NULL)		//记录链首
	{
		plist=plist->ltree;
	}
	tree2chain(root,true);	

	printf("正向遍历链表:\n");
	while(1)
	{
		printf("%d->",plist->data);
		if(plist->ltree!=NULL)
		{
			plist=plist->ltree;
		}
		else
		{
			break;
		}
	}
	printf("\n\n反向遍历链表:\n");
	while(1)
	{
		printf("%d<-",plist->data);
		if(plist->rtree!=NULL)
		{
			plist=plist->rtree;
		}
		else
		{
			break;
		}
	}
	printf("\n\n");

	system("pause");
	return 0;
}</span>


至于非递归的方法可以按照中序遍历的方法将遍历各个节点的指针保存起来,最后再修改指针的指向


#include "stdafx.h"
#include <vector>
#include <iostream>
using namespace std;

#define A 16

//二叉树前序遍历序列
int buffer[16]={1,2,4,-1,-1,5,-1,-1,3,6,-1,-1,7,-1,-1,-100};

//二叉树结构体
typedef struct binary_tree_node
{
	int data;
	struct binary_tree_node* ltree;
	struct binary_tree_node* rtree;
}Btnode;

//创建新节点
Btnode* create_node(void)
{
	Btnode* node;
	node=(Btnode*)malloc(sizeof(Btnode));
	return node;
}

//据前序序列创建二叉树
/*
	明确问题:

	(1)何时进行二叉树分支的切换

		①左分支遍历到叶子节点时

		②右分支有新的节点加入时

	(2)何时节点入栈

		新加入的非空节点

	(3)何时节点出栈

		某分支遍历到叶子节点时
*/
Btnode* create_tree(int* buf)
{
	Btnode* root;
	Btnode* pnode,*temp;
	Btnode* s[A];
	bool ltree=true;
	int index=0;
	int m=0;
	
	root=create_node();
	root->data=buf[index++];
	s[m++]=root;
	pnode=root;

	while(buf[index]!=-100)
	{
		if(ltree==true)
		{
			if(buf[index]==-1)
			{
				pnode->ltree=NULL;
				index++;
				ltree=false;
				pnode=s[--m];
			}
			else
			{
				temp=create_node();
				temp->data=buf[index++];
				pnode->ltree=temp;
				s[m++]=temp;
				pnode=temp;
			}
		}
		else
		{
			if(buf[index]==-1)
			{
				pnode->rtree=NULL;
				index++;
				pnode=s[--m];
			}
			else
			{
				temp=create_node();
				temp->data=buf[index++];
				pnode->rtree=temp;
				s[m++]=temp;
				pnode=temp;
				ltree=true;
			}
		}
	}

	return root;
}

//递归方法前序遍历
void preorder_traversal(Btnode* pnode)
{
	if(pnode!=NULL)
	{
		printf("%d ",pnode->data);
	}
	else
	{
		return;
	}

	preorder_traversal(pnode->ltree);
	preorder_traversal(pnode->rtree);
	return;
}

vector<Btnode*> s;
Btnode* head;
void medDList(Btnode* node)
{
	if(node==NULL)
	{
		return;
	}
	else
	{
		medDList(node->ltree);
		if(s.empty())
		{
			s.push_back(node);
			head=node;
		}
		else
		{
			s.back()->rtree=node;
			node->ltree=s.back();
			s.push_back(node);
		}
		medDList(node->rtree);
	}
}

void showList()
{
	int len=s.size();
	Btnode* p=s.back();

	for(int i=0;i<len && p!=NULL;i++)
	{
		cout<<p->data<<"->";
		p=p->ltree;
	}
	printf("\b\b");
	cout<<"  ";
	cout<<endl;

	return;
}

int main(void)
{
	Btnode* root;
	root=create_tree(buffer);
	
	medDList(root);
	showList();
	
	system("pause");
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值