
这里可能会有的一个问题是:b有左右两个子节点分别为d和e,为什么右旋的时候要将右子节点e拿到a的左子节点而不是b的左子节点d。 供选择的答案: a:①是特殊的树②不是树的特殊形式③是两棵树的总称④是只有二个根结点的树形结构 b:①左子结点②右子结点③左子结点或者没有右子结点 ④兄弟 c~d: ①最左子结点②最右子结点③最邻近的右兄弟④最邻近的左兄弟⑤最左的兄弟⑥最右的兄弟e:①o(n)②o(n)③o(log2n)④o(log2n) 15、每一棵树都能唯一地转换为它所对应的二叉树,树的这种二叉树表示对树的运算带来很大的好处。决意前行无界缝隙(位置就在大地图下方)-->告别刘备(在仁字房) -->回将军府说其行(如果要邀各城军将入队,这时可选择其一)-->再回岳山客栈找红夜二人-->前行入口(触发对话)-->无界异树,右树道,右莲台(切换玄刁跳跃) -->遇胖熊妖老三(抢劫&怪叔叔性格) -->右莲蓬,取七颗巨莲子补洞(攻打外边妖怪即可取得,补完后则会开启另一通道) -->无界异树,中树道,中莲台-->遇胖熊妖老二(啐啐念性格) -->中莲蓬,再取七颗巨莲子补洞-->无界异树,左树道,左莲台-->遇胖熊妖老大(色胚性格) -->左莲蓬,再取七颗巨莲子补洞-->开启三色走道。
二叉排序树又叫二叉查找树或者二叉搜索树,它首先是一个二叉树,而且必须满足下面的条件:
1)若左子树不空,则左子树上所有结点的值均小于它的根节点的值;
2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值
3)左、右子树也分别为二叉排序树
4)没有键值相等的节点(?可能是因为不好处理键值相等的节点到底是左节点还是右节点吧)
概念就介绍这么多,都是来自网上,下面主要看算法和具体实现代码。
1.定义一个节点类,使节点与二叉树操作分离
class Node {
int value;//节点
Node leftChild;//左子树
Node rightChild;//右子树
Node(int value) {
this.value = value;
}
public void display() {
System.out.print(this.value + "\t");
}
@Override
public String toString() {
// TODO Auto-generated method stub
return String.valueOf(value);
}
}
2.需要实现的二叉树操作

class BinaryTree {
private Node root = null;
BinaryTree(int value) {
root = new Node(value);
root.leftChild = null;
root.rightChild = null;
}
public Node findKey(int value) {}; //查找
public String insert(int value) {}; //插入
public void inOrderTraverse() {}; //中序遍历递归操作
public void inOrderByStack() {}; //中序遍历非递归操作
public void preOrderTraverse() {}; //前序遍历
public void preOrderByStack() {}; //前序遍历非递归操作
public void postOrderTraverse() {}; //后序遍历
public void postOrderByStack() {}; //后序遍历非递归操作
public int getMinValue() {}; //得到最小(大)值
public boolean delete(int value) {}; //删除
}
一、线索二叉树的原理
通过考察各种二叉链表,不管儿叉树的形态如何,空链域的个数总是多过非空链域的个数。准确的说,n各结点的二叉链表共有2n个链域,非空链域为n-1个,但其中的空链域却有n+1个。如下图所示。

因此,提出了一种方法,利用原来的空链域存放指针,指向树中其他结点。这种指针称为线索。
记ptr指向二叉链表中的一个结点,以下是建立线索的规则:
(1)如果ptr->lchild为空,则存放指向中序遍历序列中该结点的前驱结点。这个结点称为ptr的中序前驱;
(2)如果ptr->rchild为空,则存放指向中序遍历序列中该结点的后继结点。这个结点称为ptr的中序后继;
既然双向链表可以多出一个指针域用来指向前一个结点,用llink和rlink区分这两个指针域。链表中每一个元素成为“结点”,每一个结点都是由数据域和指针域组成的,每个结点中的指针域指向下一个结点。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。


其中:
(1)ltag为0时指向该结点的左孩子,为1时指向该结点的前驱;
(2)rtag为0时指向该结点的右孩子,为1时指向该结点的后继;
(3)因此对于上图的二叉链表图可以修改为下图的养子。

二、线索二叉树结构实现
二叉线索树存储结构定义如下:
/* 二叉树的二叉线索存储结构定义*/
typedef enum{Link, Thread}PointerTag; //Link = 0表示指向左右孩子指针;Thread = 1表示指向前驱或后继的线索
typedef struct BitNode
{
char data; //结点数据
struct BitNode *lchild, *rchild; //左右孩子指针
PointerTag Ltag; //左右标志
PointerTag rtal;
}BitNode, *BiTree;
一些常见的选择题考点包括:满二叉树、完全二叉树节点数的计算,由树、二叉树的给出相应的遍历序列,依据二叉树的遍历序列还原二叉树,线索化的实质,计算采用不同的方法线索化后二叉树剩余空指针域的个数,平衡二叉树的定义、性质、建立和四种调整算法以及回溯法相关的问题。 使用三个指针表示前驱,当前和后继节点,每次将当前节点的next指向前驱节点,然后向后遍历直到链表末尾。}不难分析,上述算法的时间复杂度同样为 o(n) 7.6.3 二叉树的线索化算法对--x 树的线索化,就是把二叉树的二叉链表存储结构中结点的所有空指针域改造成指向某结点在某种遍历序列中的直接前驱或直接后继的过程, 因此, 二叉树的线索化过程只能在对二叉树的遍历过程中进行。
中序遍历线索化的递归函数代码如下:

