数据结构二叉树的基本操作(C语言)

要求

  • 数据域为字符的一棵二叉树用广义表形式输入,创建一个采用二叉链表存储的二叉树,并按广义表的形式输出这棵二叉树。
  • 完成这棵二叉树的中序遍历的递归算法。
  • 完成这棵二叉树的中序遍历的非递归算法。

主要写的是链式二叉树的遍历操作。 

目录

//主函数

 //用广义表形式初始化

//用队列初始化

//用广义表形式输出

//递归的遍历

 //非递归的遍历

总结:


//主函数

typedef struct BTree {
	ElemType data;
	struct BTree* left;
	struct BTree* right;
}*BTree,BT;

int main(){
	BTree root=NULL;
	printf("广义表形式初始化树,如:a(b(d,e),c(f,g)):\n");
	root = InitTree(root);
	printf("一广义表形式输出:\n");
	Print(root);
	printf("\n");
	int chose = 0;
	while (1) {
		printf("========================\n");
		printf("1、***前序遍历***\n2、***中序遍历***\n3、***后序遍历***\n");
		printf("4、非递归前序遍历\n5、非递归中序遍历\n6、非递归后序遍历\n");
		printf("========================\n");
		scanf("%d", &chose);
		switch (chose) {
		case 1:PreOrder(root);printf("\n"); break;//递归前序遍历
		case 2:InOrder(root);printf("\n"); break;//递归中序遍历
		case 3:PostOrder(root);printf("\n"); break;//递归后序遍历
		case 4:PreOrder2(root); printf("\n"); break;//非递归前序遍历
		case 5:InOrder2(root); printf("\n"); break;//非递归中序遍历
		case 6:PostOrder2(root); printf("\n"); break;//非递归后序遍历
		default:printf("退出\n"); return 0;
		}
	}
	return 0;
}

 //用广义表形式初始化

//广义表形式初始化
BTree InitTree(BTree root) {
	BTree stack[15];	//创建一个栈
	int top = -1;		//栈顶指针
	int k = 0;			//儿子标志
	ElemType ch;		//接收数据
	BTree new=NULL;		//新节点
	while ((ch = getchar()) != '\n') {
		switch (ch) {
			//遇见'('说明有左儿子
		case '(':
			k = 1;
			stack[++top] = new;
			break;
			//遇见')'说明儿子完了,要退栈到父亲结点
		case ')':
			top--;
			break;
			//遇见','说明有右儿子
		case ',':
			k = 2;
			break;
		default:
			new = (BTree)malloc(sizeof(BT)); //分配空间
			if (new == NULL)
				break;
			new->left = new->right = NULL;		//初始化
			new->data = ch;						//赋值
			if (root == NULL)					//根节点
				root = new;
			switch (k) {
			case 1:stack[top]->left = new; break;	//连接左儿子
			case 2:stack[top]->right = new; break;	//连接右儿子
			}
		}
	}
	return root;
}

//用队列初始化

//队列初始化树
#define MAXSIZE 15
BTree InitTree(BTree root) {
	BTtree Queue[MAXSIZE+1];	//创建队,+1防止溢出
	int front = 1;				//队首指针,从1开始方便后面的左右儿子判断
	int rear = 0;				//队尾指针。从0开始方便后面计算
	BTree new;				//新节点
	ElemType ch;				//结点值
	while ((ch = getchar()) != '\n') {
		new = (BTree)malloc(sizeof(BT));
		new->data = ch;
		new->left = new->right = NULL;
		Queue[++rear] = new;	//入队
		if (root == NULL)
			root = new;			
		if (rear == front * 2)	//判断是否是root的左儿子
			Queue[front]->left = Queue[rear];
		if (rear == front * 2 + 1) {	//判断是否是root的右儿子
			Queue[front]->right = Queue[rear];
			front++;			//如果是右儿子那代表着这个结点已经操作完了,就将front加1(出队)
		}
	}
	return root;
}

//用广义表形式输出

//广义表形式输出
void Print(BTree root) {
	BTree p = root;//用p代替root,改变p不影响root
	if (p == NULL)
		return;
	printf("%c", p->data);
	//有儿子就打印左括号
	if (p->left||p->right)
		printf("(");
	Print(p->left);
	//有右儿子才打印逗号
	if (p->right)
		printf(",");
	Print(p->right);
	//到这说明遍历完了右子树回到了父亲结点,打印右括号
	if (p->left || p->right)
		printf(")");
}

