已知后序与中序输出前序(先序)

已知后序与中序输出前序(先序):
后序:3, 4, 2, 6, 5, 1(左右根)
中序:3, 2, 4, 1, 6, 5(左根右)
分析:因为后序的最后一个总是根结点,令i在中序中找到该根结点,则i把中序分为两部分,左边是左子树,右边是右子树。因为是输出先序(根左右),所以先打印出当前根结点,然后打印左子树,再打印右子树。左子树在后序中的根结点为root – (end – i + 1),即为当前根结点-右子树的个数。左子树在中序中的起始点start为start,末尾end点为i – 1.右子树的根结点为当前根结点的前一个结点root – 1,右子树的起始点start为i+1,末尾end点为end。
输出的前序应该为:1, 2, 3, 4, 5, 6(根左右)

 

已知前序(先序)与中序输出后序(建树)

已知前序(先序)与中序输出后序:
前序:1, 2, 3, 4, 5, 6(根左右)
中序:3, 2, 4, 1, 6, 5(左根右)
分析:因为前序(根左右)最先出现的总是根结点,所以令root为前序中当前的根结点下标(并且同时把一棵树分为左子树和右子树)。start为当前需要打印的子树在中序中的最左边的下标,end为当前需要打印的子树在中序中最右边的下标。递归打印这棵树的后序,递归出口为start > end。i为root所表示的值在中序中的下标,所以i即是分隔中序中对应root结点的左子树和右子树的下标。
先打印左子树,后打印右子树,最后输出当前根结点pre[root]的值。
输出的后序应该为:3, 4, 2, 6, 5, 1(左右根)

使用数组存储邻接表

 

《大话数据结构》读书笔记