BiTree pre; //全局变量,始终指向刚刚访问过的结点
//中序遍历进行中序线索化
void InThreading(BiTree p)
{
if(p)
{
InThreading(p->lchild); //递归左子树线索化
//===
if(!p->lchild) //没有左孩子
{
p->ltag = Thread; //前驱线索
p->lchild = pre; //左孩子指针指向前驱
}
if(!pre->rchild) //没有右孩子
{
pre->rtag = Thread; //后继线索
pre->rchild = p; //前驱右孩子指针指向后继(当前结点p)
}
pre = p;
//===
InThreading(p->rchild); //递归右子树线索化
}
}
中间部分代码做了这样的事情:
因为此时p结点的后继还没有访问到,因此只能对它的前驱结点pre的右指针rchild做判断,if(!pre->rchild)表示如果为空,则p就是pre的后继,于是pre->rchild = p,并且设置pre->rtag = Thread,完成后继结点的线索化。如图:
if(!p->lchild)表示如果某结点的左指针域为空,因为其前驱结点刚刚访问过,赋值了pre,所以可以将pre赋值给p->lchild,并修改p->ltag = Thread(也就是定义为1)以完成前驱结点的线索化。
完成前驱和后继的判断后,不要忘记当前结点p赋值给pre,以便于下一次使用。
有了线索二叉树后,对它进行遍历时,其实就等于操作一个双向链表结构。
和双向链表结点一样,在二叉树链表上添加一个头结点,如下图所示,并令其lchild域的指针指向二叉树的根结点(图中第一步),其rchild域的指针指向中序遍历访问时的最后一个结点(图中第二步)。反之,令二叉树的中序序列中第一个结点中,lchild域指针和最后一个结点的rchild域指针均指向头结点(图中第三和第四步)。这样的好处是:我们既可以从第一个结点起顺后继进行遍历,也可以从最后一个结点起顺前驱进行遍历。


遍历代码如下所示。
//t指向头结点,头结点左链lchild指向根结点,头结点右链rchild指向中序遍历的最后一个结点。
//中序遍历二叉线索树表示二叉树t
int InOrderThraverse_Thr(BiTree t)
{
BiTree p;
p = t->lchild; //p指向根结点
while(p != t) //空树或遍历结束时p == t
{
while(p->ltag == Link) //当ltag = 0时循环到中序序列的第一个结点
{
p = p->lchild;
}
printf("%c ", p->data); //显示结点数据,可以更改为其他对结点的操作
while(p->rtag == Thread && p->rchild != t)
{
p = p->rchild;
printf("%c ", p->data);
}
p = p->rchild; //p进入其右子树
}
return OK;
}
说明:
(1)代码中,p = t->lchild;意思就是上图中的第一步,让p指向根结点开始遍历;
在单向链表(c++实现)中,链表的最后一个节点的nex指针指向null,而所谓的循环单向链表即是指链表的最后一个节点的next指针指向首节点(注意不是头节点,头节点是方便链表操作而存在的结构体变量)。循环双链表终端结点的next指针指向表头结点,头结点的prior指针指向表尾结点。只要将单链表的最后一个指针域(空指针)指向链表中第一个结点即可(这里之所以说第一个结点而不说是头结点是因为,如果循环单链表是带头结点的则最后一个结点的指针域要指向头结点。
(3)while(p-ltag == Link)这个循环,就是由A->B->D->H,此时H结点的ltag不是link(就是不等于0),所以结束此循环;
(4)然后就是打印H;
(5)while(p->rtag == Thread && p->rchild != t)序列二叉排序树,由于结点H的rtag = Thread(就是等于1),且不是指向头结点。因此打印H的后继D,之后因为D的rtag是Link,因此退出循环;
(6)p=p->rchild;意味着p指向了结点D的右孩子I;
(7).....,就这样不断的循环遍历,直到打印出HDIBJEAFCG,结束遍历操作。
从这段代码可以看出,它等于是一个链表的扫描,所以时间复杂度为O(n)。
使用两个指针分别遍历两个链表,每次取出序列链表的一个序号后,根据该序号,到达目标链表指定节点。}不难分析,上述算法的时间复杂度同样为 o(n) 7.6.3 二叉树的线索化算法对--x 树的线索化序列二叉排序树,就是把二叉树的二叉链表存储结构中结点的所有空指针域改造成指向某结点在某种遍历序列中的直接前驱或直接后继的过程, 因此, 二叉树的线索化过程只能在对二叉树的遍历过程中进行。嵌入水印对音频信号波形的影响受到的关注不多.分析得出改变采样序列离散余弦变换(discretecosinetransform,dct)域某个交流系数时,逆dct后幅值变化服从余弦曲线,改变离散小波变换(discretewavelettransform,dwt)域某个近似系数时,重构后采样序列幅值变化呈现为所选小波的尺度函数.并对在dwt-dct混合域嵌入水印做了讨论.通过推导和实验,得到采样点的改变量与dct域低频系数的改变量、dwt域近似系数的改变量及混合域低频系数的改变量成线性关系.所得结论有助于发现嵌入算法带给采样点序列的不连续变化而使含水印音频产生可听噪声,也有助于提高水印的嵌入效率.。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-111389-1.html
第一