单链表
关于线索二叉树,其就是一个二叉树转化为双向链表
先回顾一下单链表
双向链表
之前没有写双向链表,现在补上(刚开始还不是很能接受哈哈哈,亡羊补牢啦)
单链表只有一个指针指向下一个,但要回头却不方便,只能再次从头循环。
而双链表,结点前后都有指针,可以回头看,但是处理某个结点时要对四个指针进行处理,操作较单链表复杂。
双向链表比单链表的每一个结点上多了一个左指针用来指向前驱结点
所以再用的时候操作上多了几步
下面详见。
由此图看每个结点结构分为:
左指针指向前驱
数据域存储内容
右指针指向后继
当然,收尾指针也可以相连接
#include<iostream>
using namespace std;
typedef char elementype;
typedef int Status;
typedef struct DLink
{
elementype data;
struct DLink *lef_p;
struct DLink *rig_p;
}*D_NODE;
//初始化一个双向链表的头结点
Status IniLInk(D_NODE &link)
{
link = new DLink;
link->lef_p = NULL;
link->rig_p = NULL;
return 0;
}
//增加结点
Status CreatLink(D_NODE &link)
{
cout << "please input a element"<< endl;
cin >> link->data;
if (link->data == '#')
{
link->data = NULL;
link->rig_p = NULL;
link = NULL;
return NULL;
}
else//当结点合理时再创建下一个结点body
{
D_NODE body = new DLink;
link->rig_p = body;
body->lef_p = link;
body->rig_p = NULL;//给两个结点之间建立联系
CreatLink(body);
}
return 0;
}
//顺序输出
Status OutLink(D_NODE &link)
{
if (link == NULL)
{
return NULL;
}
if (link != NULL)
{
cout << link->data ;
if (link->rig_p)
{
cout << "->";
OutLink(link->rig_p);
}
}
return 0;
}
//寻找某一结点的前后元素
Status OutLink_x(D_NODE link)
{
if (link == NULL)
{
return NULL;
}
cout <<"Please enter the element you want to find" << endl;
elementype x;
cin >> x;
if (link != NULL)
{
while (link&&link->data != x)
{
link = link->rig_p;
}
if (link->data == x)
{
cout << "Please input the previous node of the element" << endl;
if (link->lef_p != NULL)
{
cout << link->lef_p->data << endl;
}
else
{
cout <<"Sorry! There is no element in the front node" << endl;
}
cout << "Please input the next node of the element" << endl;
if (link->rig_p->data != NULL)
{
cout << link->rig_p->data << endl;;
}
else
{
cout << "Sorry! There is no element in the following node" << endl;
}
}
}
return 0;
}
//插入一个结点 不适用与头插法
Status Insertlink(D_NODE &link)
{
if (link == NULL)
{
return NULL;
}
else
{
D_NODE ins = new DLink;
cout << "Please enter the node element to be inserted" << endl;
cin >> ins->data;
cout << "Please enter the position you want to insert" << endl;
int i,pos;
cin >> pos;
i = 0;
D_NODE p = link;//这一步很重要 如若没有这一步 则插入位置前面的一个之前所有元素空缺。 /*原因:*/
while (p&&i < pos - 1)
{
p = p->rig_p;
++i;
}
if (!p&&i > pos - 1)
{
cout << "error" << endl;
return 0;
}
ins->rig_p = p->rig_p;
p->rig_p->lef_p = ins;
p->rig_p = ins;
ins->lef_p = p;
}
return 0;
}
//删除一个结点 也不适合用于头插法
Status Dellink(D_NODE &link)
{
if (link == NULL)
{
return NULL;
}
else
{
cout <<"Please enter the location of the node to be deleted" << endl;
int pos;
cin >> pos;
int i = 0;
D_NODE p = new DLink;
p = link;
while (p&&i < pos - 1)
{
p = p->rig_p;
++i;
}
if (!p&&i > pos - 1)
{
cout << "error" << endl;
return 0;
}
p = p->rig_p;
p->lef_p->rig_p = p->rig_p;
p->rig_p = p->rig_p->lef_p;
//p->rig_p = p->rig_p->rig_p;
free(p);
//p=p->rig_p->lef_p;
//p = link;
}
return 0;
}
//统计双链表数据个数
Status CountLink(D_NODE &link)
{
int t = 0;
while (link->data!=NULL)
{
t++;
link=link->rig_p;
}
return t;
}
int main()
{
D_NODE link;
cout << "——————" <<"initialization" << "——————"<< endl;
IniLInk(link);
cout << "——————" << "Add a node to end with #" << "——————" << endl;
CreatLink(link);
cout << "——————" << "Sequential output" << "——————" << endl;
OutLink(link);
cout << endl;
cout << "——————" << "Find the elements before and after a node" << "——————" << endl;
OutLink_x(link);
cout << "——————" << "Insert a node" << "——————" << endl;
Insertlink(link);
cout << "——————" << "Sequential output" << "——————" << endl;
OutLink(link);
cout << "——————" << "Del a node" << "——————" << endl;
Dellink(link);
cout << "——————" << "Sequential output" << "——————" << endl;
OutLink(link);
cout << "——————" << "Count link" << "——————" << endl;
int count = CountLink(link);
cout << count << endl;
return 0;
}
线索二叉树
看一下线索二叉树的生成
线索二叉树的应用
当我生成一颗二叉树 再将其转化为线索二叉树时,这颗树就是一个双链表
见处理:
中序线索二叉树
Status InitThread_mid(TB_NODE &tree,TB_NODE &pre)
{
if (tree == NULL)
{
return 0;
}
else
{
InitThread_mid(tree->lchild,pre);
//pre始终在过程中的结点tree的前一个(顺序是按照遍历的来)
//既然pre在前 tree在后
//那么先使tree的左孩子指向pre结点
//再使得pre的右孩子指向tree结点
//在遍历的过程中tree一直变化, pre也在变化
//刚开始没有理解双向链表如何生成 看图可以推一下
if (!tree->lchild)//如果某元素的左孩子不存在的话,则使pre为其它的前驱 使得遍历顺序直接能用指针找到
{
tree->ltag = thread;
tree->lchild = pre;
}
if (pre->rchild == NULL)//如果前驱元素的右孩子不存在的话,使其右孩子指向下一个 即建立后继
{
pre->rtag = thread;
pre->rchild = tree;
}
pre = tree;//保持pre为 前面的元素
//这里原为中序遍历的输出
InitThread_mid(tree->rchild,pre);
}
return 0;
}
寻找某一结点的前后位置
注:二叉树只能找左孩子和右孩子,线索化后寻找所需结点更方便,可以前后找 无需再次循环处理 ,这样一想确实方便了许多
线索二叉树能很快速地求出二叉树节点的前驱节点和后继节点,
算法的复杂度为O(n),虽然普通二叉树遍历求前驱和后继节点复杂度也是O(n),
但线索二叉树的常数因子更小,求前驱和后继节点比普通二叉树遍历更快。
注:先序线索二叉树查找后继节点容易、查找前驱节点困难;
后序线索二叉树查找前驱节点容易、查找后继节点困难;而中序线索二叉树查找后继节点和先驱节点都很容易。
因此,先序和后序线索二叉树应用较少,中序线索二叉树应用更加广泛。
//寻找中序线索二叉树某一结点的前后结点
Status Outtree_x(TB_NODE &tree)
{
if (tree == NULL)
{
return NULL;
}
cout << endl << "please input the element you want to find" << endl;
elementype x;
cin >> x;
if (tree != NULL)
{
while (tree&&tree->data != x)
{
tree = tree->rchild;
}
if (tree->data == x)
{
cout << "Please input the previous node of the element" << endl;
if (tree->lchild->data != NULL)
{
cout << tree->lchild->data << endl;
}
else
{
cout << "Sorry! There is no element in the front node" << endl;
}
cout << "Please input the next node of the element" << endl;
if (tree->rchild->data != NULL)
{
cout << tree->rchild->data << endl;
}
else
{
cout << "Sorry! There is no element in the next node" << endl;
}
}
}
return 0;
}
所有代码 较长 我自己留着以后好回顾 ————如果你也在看 以下可以忽略
#include<iostream>
using namespace std;
typedef int Status;
typedef char elementype;
typedef enum {
Link,thread}Pointertag;//枚举类型 第一个不声明的话就为1,后面依次增加
typedef struct TBree
{
elementype data;
struct TBree *lchild, *rchild;
Pointertag ltag, rtag;
}*TB_NODE,BNODE;
//初始化一个结点
Status IniTree(TB_NODE &tree)
{
tree = new TBree;
tree->lchild = NULL;
tree->rchild = NULL;
return 0;
}
//生成二叉树
Status Creatree(TB_NODE &tree)
{
tree = new TBree;
cout << "Please enter node element" << endl;
cin >> tree->data;
if (tree->data == '#')
{
cout << "The node branch is empty" << endl;
tree=NULL;//如果输入的元素是# 那么该结点为NULL 即双亲指向为NULL
}
else
{
tree->ltag = Link;//初始化 这里应该加不加都可,因为最后的叶子是指向空的
tree->rtag = Link;
cout << "Please enter the " << tree->data << " left child" << endl;
Creatree(tree->lchild);
cout << "Please enter the " << tree->data << " right child" << endl;
Creatree(tree->rchild);
}
return 0;
}
//中序线索二叉树
Status InitThread_mid(TB_NODE &tree,TB_NODE &pre)
{
if (tree == NULL)
{
return 0;
}
else
{
InitThread_mid(tree->lchild,pre);
//pre始终在过程中的结点tree的前一个(顺序是按照遍历的来)
//既然pre在前 tree在后
//那么先使tree的左孩子指向pre结点
//再使得pre的右孩子指向tree结点
//在遍历的过程中tree一直变化, pre也在变化
//刚开始没有理解双向链表如何生成 看图可以推一下
if (!tree->lchild)//如果某元素的左孩子不存在的话,则使pre为其它的前驱 使得遍历顺序直接能用指针找到
{
tree->ltag = thread;
tree->lchild = pre;
}
if (pre->rchild == NULL)//如果前驱元素的右孩子不存在的话,使其右孩子指向下一个 即建立后继
{
pre->rtag = thread;
pre->rchild = tree;
}
pre = tree;//保持pre为 前面的元素
//这里原为中序遍历的输出
InitThread_mid(tree->rchild,pre);
}
return 0;
}
//寻找中序线索二叉树某一结点的前后结点
Status Outtree_x(TB_NODE &tree)
{
if (tree == NULL)
{
return NULL;
}
cout << endl << "please input the element you want to find" << endl;
elementype x;
cin >> x;
if (tree != NULL)
{
while (tree&&tree->data != x)
{
tree = tree->rchild;
}
if (tree->data == x)
{
cout << "Please input the previous node of the element" << endl;
if (tree->lchild->data != NULL)
{
cout << tree->lchild->data << endl;
}
else
{
cout << "Sorry! There is no element in the front node" << endl;
}
cout << "Please input the next node of the element" << endl;
if (tree->rchild->data != NULL)
{
cout << tree->rchild->data << endl;
}
else
{
cout << "Sorry! There is no element in the next node" << endl;
}
}
}
return 0;
}
//前序线索二叉树 同理也可以将其作为双链表处理
Status InitThread_before(TB_NODE &tree, TB_NODE &pre)
{
if (tree == NULL)
{
return 0;
}
else
{
if (tree->lchild == NULL)//建立该结点的前驱
{
tree->ltag = thread;
tree->lchild = pre;
}
if (pre->rchild == NULL)//建立前驱的后继
{
pre->rtag = thread;
pre->rchild = tree;
}
pre = tree;
InitThread_before(tree->lchild, pre);
InitThread_before(tree->rchild,pre);
}
return 0;
}
//后续线索二叉树
Status Initthread_after(TB_NODE &tree, TB_NODE &pre)
{
if(tree == NULL)
{
return 0;
}
else
{
Initthread_after(tree->lchild, pre);
Initthread_after(tree->rchild,pre);
if (tree->lchild == NULL)
{
tree->ltag = thread;
tree->lchild = pre;
}
if (pre->rchild == NULL)
{
pre->rtag = thread;
pre->rchild = tree;
}
pre = tree;
}
}
//当有了线索之后,二叉树可以被认为是一个双向链表
//前序遍历输出 前序 中序 后序的输出部分对应其位置
Status OutTree_before(TB_NODE &tree)
{
if (tree == NULL)
{
//cout << "这是一颗空树"<< endl;
return 0;
}
if (tree != NULL)
{
cout << tree->data<<' ';
}
if (tree->lchild != NULL)
{
OutTree_before(tree->lchild);
}
if (tree->rchild != NULL)
{
OutTree_before(tree->rchild);
}
return 0;
}
//中序遍历输出
Status OutTree_mid(TB_NODE &tree)
{
if (tree == NULL)
{
return 0;
}
if (tree->lchild != NULL)
{
OutTree_mid(tree->lchild);
}
cout << tree->data <<' ';
if (tree->rchild != NULL)
{
OutTree_mid(tree->rchild);
}
return 0;
}
//后序遍历输出
Status Outputafter(TB_NODE &tree)
{
if (tree == NULL)
{
return 0;
}
else
{
if (tree->lchild != NULL)
{
Outputafter(tree->lchild);
//cout << tree->lchild->data << endl;
}
if (tree->rchild != NULL)
{
Outputafter(tree->rchild);
//cout << tree->rchild->data << endl;
}
cout << tree->data <<' ';
}
return 0;
}
int main()
{
TB_NODE tree,pre;
//生成二叉树
Creatree(tree);
//初始化空树
IniTree(pre);
//中序输出二叉树
cout << endl << "——————Middle order output——————" << endl;
OutTree_mid(tree);
//中序线索二叉树
InitThread_mid(tree,pre);
//寻找中序线索二叉树某一结点的前后结点
Outtree_x(tree);
//输出部分
/*cout << "——————Preamble output——————" << endl;
OutTree_before(tree);
cout <<endl<< "——————Middle order output——————" << endl;
OutTree_mid(tree);
cout <<endl<< "——————Sequential output——————" << endl;
Outputafter(tree);*/
return 0;
}