第五章小结

第五章学习了非线性结构树,数据元素之间存在一对多的关系。二叉树是一种最常用的树形结构,满二叉树和完全二叉树又是两种特殊形态的二叉树。

一、本章知识小结

 

二叉树的二叉链表存储表示:

1 typedef struct BiTNode
2 {
3      TElemType data;
4      struct BiTNode *lchild, *rchild;
5 }BiTNode, *BiTree;

中序遍历的递归算法:

viod InOrderTraverse(BiTree T)
{
    if(T == NULL) return ;
    InOrderTraverse(T->lchild);
    cout<<T->data;
    InOrderTraverse(T->rchild);
}

先序和后序遍历的递归算法与中序类似,只是cout语句的位置不一样。对含有n个结点的二叉树,遍历算法的时间复杂度都为O(n),空间复杂度都为O(n).

 

基于二叉链表的层次遍历

viod level(BiTree T)
{
    queue<BiTree> q;
    BiTree p;
    q.init();
    q.push(T);
    while(!q.empty())
    {
         p=q.front();
         q.pop();
         if(p!=NULL){
             cout<<p->data<<' ';
             q.push(p->lchild);
             q.push(p->rchild);
         }
    }
}

遍历结点的顺序是自上而下,自左向右。在队列里排队的是指针(结点的首地址),所以queue<BiTree> q;

但是理论与实际是有很大差别的,下面是我对于深入虎穴这道题的一些心得体会

二、深入虎穴

这道题已经不能再使用二叉树了,结点数目不再仅限于两个,而是多个,所以我们需要用到新的存储结构,

typedef struct node
{
    int doors;//门的数量 
    int *p;//p指向具体门的编号,把p看作一个整型数组 
}node; 

根据实际的数据输入形式,我们需要一个input()函数建立树且返回根结点,还需要一个查找函数find()返回最远那扇门的编号,因此main()函数是

int main()
{
    node *a;//定义一个动态的整型数组 
    int root;    
    root = input(a); //返回根所在的下标 
    cout<<find(a,root);
    
    return 0;
} 

input函数

int input(node *&a)
{
    int n,i;
    cin>>n;
    bool *vi; 
    a=new node[n+1];
    vi=new bool[n+1];
    for(i=1;i<=n;i++)
    { //将vi数组初始化为false 
        vi[i]=false;
    }
    for(i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        a[i].doors=x;
        a[i].p=new int[x];//x的有效下标是从0到x-1,下面的循环j不能从1开始 
        for(int j=0;j<x;j++)
        {
            cin>>a[i].p[j];
            vi[a[i].p[j]]=true; 
        }
    }
    //找出根在数组的下标
    for(i=1;i<=n;i++)
    {
        if(!vi[i]) break;
    } 
    return i;
}

这里采用的是创建动态数组的方法,虽然只有n扇门,但使用new的时候,创建的数组空间大小为n+1,这是为了数组下标能从1到n,能直接对应第几扇门。

数组的空间大小就决定了下标的有效范围,大小为n的数组,下标只能从0到n-1,在循环中要注意下标的取值。

 

find函数

int find(node *a,int root)
{//从a数组的root下标开始往下搜索,层次遍历的最后一个结点就是最远的 
    int x=0;
    queue<int> q;//定义用于存放的带访问的门编号队列
    q.push(root);//根编号入队
    //当队列不为空
    //x = 出队
    //x后面的门号入队
    while(!q.empty())
    {
        x=q.front();
        q.pop();
        for(int i=0;i<a[x].doors;i++)
        {
            q.push(a[x].p[i]);
        }    
    }
    return x;//答案就是x 
}

队列里排队的是门编号,是int类型,在定义一个队列时,首先要确定其中元素的类型!

这道题是老师带着我们一起完成的,一道题可以用多种的存储结构,但有一些基本的标准,是否能方便大量的数据操作,它的时间复杂度和空间复杂度;要基于这两点来选择合适的存储结构。如这道题还可以选用二维数组实现,但是N的数量是10的5次方,如果使用数组,是不能通过的,所以需要选用别的存储结构。

我认为能将数据正确存储并找到根结点编号,这道题已经成功了一半,理论与实际是有很大差别的,必须实际问题实际分析。遍历算法是解决树问题的基础,只有掌握了遍历算法,才能完成更多的实践。

上次的目标是多做编程题,但树的问题确实是不容易解决,所以没有很好的完成目标;接下来的目标是好好学习图这种更难的数据结构,多打代码。

 

posted @ 2019-05-04 12:14  Jimin~  阅读(189)  评论(1编辑  收藏  举报