二叉树Notes

相比数组与链表

1.数组存储方式:
优:可以直接通过下标访问数组元素,效率高。对于有序数组,直接采用二分搜索就OK
缺:增删效率太低,因为移动了差不多整个数组
2.链表存储方式:
优:增删效率高
缺:检索效率低,每次要从head结点开始搜索
3.树存储方式:
能够提高存储,读取数据的效率

二叉树

粗略定义:
每个结点最多只能有两个子结点的一种形式

这颗二叉树共有三层,且是一颗满二叉树
路径:从root结点到当前结点的路线
树的高度:最大层数
子结点:eg ④和⑤均为②的子结点
满二叉树:所有叶子结点均在最后一层,结点总数为2^n-1;
完全二叉树:所有的叶子结点均在最后一层或倒数第二层,且最后一层的叶子结点在左边连续,倒数第二层的叶子结点在右边连续

几种遍历(递归)

1.前序遍历
即先输出父结点,再依次遍历左子树和右子树
代码:

void preOrder(Node* node) {
	if (node == NULL)return;
	cout << node->data << " ";
	preOrder(node->left);
	preOrder(node->right);
}

2.中序遍历
即先遍历左子树,再输出父结点,最后遍历右子树
代码:

void infixOrder(Node* node) {
	if (node == NULL)return;
	infixOrder(node->left);
	cout << node->data << " ";
	infixOrder(node->right);
}

3.后序遍历
即先依次遍历左右子树,最后再输出父结点
代码:

void postOrder(Node* node) {
	if (node == NULL)return;
	postOrder(node->left);
	postOrder(node->right);
	cout << node->data << " ";
}

用递归代码是真的简洁又清晰

4.层序遍历
最接近人的思维的一种遍历…
用队列实现,先进先出

void levelOrder(Node* node){
	if(node == NULL)return;
	queue<Node*>que;
	que.push(node);
	while(!que.empty()){
		Node* tmp = que.front();
		que.pop();
		cout << tmp->data << " ";
		if(tmp->left)que.push(tmp->left);
		if(tmp->right)que.push(tmp->right);
	}
}

用C语言描述

void levelOrder(Node* node){
	Node* tree[100];
	Node* tmp;
	int front = 0, rear = 0;
	tree[rear++] = node;
	while(front != rear){
		tmp = tree[front++];
		printf("%c ",tmp->data);
		if(tmp->left)tree[rear++]=tmp->left;
		if(tmp->right)tree[rear++]=tmp->right;
	}
}

5.垂直输出

struct Location {
	int x, y;
};
void gotoxy(int x, int y) {
	static int level = 0;
	int w = 0;
	if (y == 0) {
		level = 0;
		w = 0;
	}
	if (y != level) {
		cout << endl;
		w = 0;
		level++;
	}
	cout.width(x - w);
	w = x;
}
template<class T>
void printBtree(BTNode<T>* root, int width) {
	if (root == NULL)return;
	int level = 0, offset = width / 2;
	queue<BTNode<T>*>q;
	queue<Location>lq;
	q.push(root);
	Location floc, cloc;
	floc.x = offset;
	floc.y = level;
	lq.push(floc);
	while (!q.empty()) {
		BTNode<T>* cur = q.front();
		q.pop();
		floc = lq.front();
		lq.pop();
		gotoxy(floc.x, floc.y);
		cout << cur->data;
		if (floc.y != level) {
			level++;
			offset /= 2;
		}
		if (cur->left) {
			q.push(cur->left);
			cloc.x = floc.x - offset;
			cloc.y = floc.y + 1;
			lq.push(cloc);
		}
		if (cur->right) {
			q.push(cur->right);
			cloc.x = floc.x + offset;
			cloc.y = floc.y + 1;
			lq.push(cloc);
		}
	}
	cout << endl;
}

二叉树查找

对应着几种遍历,查找也有三种
1.先序查找

Node* preSearch(Node* node, int key) {
	if (node == NULL)return;
	if (node->data == key)return node;
	Node* res = NULL;
	if (node->left) {
		res = preSearch(node->left, key);
	}
	if (res)return res;
	if (node->right) {
		res = preSearch(node->right,key);
	}
	return res;
}

其他两种大同小异,就不展示了

删除结点

一般来说,若删除的是叶子结点,则直接删除该结点即可
若删除的是非叶子结点,则要删除该子树
代码:

void deleNode(Node* node, int key) {
	if (!node)return;
	if (node->left && node->left->data == key) {
		node->left = NULL;
		return;
	}
	if (node->right && node->right->data == key) {
		node->right = NULL;
		return;
	}
	if (node->left) {
		deleNode(node->left, key);
	}
	if (node->right) {
		deleNode(node->right, key);
	}
}

至于说这里为什么不考虑当前结点,因为后面我们传进去的参数会是root,在那里进行判断即可
当然,也可以在此处进行判断

顺序存储二叉树

特点
使用二叉完全树
第n个元素的左结点索引是2n+1
第n个元素的右结点索引是2n+2
第n个元素的父结点索引为(n-1)/2
那么
此时的先序遍历等价于

void PreO(int index) {
		if(arr.length==0||arr==null) {
			printf("Empty ArrBT");
			return;
		}
		printf(arr[index]);
		if((index*2+1)<arr.length) {
			PreO(index*2+1);
		}
		if(index*2+2<arr.length) {
			PreO(index*2+2);
		}
	}

核心思想完全一样,所以说可以用数组来简单模拟二叉树

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值