数据结构之二叉树

一、定义

1、二叉树

二叉树是一个有限的结点集合,这个集合或者为空、或者由一个根节点和两棵互不相交的左、右子树组成

2、满二叉树

二叉树的所有分支结点都有左、右孩子,且叶子结点都集中再二叉树的最下一层

3、完全二叉树

若二叉树的所有分支结点只有最下面两层的结点度可以小于2,且最下面一层的叶子结点都依次排列在该层的最左边的位置上。(度为1的结点,要么为1,要么为0)

二、性质

  1. 非空二叉树上的叶子结点等于双分支结点数加1
  2. 非空二叉树的第i层上最多有^{}2^{i-1}个结点(i\geq 1
  3. 高度为h的二叉树,最多有2^{h}-1 个结点
  4. n个(n> 0)结点的完全二叉树的高度为\left \lceil \displaystyle \log_{2}{(n+1)} \right \rceil
  5. 完全二叉树中,层序编号为i的结点
  • i\leq \left \lfloor n/2 \right \rfloori为分支结点
  • n为奇数时,度为1的结点数为0;否则,度为1的结点数为1

  • i的左孩子为2\times i,右孩子为2\times i-1

  • 除根右孩子节点外,结点i的双亲结点为\left \lfloor i/2 \right \rfloor

三、二叉树与树、森林之间的转换

对于树转化为二叉树,是基于数的孩子兄弟存储法。所有的树、森林都可以转化为二叉树,逆向看,所有的二叉树均可以转换为树、森林

1、二叉树变为树、森林

窍门:将二叉树中每个结点的左孩子变为该结点的长子,将该结点的右孩子变为其长子的兄弟

2、树、森林变为二叉树

窍门:将树中每个结点的长子变为该结点的左孩子,将该结点的兄弟变为该结点的

四、存储结构

1、顺序存储

#define MaxSize 100
typedef ElemType SqBinTree[MaxSize];

2、链式存储

typedef ElemType char;
typedef struct node{
  ElemType data;
  struct node* lchild;
  struct node* rchild;
}BTNode;

3、两种存储方式的优缺点

  1. 顺序存储方便查询孩子、双亲,但是对于插入、删除等操作比较麻烦,而且对于右单支树而言,将浪费大量空间
  2. 对于一般二叉树而言,也比较节省空间。访问孩子结点方便,但访问双亲结点难。插入、删除操作简单

五、基本运算及其实现

1、创建二叉树

void CreateBTree(BTNode** bt, char* str) {
	BTNode* cur, * ins;
	InitBTree(&ins);
	SqStack* sq;
	int dir = 0;//标识插入左子树(dir == 0),还是插入右子树(dir == 1)
	InitStack(&sq);
	*bt = NULL;
	while (*str != '\0') {
		switch (*str) {
		case '(':
			Push(&sq, ins);
			dir = 0;
			break;
		case ',':
			dir = 1;
			break;
		case ')':
			Pop(&sq, &cur);
			break;
		default:
			InitBTree(&ins);
			ins->val = *str;
			if (*bt == NULL)
				*bt = ins;
			else {
				GetTop(sq, &cur);
				if (dir == 0)
					cur->lchild = ins;
				else
					cur->rchild = ins;
			}
			break;
		}
		str++;
	}
}

2、销毁二叉树

void DestroyBTree(BTNode** bt) {
	if ((*bt) == NULL)
		return;
	DestroyBTree(&((*bt)->lchild));
	DestroyBTree(&((*bt)->rchild));
	free(*bt);
}

3、寻找结点

BTNode* FindNode(BTNode* bt, BTElem target) {
	if (bt == NULL)
		return NULL;
	else if (bt->val == target)
		return bt;
	else {
		BTNode* mid;
		mid = FindNode(bt->lchild, target);
		if (mid != NULL)
			return mid;
		else
			return FindNode(bt->rchild, target);
	}
}

4、找孩子结点

BTNode* LchildNode(BTNode* midnode) {
	return midnode->lchild;
}
BTNode* RchildNode(BTNode* midnode) {
	return midnode->rchild;
}

5、求高度

int BTreeHeight(BTNode* bt) {
	if (bt != NULL) {
		return BTreeHeight(bt->lchild) > BTreeHeight(bt->rchild) ? (BTreeHeight(bt->lchild) + 1) : (BTreeHeight(bt->rchild) + 1);
	}
	else
		return 0;
}

6、输出二叉树

void DisplayBTree(BTNode* bt) {
	if (bt == NULL)
		return;
	printf("%c", bt->val);
	if (bt->lchild != NULL || bt->rchild != NULL) {
		printf("(");
		DisplayBTree(bt->lchild);
		if (bt->rchild != NULL)
			printf(",");
		DisplayBTree(bt->rchild);
		printf(")");
	}
}

7、先序,中序,后续遍历(递归)

void PreOrderByRecursion(BTNode* bt) {
	if (bt != NULL) {
		printf("%c\t", bt->val);
		PreOrderByRecursion(bt->lchild);
		PreOrderByRecursion(bt->rchild);
	}
}
void InOrderByRecursion(BTNode* bt) {
	if (bt != NULL) {
		InOrderByRecursion(bt->lchild);
		printf("%c\t", bt->val);
		InOrderByRecursion(bt->rchild);
	}
}
void PostOrderByRecursion(BTNode* bt) {
	if (bt != NULL) {
		PostOrderByRecursion(bt->lchild);
		PostOrderByRecursion(bt->rchild);
		printf("%c\t", bt->val);
	}
}

8、先序,中序,后续遍历(非递归)

void PreOrderByStack1(BTNode* bt) {
	BTNode* tmp;
	SqStack* st;
	InitStack(&st);
	Push(&st, bt);
	while (!StackEmpty(st)) {
		Pop(&st, &tmp);
		printf("%c\t", tmp->val);
		if (tmp->rchild != NULL)
			Push(&st, tmp->rchild);
		if (tmp->lchild != NULL)
			Push(&st, tmp->lchild);
	}
	printf("\n");
	DestroyStack(&st);
}
void PreOrderByStack2(BTNode* bt) {
	BTNode* tmp = bt;
	SqStack* st;
	InitStack(&st);
	while (!StackEmpty(st) || tmp != NULL) {
		while (tmp != NULL) {
			printf("%c\t", tmp->val);
			Push(&st, tmp);
			tmp = tmp->lchild;
		}
		if (!StackEmpty(st)) {
			Pop(&st, &tmp);
			tmp = tmp->rchild;
		}
	}
	printf("\n");
	DestroyStack(&st);
}
void InOrderByStack(BTNode* bt) {
	BTNode* tmp;
	SqStack* st;
	InitStack(&st);
	tmp = bt;
	while (!StackEmpty(st) || tmp != NULL) {
		while (tmp != NULL) {
			Push(&st, tmp);
			tmp = tmp->lchild;
		}
		if (!StackEmpty(st)) {
			Pop(&st, &tmp);
			printf("%c\t", tmp->val);
			tmp = tmp->rchild;
		}
	}
	printf("\n");
	DestroyStack(&st);
}
void PostOrderByStack(BTNode* bt) {
	BTNode* tmp, * visited;
	bool flag;//flag和visited的设置有什么用?
	SqStack* st;
	InitStack(&st);
	tmp = bt;
	do {
		while (tmp != NULL) {//处理左子树
			Push(&st, tmp);
			tmp = tmp->lchild;
		}
		visited = NULL;
		flag = true;
		while (!StackEmpty(st) && flag) {//为什么要连续判断栈顶是否可访问->不这样,会重复访问一些结点,会重复访问什么结点呢?
			GetTop(st, &tmp);
			if (tmp->rchild == visited) {//此处,有几种情况?2种
				printf("%c\t", tmp->val);
				Pop(&st, &tmp);
				visited = tmp;
			}
			else {
				tmp = tmp->rchild;
				flag = false;
			}
		}
	} while (!StackEmpty(st));//为什么循环条件不是"!StackEmpty(st) || tmp != NULL"?
	printf("\n");
	DestroyStack(&st);
}

9、层次遍历

void LevelOrder(BTNode* bt) {
	BTNode* tmp;
	SqQueue qu;
	qu.front = qu.rear = -1;
	if (bt != NULL)
		qu.data[++(qu.rear)] = bt;
	while (qu.front < qu.rear) {
		tmp = qu.data[++(qu.front)];
		printf("%c\t", tmp->val);
		if (tmp->lchild != NULL)
			qu.data[++(qu.rear)] = tmp->lchild;
		if (tmp->rchild != NULL)
			qu.data[++(qu.rear)] = tmp->rchild;
	}
	printf("\n");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值