//递归的遍历

1、前序遍历

数据结构二叉树的基本操作(C语言)_第1张图片

2、中序遍历 

数据结构二叉树的基本操作(C语言)_第2张图片

 3、后序遍历

数据结构二叉树的基本操作(C语言)_第3张图片

//前序遍历
void PreOrder(BTree root) {
	if (root == NULL)
		return;
	BTree p = root;
	printf("%c", p->data);
	PreOrder(p->left);
	PreOrder(p->right);
}

//中序遍历
void InOrder(BTree root) {
	if (root == NULL)
		return;
	BTree p = root;
	InOrder(p->left);
	printf("%c", p->data);
	InOrder(p->right);
}

//后序遍历
void PostOrder(BTree root) {
	if (root == NULL)
		return;
	BTree p = root;
	PostOrder(p->left);
	PostOrder(p->right);
	printf("%c", p->data);
}

 //非递归的遍历

1、标准写法:

//非递归前序遍历
void PreOrder2(BTree root) {
	if (root == NULL)
		return;
	BTree p = root;					//代替root移动
	BTree stack[15];				//创建一个栈
	int top = -1;					//栈顶指针
		//书上写法:
	while (p || top > -1) {
		while (p) {
			printf("%c", p->data);
			stack[++top] = p;
			p = p->left;
		}
		p = stack[top--];
		p = p->right;
	}
}

//非递归中序遍历
void InOrder2(BTree root) {
	if (root == NULL)
		return;
	BTree p = root;
	BTree stack[15];
	int top = -1;
	//书上写法:
	while (p || top > -1) {
		while (p) {
			stack[++top] = p;	
			p = p->left;
		}
		p = stack[top--];
		printf("%c", p->data);
		p = p->right;
	}
}

//非递归后序遍历
//1、第一次进栈是为了遍历左子树
//2、第二次进栈是为了遍历右子树
//3、左右遍历完了才能访问根节点
void PostOrder2(BTree root) {
	if (root == NULL)
		return;
	BTree p = root;
	BTree stack1[15];
	int stack2[15];
	int top = 0, b = 0;
	do {
		while (p) {
			stack1[top] = p;
			stack2[top++] = 0;
			p = p->left;
		}
		if (top > 0) {
			p = stack1[--top];
			b = stack2[top];
			if (b == 0) {
				stack1[top] = p;
				stack2[top++] = 1;
				p = p->right;
			}
			else {
				printf("%c", p->data);
				p = NULL;
			}
		}
	} while (top > 0);
}

2、自己写法:

//非递归前序遍历
void PreOrder2(BTree root) {
	if (root == NULL)
		return;
	BTree p = root;					//代替root移动
	BTree stack[15];				//创建一个栈
	int top = -1;					//栈顶指针
	while (p) {						//p不等于NULL时
		printf("%c", p->data);		//输出
		if (p->left||p->right) {	//只要有儿子
			if (p->left) {			//如果有左儿子就入栈
				stack[++top] = p;
				p = p->left;		
				continue;
			}
			else {					//如果没有左儿子就自己变成右儿子
				p = p->right;
				continue;
			}
		}
		if (top == -1)				//top==-1代表着全部元素退栈了,该退出循环了
			return;
		p = stack[top--];			//到这说明是叶子节点,所以p变成它的父亲结点
		p = p->right;				//然后指向右儿子 
	}
}

//非递归中序遍历
void InOrder2(BTree root) {
	if (root == NULL)
		return;
	BTree p = root;
	BTree stack[15];
	int top = -1;
	//先遍历到左边第一个结点并入栈
	while (p->left) {
		stack[++top] = p;
		p = p->left;
	}
	//因为上面循环退出时,最后一个结点没有入栈
	stack[++top] = p;
	while (p) {
		p = stack[top--];			//top--让top指向父节点
		printf("%c", p->data);		//输出当前结点
		if (p->right) {				//如果有右儿子
			p = p->right;			//p变成右儿子
			while (p->left) {		//如果还有左儿子就入栈
				stack[++top] = p;
				p = p->left;
			}
			printf("%c", p->data);	//输出
		}
		if (top == -1)				//出栈完毕
			break;
	}
}

总结:

  • 递归难的地方在于逻辑理解 

  • 非递归后序遍历难写

你可能感兴趣的:(数据结构,c语言,算法,二叉树,1024程序员节)