今天是释然发题解的第二十六天,以后会经常和大家分享学习路上的心得,希望和大家一起进步,一起享受coding的乐趣
本文约2400字,预计阅读10分钟
昨天我们学习了并查集,忘记的小伙伴们可以看一下哦:
今天我们来聊一聊二叉树,明天和大家分享树的问题的相关题目:
定义结点
基础的知识就不说了,无论是在课堂中还是自己课下多少都有听过,只要懂了原理,其实树就很好理解了。保存二叉树结点的方式大同小异,数据域+左孩子和右孩子
二叉树的链式存储结构的特点:
除了指针外,二叉链比较节省存储空间。占用的存储空间与树形没有关系,只与树中结点个数有关。
在二叉链中,找一个结点的孩子很容易,但找其双亲不方便
如果一个二叉树有n个结点,会有2n个指针域,f分支数为n-1,非空指针域有n-1个空指针域的个数就是n+1;
struct node
{
int val;
struct node *lch,*rch;
} ;
public class Node
{
public int value;
public Node left;
public Node right;
//构造函数
public Node(int data)
{
this.value=data;
}
}
树的种类
比如说普通二叉树、完全二叉树、满二叉树、线索二叉树、哈夫曼树、二叉搜索树(排序树)、平衡二叉树、AVL平衡二叉树、红黑树、B树、B+树、堆
线索二叉树
对于n个结点的二叉树,在二叉链存储结构中有n+1个空链域,利用这些空链域存放在某种遍历次序下该结点的前驱结点和后继结点的指针,这些指针称为线索,加上线索的二叉树称为线索二叉树。
这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
注意:线索链表解决了无法直接找到该结点在某种遍历序列中的前驱和后继结点的问题,解决了二叉链表找左、右孩子困难的问题。
(来源百度百科)
二叉查找树
二叉查找树,也叫二叉排序树是满足以下条件的二叉树:
1.左子树上的所有节点值均小于根节点值
2.右子树上的所有节点值均不小于根节点值
3.左右子树也满足上述两个条件
(来源计算机考研复试)
平衡二叉树:(AVL)
二叉树的每个节点的左右子树的高度差的绝对值不超过 11,则二叉树是平衡二叉树。根据定义,一棵二叉树是平衡二叉树,当且仅当其所有子树也都是平衡二叉树,因此可以使用递归的方式判断二叉树是不是平衡二叉树,递归的顺序可以是自顶向下或者自底向上。
(来源leetcode)
红黑树
是一种特定类型的二叉树,它是在计算机科学中用来组织数据比如数字的块的一种结构。若一棵二叉查找树是红黑树,则它的任一子树必为红黑树.
红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但 对之进行平衡的代价较低, 其平均统计性能要强于 AVL .
由于每一颗红黑树都是一颗二叉排序树,因此,在对红黑树进行查找时,可以采用运用于普通二叉排序树上的查找算法,在查找过程中不需要颜色信息.
(来源于百度百科)
下一节呢,用一张图告诉大家算法面试中的考点频率,哪些是重点,哪些只需要了解即可
二叉树的遍历(递归方法)
二叉树的遍历分为前序遍历和中序遍历和后序遍历,可以通过递归或者非递归的方式去访问,递归的方式比较简单:
//前序遍历
void PreOrder(Node *head)
{
if (b==NULL)
return;
printf("%c ",b->data); //访问根结点
PreOrder(b->lch);
PreOrder(b->rch);
}
//中序遍历
void InOrder(Node *b)
{
if (b==NULL)
return;
InOrder(b->lch);
printf("%d ",b->data); //访问根结点
InOrder(b->rch);
}
//后序遍历
void PostOrder(Node *b)
{
if(b==NULL)
return;
PostOrder(b->lch);
PostOrder(b->rch);
printf("%d ",b->data);
}
非递归的方法
非递归的前序遍历
判断结点是否非空,如果非空就继续
根节点压栈,栈非空时每次输出栈顶
先序遍历我们就先压右结点入栈,每次弹出的时候总会先弹出左孩子,这样就保持了先序遍历的顺序
#include<stack>
void PreOrder(Node root)
{
if (root == null)
{
return;
}
stack<Node> stack;
//vector<int> result;
// 先把根节点压栈
stack.push(root);
while (!stack.empty())
{
root = stack.pop();
cout<<root.val;
// 先压右节点
if (root.right != null)
{
stack.push(root.right);
}
// 再压左节点
if (root.left != null)
{
stack.push(root.left);
}
}
printf("\n");
}
二叉树的中序遍历和后序遍历分开说,信息量有点大,我觉得做什么事最重要的是坚持,每天去leetcode刷一道题,一年以后绝对是一条好汉。
好了,今天的二叉树就到这里。
释然每天发布一点自己学习的知识,希望1年后我们也能在ACM的赛场上见面,一起去追寻自己的程序猿之路吧!
后期也会和大家一起分享学习心得和学习经验呢,明天我们不见不散哦!
下期预告:
树的中序遍历
如果大家有什么建议或者要求请后台留言,释然也想和大家一起进步呀!
联系方式:shirandexiaowo@foxmail.com