【链表】单链表要查找某一个结点时,需要从头结点开始遍历整个链表
当想要从当中一个结点开始遍历整个链表的时候,这是原来的单链表结构解决不了的问题,所以可以用循环链表解决问题
当想要反向遍历整个链表的时候,这是原来的单链表和循环链表解决不了的问题,所以可以用双向链表来解决。正反都可以遍历了
静态链表:便于在不设『指针』类型的高级程序设计语言中使用链表结构。
【栈】1.word、photoshop等动作的撤销键用的是栈
2.web中的后退键
3.两栈共享空间:如果两个人分别一居室各有各的卫生间和厨房客厅,显然空间利用率不高,但是如果改成两居室各有各的房间但是共享卫生间和厨房客厅,这样的空间利用率就显著提高了。 如果我们有两个相同类型的栈,我们为它们各自开辟数组空间,可能一个已经满了但是还有一个还有很多存储空间。我们完全可以用一个数组来存储两个栈,分别放在数组的两个端点处,如果两个栈增加元素,数据从两个端点向中间延伸。{主要适用于两个栈的空间需求有相反关系的时候,也就是一个栈增长时另一个栈在缩短的情况,就像比如买卖股票,一个人买必定是有一个人做出了卖出的操作,所以这样就可以用两栈共享空间存储方法来存储}
4.顺序栈和链栈:虽然在时间复杂度上都是一样的,但是空间性能来说,顺序栈需要事先确定一个固定的长度,可能会存在空间浪费的问题,优势是存取时定位方便,而链栈则要求每一个元素都有指针域,总加了一些内存的开销,对于栈的长度无限制。所以,如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。
!括号匹配的问题很符合栈的先进后出,后进先出的特点
5.栈的应用:递归。递归这种存储了某些数据,并在后面又以存储的逆序恢复这些数据以提供之后使用的需求,这很符合栈的数据结构。
6.栈的应用:四则运算表达式求值:将中缀表达式转化为后缀表达式。规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号(乘除优先加减)则栈顶元素一次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
【队列】操作系统和客服系统、银行排号系统等都是应用了队列功能(排队)。先进先出(FIFO)
循环队列:队列头尾相接的顺序存储结构称为循环队列。
【串】由零个或多个字符组成的有限序列,又名字符串。
“over”“end”“lie”可以认为是“lover”“friend”“believe”的子串。
1.电子词典查找单词实现的原理就是字符串这种数据结构的典型应用。
2.串的比较相当于我们查纸质字典的过程。
3.对于串的顺序存储,有一些变化,串值的存储空间可在程序执行过程中动态分配而得。比如在计算机中存在一个自由存储区,叫做“堆”。这个堆可由C语言的动态分配函数malloc()和free()来管理。
4.串的链式存储结构除了在连接串与串操作时有一定的方便之外,总的来说不如顺序存储灵活,性能也不如顺序存储结构好。
5.串的模式分配:(即为子串的定位操作), 比如说查找一个单词(相当于子串)在一篇文章(相当于一个大字符串)中的定位问题。 是串中最重要的操作之一。
{朴素的模式匹配算法}:
方法:对主串的每一个字符作为子串开头,与要匹配的字符串进行匹配。对主串做大循环,每一个字符开头做T长度的小循环,直到配对成功或全部遍历完成为止。
{KMP模式匹配算法}:
是朴素的模式匹配算法上的提高,大大避免重复遍历的情况。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。
以及KMP模式匹配算法的改进。index函数用于模式匹配,t是模式串,s是原串。返回模式串的位置,找不到则返回0。
6.相对于线性表关注一个个元素来说,我们对串这种结构更多的是关注它的子串应用问题,如查找、替换等操作。
7.所谓回文,就是一个字串的逆转显示,我们只要在串的抽象数据类型中增加一种逆转reverse的操作,就可以实现这样的功能。
【树】
1.前面所讲的栈、队列、串都是一对一的线性结构,而树是一对多的数据结构(树结构)。
2.子树的个数没有限制,但是它们一定是互不相交的。
3.双亲表示法:每个结点除了知道自己是谁之外(data数据域),还知道它的双亲在哪里(parent指针域)。双亲表示法还可以改进,再加一个长子域或者兄弟域
4.孩子表示法:把每个结点的孩子结点排列起来,以单链表作存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。链表+顺序表 链表=child数据域+next指针域;顺序表=data数据域+firstchild头指针域。
这个可以改进为双亲孩子表示法,在顺序表的data和firstchild中间加一个parent域。
5.孩子兄弟表示法:data数据域+firstchild指针域+rightsib指针域。
【二叉树】
1.折半查找算法
2.二叉树的左子树和右边子树是有顺序的,次序不能颠倒。即使树中某结点只有一颗子树,也要区分它是左子树还是右子树。
3.斜树。所有结点都只有左(右)子树的二叉树叫做左(右)斜树。线性表结构就可以理解为树的一种极其特殊的表现形式。
4,二叉树的顺序存储结构:为了避免存储空间的浪费,顺序存储结构一般只用于完全二叉树。
5.二叉链表:lchild指针域+data数据域+rchild指针域
6.就像高考填志愿面临选择哪个城市、哪所大学、具体专业,由于选择方式不同,遍历的次序就完全不同了
7.前序遍历、中序遍历、后序遍历、层序遍历:研究遍历的方法,可以把树中的结点变成某种意义的线性序列,这就给程序通过循环、判断等方式处理实现来提供方便。不同的遍历提供了对结点依次处理的不同方式。
8.线索二叉树:充分利用二叉树中的空指针域,把lchild指向前驱,rchild指向后继。这种指向前驱和后继的指针称为线索加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树。lchild+ltag+data+rtag+rchild 线索化的过程就是在遍历的过程中修改空指针的过程~
9.【赫夫曼树】压缩文件技术:把要压缩的文本进行重新编码,以减少不必要的空间,最基本的压缩编码方法——赫夫曼编码。
带权路径长度WPL最小的二叉树称做赫夫曼树(最优二叉树)。
将有权值的叶子结点按照从小到大的顺序排成一个有序列,取头两个最小权值的结点作为一个新结点N1的两个子结点,则N2的权值为15.将N1替换A与E,插入有序序列中
然后N1与B作为新结点N2的两个子结点插入到有序序列中……
【赫夫曼编码】解决当年远距离通信(电报)的数据传输的最优化问题
要设计长短不等的编码,则必须是任一字符的编码都不是另一个字符的前缀,这种编码称作前缀编码~
10.图的存储结构中比较重要的是邻接矩阵和临界表,分别代表着边集使用数组还是链表的方式存储。十字链表是邻接矩阵的一种升级,而邻接多重表则是邻接表的升级。边集数组更多考虑的是对边的关注。通常稠密图,或存储数据较多,结构修改较少的图,用邻接矩阵要更合适,反之则应该考虑邻接表。