树与二叉树基础算法的比较

一:树的创建

在数据结构中,树是以二叉树的形式储存的。

树转换为二叉树形式分为三步:

⑴加线——树中所有相邻兄弟之间加一条连线。

⑵去线——对树中的每个结点,只保留它与第一个孩子结点之间的连线,删去它与其它孩子结点之间的连线。

⑶层次调整——以根结点为轴心,将树顺时针转动一定的角度,使之层次分明。

转换后结果如图:

所以树的创建算法有两个思路:

1.将树转化为二叉树后,以二叉树中结点的关系输入而创建树。

2.直接以树中结点的关系输入,用代码转换为相应的二叉树。

第一种方法实际就是二叉树创建,只不过是先把树结构转化为二叉树结构,然后再输入创建。

算法思路:

1.每个结点有三个数据信息需要输入,分别是fa,ch,lrflag。(fa是父元素结点的数据,用于找到父元素结点的位置,ch为输入结点的数据,lrflag记录插入父元素的左孩子还是右孩子)

2.每输入一个结点的信息,先进队列,再通过fa在队列中得到父元素结点的地址,最后根据lrflag将新结点插入相应的位置。

3.当输入的ch为指定‘#‘,即无数据时,停止循环。

void CreatBitree2(BiTree *T)  //读边按层次创建二叉树
{
    LinkQueue Q;
    InitQueue(&Q);
    BiTree p,s;
    char fa,ch;
    int lrflag;
    setbuf(stdin,NULL);                                     //清空键盘输入
    scanf("%c%c%d",&fa,&ch,&lrflag);
    while(ch != ‘#‘)
    {
        p = (BiTree)malloc(sizeof(BiNode)); //二叉树结点p用来记录新数据
        p->data = ch;
        p->lchild = p->rchild = NULL;           //置空
        EnQueue(&Q,p);                                  //父结点入队列
        if(fa == ‘#‘)
        {
            *T = p;                                                 //如果fa为# 则p为总的根结点T
        }
        else
        {
            GetHead(Q,&s);
            while(s->data != fa)        //找到插入结点的父结点的位置
            {
                DeQueue(&Q,&s);
                GetHead(Q,&s);
            }
            // 此时s为父结点
            if(lrflag == 0)                     //如果子结点标记为0,将新结点p与父节点lchild连接
            {
                s->lchild = p;
            }
            else if(lrflag == 1)
            {
                s->rchild = p;              //同理,p连上父结点rchild
            }
            else
            {
                free(p);
                printf("输入错误!按任意键重新输入....");    //标志输入错误,新结点释放重新输入
                getch();
            }
        }
        setbuf(stdin,NULL);                             //清空键盘输入
        scanf("%c%c%d",&fa,&ch,&lrflag);
    }
}

第二种方法就是直接输入树中结点,通过代码的处理转化为二叉树结构,与第一种方法的处理顺序是相反的。

这种算法与第一种的二叉树创建的算法有一点区别,因为没有左右孩子,树的结构体定义与二叉树不同,所以不需要lrflag,而是将有相同父元素的结点以兄弟指针连起来。

算法思路:

1.每个结点有二个数据信息需要输入,分别是fa,ch.(fa是父元素结点的数据,用于找到父元素结点的位置,ch为输入结点的数据)

2.每输入一个结点的信息,先进队列,再通过fa在队列中得到父元素结点的地址,如果父元素结点的firstchild指针为空,则firstchild连接上新结点。若不为空,则连上当前父元素的最后一个兄弟结点的nextsibling指针。

3.当输入的ch为指定‘#‘,即无数据时,停止循环。

void CreateCSTree(CSTree *T)//树的按边层次创建
{
    LinkQueue Q;
    InitQueue(&Q);
    CSTree p,s,sign;
    char fa,data;
    printf("请输入新建结点的父元素和子元素的数据:");
    scanf("%c %c",&fa,&data);  //scanf(" %c") 一个空格在加上%c:表示读取遇到的第一个非空格字符
    getchar();
    while(data != ‘#‘)
    {
        s = (CSTree)malloc(sizeof(CSNode));
        s->data = data;
        s->firstchild = s->nextsibling = NULL;
        EnQueue(&Q,s);
        if(fa == ‘#‘)
        {
            *T = s;
        }
        else
        {
            GetHead(Q,&p);
            while(p->data != fa)
            {
                DeQueue(&Q,&p);
                GetHead(Q,&p);
            }
            //此时p为父元素结点地址
            if(p->firstchild == NULL)//父元素的firstchild连接
            {
                p->firstchild = s;
                sign = s;            //父元素firstchild已被连接,用sign记住s;
            }
            else                    //父元素其他孩子连在sign的nextsibling上
            {
                sign->nextsibling = s;
                sign = s;            //依然记住,便于下一个结点连接
            }
        }
        printf("请输入新建结点的父元素和子元素的数据:");
        scanf("%c %c",&fa,&data);
        getchar();
    }
}

二:树的遍历

树的遍历和二叉树的遍历差不多,只是根据结构的调整,没有中序遍历。

不过有两个规则:

1.二叉树的前序遍历是树的前序遍历。

2.二叉树的中序遍历是树的后序遍历。

利用这两个规则可以直接使用二叉树的遍历算法来相应的遍历树。

二叉树的遍历算法先前已经写过总结,移步:http://www.cnblogs.com/ecizep/p/4719553.html

此处不再赘述。

三:根结点到叶子结点所有的路径

二叉树:

二叉树求从根结点到叶子结点的路径可以借助前序递归遍历的思想。

算法思路:

1.按照前序递归的思路遍历二叉树且对每个遍历的结点进栈,但是不访问

2.然后当遇到叶子结点时,按从栈底到栈顶的顺序输出栈中的数据(即为一个根结点到叶子结点的路径),然后出栈叶子结点

3.前序递归遍历的过程不断遇到叶子节点并输出路径,直到根结点出栈

void DispPath(BiTree T,SqStack *s) //输出所有的根到叶子结点的路径
{
    Bitree p;
    if(T)
    {
        Push(s,p);
        if(T->lchild == NULL && T->rchild == NULL)
        {
            PrintStack(*s);
            printf("\n");
        }
        else
        {
            DispPath(T->lchild,s);
            DispPath(T->rchild,s);
        }
        Pop(s),&p);
    }
}

树:

由于树是以二叉树的形式存储的,所以实际的树的叶子结点与二叉树叶子结点不同。

树的叶子节点:firstchild指针为NULL的结点。

除了这个差别带来的算法带来的if条件语句的差异之外,还有一点与二叉树的根到叶子结点算法不同。

都是使用前序递归遍历的思想,但是树一直向firstchild方向遍历,遇到叶子结点,则向兄弟结点nextsibling遍历。

且需要将firstchild结点先出栈后再遍历兄弟结点,所以需要将上述的算法中向右子树的遍历放在出栈之后。

算法思路:

1.从根结点一直向firstchild方向遍历,并进栈。

2.若遍历到叶子结点则输出路径,且出栈叶子结点,然后转向兄弟结点nextsibling。

3.重复1,2步骤

void DispPath(CSTree T,SqStack *s)//输出树从根结点到叶子结点的所有路径
{
    CSTree temp = T;
    if(T)
    {
        Push(s,temp);
        if(T->firstchild == NULL) //第一个孩子结点为空说明当前结点为叶子结点
        {
            PrintStack(*s);
            printf("\n");
        }
        else        //一直向左遍历
        {
            DispPath(T->firstchild,s);
        }
        Pop(s,&temp);
        if(T->nextsibling)    //必须保证firstchild出栈后,才能向兄弟结点遍历
        {
            DispPath(T->nextsibling,s);
        }
    }
}

四:数据插入与删除

数据的插入,二叉树和树都是差不多的,插入结点是叶子结点,都是先找到父结点,然后插入。

二叉树则是分左右孩子,树则是fistchild存在,就插入兄弟结点。

在树中数据的插入

算法思路:

1.根据父元素数据找到父元素的位置

2.若当前父元素firstchild为空,则将数据连到firstchild上,否则则插入到最后一个兄弟结点上。

void SearchCST(CSTree T,char keyword,CSTree *p)//查找插入位置
{
    if(T)
    {
        if(T->data == keyword)
        {
            *p = T;
        }
        if(p)
        {
            SearchCST(T->firstchild,keyword,p);
            SearchCST(T->nextsibling,keyword,p);
        }
    }
}

int Insert(CSTree T,char fa,char data)//数据插入
{
    CSTree pos = NULL,s;                //pos记录新结点插入地址
    if(T == NULL)
    {
        return 0;
    }
    SearchCST(T,fa,&pos);
    if(pos)        //在树中找到插入结点地址
    {
        s = (CSTree)malloc(sizeof(CSNode));
        s->firstchild = s->nextsibling = NULL;
        s->data = data;
        if(pos->firstchild == NULL)//根的第一个孩子不存在则连上firstchild指针
        {
            pos->firstchild = s;
        }
        else                        //根的第一个孩子存在,连上nextsibling末尾
        {
            pos = pos->firstchild;
            while(pos->nextsibling)
            {
                pos = pos->nextsibling;
            }
            pos->nextsibling = s;
        }
        return 1;
    }
    else
    {
        printf("父结点数据输入错误,在树中找不到此结点数据\n");
        return 0;
    }
}

二叉树结构数据的删除分2两种:

1.叶子结点直接删除

2.非叶子结点则删除此结点下的所有子结点

树结构中数据的删除分以下几个情况:

1.当删除结点为根结点时,直接摧毁整棵树

2.当删除结点为firstchild结点时,删除包括firstchild在内的下面的所有子结点

3.当删除结点是nextsibling结点时,删除包括nextsibling在内的下面的所有子结点,同时如果nextsibling不为NULL,则需连接

算法思路和插入差不多,先找到位置,然后根据不同的情况删除当前结点。

int DeletePoint(CSTree *T,char fa,char data) //删除一个结点  因为删除结点可能是树根,所以*T
{
    CSTree p = NULL,s;
    SearchCST(*T,fa,&p); //找父结点位置
    if(fa == ‘#‘)        //删除结点是树根的情况
    {
        CleanCSTree(*T);
        *T = NULL;
        return 1;
    }
    if(p == NULL)
    {
        return 0;
    }
    else  //父结点找到,继续对子结点情况分类
    {
        if(p->firstchild->data == data)    //删除结点是firstchild的情况
        {
            s = p->firstchild;            //记住删除结点地址
            p->firstchild = s->nextsibling;        //连接上后面的结点
            s->nextsibling = NULL;
            CleanCSTree(s);                //清空以删除结点为树根的树
        }
        else                            //删除结点是兄弟结点时
        {
            p = p->firstchild;            //p指向第一个孩子结点
            while(p->nextsibling && p->nextsibling->data != data) //用循环找到要删除的结点
            {
                p = p->nextsibling;
            }
            if(p->nextsibling->data == data)    //此时p状态:p指向删除结点的前一个结点
            {
                s = p->nextsibling;
                p->nextsibling = s->nextsibling; //将p的nextsibling连接到删除结点的后面一个结点
                s->nextsibling = NULL;
                CleanCSTree(s);            //清空以删除结点为树根的树
                return 1;
            }
            else        //没有找到结点,删除失败
            {
                return 0;
            }
        }
    }
    return 1;
}
时间: 2024-10-11 12:21:42

树与二叉树基础算法的比较的相关文章

树、二叉树基础

刚看到堆排序,顺便记录一下关于树的一些基本概念: 前言 前面介绍的栈.队列都是线性结构(linear structure).而树是非线性结构(non-linear structure).因此,树中的元素之间一般不存在类似于线性结构的一对一的关系,更多地表现为多对多的关系.直观地看,它是数据元素(在树中称为节点)按分支关系组织起来的结构.显然,树形结构是比线性结构更复杂的一种数据结构类型. 一.树 树的定义:树是含有n个节点的有穷集合,其中有一个节点比较特殊称为根节点.在图示树时,用一条边连接两个

二叉树基础算法总结

记录一些二叉树的基础算法 二叉树节点结构: typedef struct TreeNode{ int val; struct TreeNode *left; struct TreeNode *right; }TreeNode,*Node; 1.遍历 前.中.后序递归遍历: void pre_order_traversal(TreeNode *root){ if(root! = NULL){ visit(root); pre_order_traversal(root->left); pre_ord

树和二叉树相关算法(一) c/c++

1 //双亲储存结构 2 typedef struct{ 3 ElemType data; 4 int parent; 5 }PTree[MaxSize]; 6 7 //孩子链储存结构 8 const int MaxSons = 10; 9 typedef struct node{ 10 ElemType data; 11 struct node* sons[MaxSons]; 12 }TSonNode; 13 14 //孩子兄弟链储存结构 15 typedef struct tnode{ 16

二叉树基础算法--遍历

二叉树的前序遍历(144. Binary Tree Preorder Traversal) 递归 1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class So

二叉树基础算法--判断两棵二叉树是否相同

https://leetcode.com/problems/same-tree/ 1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution {

数据结构和算法 (二)数据结构基础之树、二叉树

Java面试宝典之二叉树的实现 我们接着上一篇数据结构继续讲解.本章系数据结构之树与二叉树,从这章开始,我们就要介绍非线性结构了,这些内容理解起来比线性表稍难一些,我尽量写的通俗一些,如果读的过程中有任何问题,请按上述方式联系我! 一.树 树 形结构是一类重要的非线性结构.树形结构是结点之间有分支,并具有层次关系的结构.它非常类似于自然界中的树.树结构在客观世界中是大量存在的,例如家 谱.行政组织机构都可用树形象地表示.树在计算机领域中也有着广泛的应用,例如在编译程序中,用树来表示源程序的语法结

我的软考之路(四)——数据结构和算法(2)树和二叉树

上鲍恩描述了数据结构的线性结构,我们引入非线性结构本博客-树和二叉树.我想向大家介绍一些基本概念树,树遍历,然后介绍了二叉树的概念和特征.和二叉树遍历.叉树的对照,总结. 树为了描写叙述现实世界的层次结构,树结构中一个数据元素能够有两个或两个以上的直接后继元素. 树的基本概念: 树的概念是学习树的关键所在.掌握了树的基本概念,学会树与二叉树,so easy. 我通过一棵树来了解树的基本概念.例如以下图 1.结点的度 结点的度是子结点的个数.比如:结点1有三个字结点2,3,4,所以结点1的度为3.

数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构.    a.树是n(≥0)结点组成的有限集合.{N.沃恩}     (树是n(n≥1)个结点组成的有限集合.{D.E.Knuth})      在任意一棵非空树中:        ⑴有且仅有一个没有前驱的结点----根(root).        ⑵当n>1时,其余结点有且仅有一个直接前驱.         ⑶所有结

3、非线性结构--树与二叉树——数据结构【基础篇】

非线性结构--树与二叉树 二叉树的基础知识: 二叉树的特点: 1.每个结点的度<=2 2.二叉树是有序树 二叉树的五种不同的形态: 1.空树 2.一个根结点的根树 3.左子树 4.右子树 5.左右并存的二叉树 二叉树的性质: 性质1:二叉树第i层上的结点数目最多为 2{i-1} (i≥1) 性质2:深度为k的二叉树至多有2{k}-1个结点(k≥1) 性质3:包含n个结点的二叉树的高度至少为log2 (n+1) 性质4:在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2