树和二叉树的存储结构、二叉树的先、中、后遍历的递归和非递归、层次遍历总结,有向图和无向图的存储结构。

        树和二叉树的存储结构都可以分为顺序存储结构和链式存储结构。

        树的顺序存储结构也称作是“父亲存储结构”,其构成一个数组,数组的下标表示的是树的节点序号,里面存储的是自己的父亲节点序号(第一个的父亲设为-1)。

        树的链式存储结构也称作是“孩子存储结构”,首先建立一个结构体数组,右节点的data和指向孩子节点的指针域,将自己所有的孩子都挂在结构体指针的后面。这种也叫做“邻接表”的方式

        二叉树的顺序存储法借鉴了树的顺序存储法,也是设置了一个数组,但是为了能让孩子和父亲同时找到对方,即规定了父亲和孩子之间下标的关系,如果从0开始的话,父亲的下标是i,左孩子的下标是2i+1,右孩子的下标是21+2,但是这样的方式只适用于完全二叉树

        二叉树的链式存储方式也借鉴了邻接表的方式,但邻接表的方式主要是为了方便树能将很多孩子节点挂在链上,但是二叉树只有两个孩子节点,而且有左右孩子之分,所以可以设置一个结构体,中间是data,左边是左孩子指针,右边是有孩子指针,按照二叉树的形状排列就好了。

        (顺便说一下森林的链式存储结构,可以将森林转化成二叉树之后,然后使用二叉树的链式存储结构就好了,这样的结构叫做“孩子兄弟存储方式。”

        二叉树的先序、中序、后序遍历的方向是根左右、左根右、左右根。

        二叉树的三种遍历在理解上还是很容易理解的,可以看做包围了整棵树的一对箭头,每个节点都会被这堆箭头访问三次,先序就是第一次访问的序列,中序就是第二次访问的序列,后序就是第三次访问的序列。其中递归代码也是容易实现的。

        二叉树的非递归算法就需要了解其整个过程。这个过程借助了自己设计的一个栈。

        首先是先序遍历的非递归算法,首先将根节点压入栈中,然后出栈访问,并将自己的左右节点也压入栈中,顺序是先右后左(这样左边的先出栈),然后再出栈,然后再重复相同的过程就好了。        

        其次是后序遍历的非递归算法,说道后序遍历的算法,必须要提到后序遍历序列的逆序列,叫做逆后序序列,这个序列是根右左,刚好只要将先序遍历的非递归算法的压入栈的顺序改变一下就好了,先压左后压右(为了先让右出栈),最后将访问输出的再压入一个栈中,最后再将栈中的序列输出就变成了后序序列。

        最后是中序遍历序列的非递归算法,这个描述起来有点复杂,先让指针一直移动到最左边的节点,不断将路途中的元素压入栈中,直到到头了,即左孩子是空的,然后选择栈顶元素出栈(即自己出栈)访问这个节点并同时查看其右节点,如果有右节点存在那么就重复上述的过程如果右节点也是空的,表示这个子树访问完毕,再选择栈顶的元素出栈即自己的父亲节点出栈),然后访问,并按照上述的程序继续执行下去就好了。

        二叉树的层次遍历和上述的非递归算法是很相像的。其借助了一个队列。首先将根节点压入队列中,然后出队访问,然后将这个节点的左右孩子节点都压入队列中,先左后右(因为队列是先进先出,所以左孩子可以先出来),然后就是出队左孩子节点,访问,然后接着循环就好了。

        有向图和无向图的顺序存储结构和链式存储结构。

        有向图和无向图的顺序存储结构都是采用了“邻接矩阵”的方式,也就是采用一个二维数组,左为行标,上为列标,分别记录点和点之间是否有联系,有的为1,没有为0,其次信息还可以填权重有向图的邻接矩阵不是实对称矩阵,而无向图是实对称矩阵。

      有向图和和无向图的链式存储结构可以用“邻接表”的形式来表示,这个方式有向图和无向图还是有所不同的,有向图的话因为有出度和入度,所以一个邻接表后面挂上的要么是出度,要么是入度,所以有两种情况,而无向图由于一条边可以看做是双方的路径,所以在邻接表中就表现为有重复的表现同一条路径,比如:A的后面挂着B,B的后面挂着A,这样浪费了存储空间。所以综上所述,邻接表的方式不能解决有向图既能找到出度又能找到入度的问题,也不能解决无向图重复链接浪费存储空间的问题,所以需要各自再设计一个链式存储结构。

        十字链表:有向图采用十字链表的方式。

        

         因为是有向图,所以结构体节点都是有in和out的指针,同时其余的结构体都是边结构体。out表示的是这个节点,比如A节点,指向的边结构体,同时指向是边结构体(不是指向边节点的in指针),然后边结构体延续了上述的邻接表的特点用边结构体的out指针指向还从A节点出来的其他边(这个很重要,不要搞混),如果没有从A节点出来的边之后,那么将最后的边节点的out指针变为空。in的操作是同理的。

        说明一下,节点结构体数组的out是用来指向边结构体的,而In是用来指向“那些指向节点结构体”的边结构体的。而边结构体数组的out是当节点结构体使用的是out的时候,指向被节点结构体指向的边结构体的,即用来链接兄弟边结构体的(这个就是邻接表的性质)当节点结构体使用out那么边结构体全部使用out,如果节点结构体使用in,那么边结构体使用in。

        邻接多重表:无向图采用邻接多重表的方式。

        

         由于无向图的边是没有方向的,所以一条边表示的是两个方向的事情,比如0-1,可能是从0连接上其他的边,也可能是1连接上其他的边,所以边节点有两个指针。而由于无向图没有出度和入度之分,所以节点结构体只有一个指针。

        规则是这样的:边结构体的指针作用其实也是连接兄弟边结构体,和十字链表不一样是没有In和out,比如0-1这个边,0后面的指针指向带有0的兄弟节点,然后这个兄弟节点中的0的指针再指向后面带有0的兄弟节点,因为无向图没有方向的约束,所以可以无脑连接,直到最后一个带0的,其后面的指针就可以填NULL了。所以总结就是:从节点结构体0出来,不断地连接带有0的边结构体,直到没有,唯一需要注意的用0后面的指针指向下一个带有0的结构体,仅此而已。其他的数字也是这样的。

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值