二叉树非递归

<pre name="code" class="cpp">/************************************************************************
非递归遍历:
(1)工作记录中包含两项,其一是递归调用的语句编号,其二是指向根节点的指针,
	则当栈顶记录中的指针非空是,应遍历左子树,即指向左子树根的指针进栈;
(2)若栈顶记录中的指针值为空,则应退至上一层,
	若是从左子树返回,则应访问当前层即栈顶记录中指针所指的根节点;
(3)若是从右子树返回,则说明当前层的遍历结束,应继续退栈。从另一角度看,
	这意味着遍历右子树时不再需要保存当前层的根指针,可直接修改栈顶记录中的指针即可。

递归遍历与非递归遍历的区别:
		递归遍历过程由高层进入底层,当底层满足返回条件时从低层返回高层。
		非递归遍历过程是将高层的指针逐级保存入栈,通过指针指向进入底层。
		当满足返回条件时(到树底)将上一层的栈弹出并进入上一层,然后转向右子树(或左子树)继续遍历。
************************************************************************/


#include "common.h"
#include <process.h>
#include "Stack.h"


extern void DataStructure();
static BOOL BinTreeLookUp(Node* node, int target);
static Node* BinTreeInsert(Node* node, int data);
static Node* NewNode(int data);
void BinTreePrint(Node* node);
void CreatBiTree(Tree* T);
void PrintTree(Tree T);
void InOrderTraverse(Tree T);
void PreOrderTraverse(Tree T);
void PostOrderTraverse(Tree T);

void DataStructure()
{
	Tree T=NULL;
	CreatBiTree(&T);
	
	BinTreePrint(T);

	printf("\n");
	//InOrderTraverse(T);
	//PreOrderTraverse(T);
	PostOrderTraverse(T);
	printf("\n");

}


/************************************************************************
非递归遍历:
(1)工作记录中包含两项,其一是递归调用的语句编号,其二是指向根节点的指针,
	则当栈顶记录中的指针非空是,应遍历左子树,即指向左子树根的指针进栈;
(2)若栈顶记录中的指针值为空,则应退至上一层,
	若是从左子树返回,则应访问当前层即栈顶记录中指针所指的根节点;
(3)若是从右子树返回,则说明当前层的遍历结束,应继续退栈。从另一角度看,
	这意味着遍历右子树时不再需要保存当前层的根指针,可直接修改栈顶记录中的指针即可。

递归遍历与非递归遍历的区别:
		递归遍历过程由高层进入底层,当底层满足返回条件时从低层返回高层。
		非递归遍历过程是将高层的指针逐级保存入栈,通过指针指向进入底层。
		当满足返回条件时(到树底)将上一层的栈弹出并进入上一层,然后转向右子树(或左子树)继续遍历。
************************************************************************/

void CreatBiTree(Tree* T)
{
	ElemType ch[100] = "";
	int len;
	int i;
	fgets(ch,100,stdin);
	len = strlen(ch);
	for(i=0; i<len-1; i++)
	{
		printf("%c ",ch[i]);
		 *T = BinTreeInsert(*T, ch[i]);
	}
	printf("\n");


}
//http://zh.wikipedia.org/wiki/二叉树

static BOOL BinTreeLookUp(Node* node, int target)
{
	if(node == NULL)
	{
		return FALSE;
	}
	else
	{
		if(node->data == target)
		{
			return TRUE;
		}
		else if (node->data < target)
		{
			return BinTreeLookUp(node->rChild,target);
		}
		else if(node->data > target)
		{
			return BinTreeLookUp(node->lChild,target);
		}
	}
	return FALSE;
}



static Node* BinTreeInsert(Node* node, int data)
{
	if(node == NULL)
	{
		return NewNode(data);
	}
	else
	{
		if(node->data >= data)
		{
			node->lChild = BinTreeInsert(node->lChild,data);
		}
		else node->rChild = BinTreeInsert(node->rChild,data);
		return node;
	}
	
}


static Node* NewNode(int data)
{
	Node* newNode = (Node*)malloc(sizeof(Node));
	newNode->data = data;
	newNode->lChild = NULL;
	newNode->rChild = NULL;
	newNode->parent = NULL;
	return newNode;
}


void BinTreePrint(Node* node)
{
	if(node == NULL)
	{
		return ;
	}
	//printf("<%c>",node->data);//先序遍历p,l,r
	BinTreePrint(node->lChild);
	//printf("<%c>",node->data);//	中序遍历l,p,r
	BinTreePrint(node->rChild);
	printf("<%c>",node->data);//后序遍历
}


//非递归中序遍历
/************************************************************************
(1)中序遍历左子树;
(2)访问根节点;
(3)中序遍历右子树;

对于任一结点的临时指针指针变量p,
	(1)如果p有指向(非空)那么将结点的地址保存入栈并进入他的左孩子。
	(2)如果p为空那么出栈访问上一个结点,然后进入右孩子。
	导致p为空的情况:
	(a)遍历左孩子到了末尾,栈顶保存的是最后一个左孩子;这时打印的是最后一个左孩子。
	(b)从左孩子返回,进入右孩子后,右孩子的地址保存到p,但是右孩子为空。
		这时打印的是最后一个左孩子(左孩子可能是空)的父节点。
************************************************************************/
void InOrderTraverse2(Tree T)
{
	SqSTACK stack;
	Tree p = T;
	StackInit(&stack);
	
	while(p!= NULL || !StackIsEmpty(&stack))
	{
		//探寻左子树的底部
		while(p != NULL)
		{
			Push(&stack,p);
			p = p->lChild;
		}
		//左子树已经到底了,打印并探寻右子树
		if(!StackIsEmpty(&stack))
		{
			p = Pop(&stack);
			printf("%c ",p->data);
			p = p->rChild;
		}		
	}
}
void InOrderTraverse(Tree T)
{
	SqSTACK stack;
	Tree p = T;
	StackInit(&stack);

	while(p!= NULL || !StackIsEmpty(&stack))
	{
		if(p != NULL)
		{
			Push(&stack,p);
			p = p->lChild;
		} 
		else
		{
			p = Pop(&stack);
			printf("%c ",p->data);
			p = p->rChild;
		}
	}
	StackDestroy(&stack);
}

//非递归遍历先序遍历
/************************************************************
(1)访问根节点;
(2)先序遍历左子树;
(3)先序遍历右子树;

遍历过程:
	定义临时指针变量p指向树节点;
	(1)访问根节点打印其值,保存根节点入栈。
	(2)进入左子树,左子树即为根节点。进入(1)过程;
	(3)
*************************************************************/
void PreOrderTraverse(Tree T)
{
	SqSTACK stack;
	Tree p = T;
	StackInit(&stack);

	while( p || !StackIsEmpty(&stack))
	{
		if(p != NULL)
		{
			printf("-%c-",p->data);
			Push(&stack,p);
			p = p->lChild;
		}
		else
		{
			p = Pop(&stack);
			p = p->rChild;
		}
	}
	
	StackDestroy(&stack);
	
}



//非递归遍历后序遍历
//http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html
/************************************************************
若二叉树为空,则空操作;否则
(1)后序遍历左子树;
(2)后序遍历右子树;
(3)访问根节点;

遍历过程:

要保证根结点在左孩子和右孩子访问之后才能访问,因此
(1)对于任一结点P,先将其入栈。
	a)如果P不存在左孩子和右孩子,则可以直接访问它;
	b)或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。

(2)若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,
	左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
*************************************************************/
void PostOrderTraverse(Tree T)
{
	SqSTACK stack;
	Tree p = T;
	Tree pre = NULL;
	StackInit(&stack);
	Push(&stack,p);
	while(!StackIsEmpty(&stack))
	{
		p = StackGetTop(&stack);
		if((p->lChild == NULL && p->rChild == NULL) ||\
			(pre != NULL &&(p->rChild == pre || p->lChild == pre)))
		{
			printf("<%c>",p->data);
			Pop(&stack);
			pre = p;
		}
		else
		{
			if (p->rChild != NULL)
			{
				Push(&stack,p->rChild);
			}
			if (p->lChild != NULL)
			{
				Push(&stack,p->lChild);
			}	
			p = p->lChild;
		}
	}

	StackDestroy(&stack);

}





#ifndef STACK_H
#define STACK_H
#include "common.h"

#ifdef TREE
#define SElemType Tree
#else 
#define SElemType char
#endif


typedef struct _SqSTACK{
	SElemType *base;
	SElemType *top;
	int stackSize;
}SqSTACK;

extern status StackInit(SqSTACK* stack);
extern status Push(SqSTACK* stack,SElemType e);
extern SElemType Pop(SqSTACK* stack);
extern status StackDestroy(SqSTACK* stack);
SElemType StackGetTop(SqSTACK* stack);
status StackIsEmpty(SqSTACK* stack);
#endif


//#include "common.h"
#include "Stack.h"

status StackInit(SqSTACK* stack)
{
	stack->base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if(!stack->base)
	{
		return ERROR;
	}
	stack->top = stack->base;
	stack->stackSize = STACK_INIT_SIZE;
	return OK;
}

status Push(SqSTACK* stack,SElemType e)
{
	if(stack->top - stack->base >= stack->stackSize)
	{
		SElemType* preBase = stack->base;
		printf("over flow! top = %p memory reallocing ...\n",stack->top);
		stack->base = (SElemType*)realloc(stack->base,(stack->stackSize + STACK_INCREMENT)*sizeof(SElemType));

		if(!stack->base)
		{
			perror("realloc");
			return ERROR;
		}
		stack->stackSize += STACK_INCREMENT;
		stack->top = stack->base + (stack->top - preBase);
	}

	*(stack->top) = e;
	stack->top += 1;
	return OK;
}


SElemType Pop(SqSTACK* stack)
{
	SElemType pop;
	if(stack->base == stack->top)
	{
		printf("error:stack empty!\n");
		return 0;
	}

	pop = *( -- stack->top);
	return pop;
}

status StackDestroy(SqSTACK* stack)
{
	free(stack->base);
	return 0;
}
status StackIsEmpty(SqSTACK* stack)
{
	if(stack->base >= stack->top)
	{
		return TRUE;
	}
	return FALSE;
}

SElemType StackGetTop(SqSTACK* stack)
{
	if(stack->top == stack->base)
	{
		return ERROR;
	}
	return *(stack->top-1);
}


#ifndef _COMMON_H_
#define _COMMON_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <malloc.h>
#include <assert.h>
//typedef int ElemType;

void Debug(int* a,int n,int k);
void Swap(int*a,int* b);

#ifndef BOOL
typedef int BOOL;
#endif

#define TRUE 1
#define FALSE 0
#define OK 1

#ifndef ERROR
#define ERROR -1
#endif

#define OVERFLOW -2
#define ESC 10

#define CHAR 1
#ifdef CHAR
	typedef char ElemType;
#else
	typedef int ElemType;
#endif

#define TREE 1

typedef int status;

#define STACK_INIT_SIZE 100
#define	STACK_INCREMENT 10
#define MAX_INIT_SIZE	10


typedef struct _SQueue{
	ElemType *addr; 
	int head;
	int tail;
	int size;
}SQueue;


typedef struct _SNode{
	struct _SNode *pre;
	struct _SNode *next;
	ElemType element;
}SNode;

typedef struct _Node{
	struct _Node *parent;
	struct _Node *lChild;
	struct _Node *rChild;
	ElemType data;
}Node,*Tree;




#endif




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ZenZenZ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值