数据结构-大学的数据统计问题

摘  要

树是一种重要的非线性数据结构,直观地看,它是数据元素(在树中称为结点)按分支关系组织起来的结构,很象自然界中的树那样。树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可用树形象表示。树在计算机领域中也得到广泛应用。因此利用树来对数据的存储和归纳是简化数据统计的重要措施。本次实验目的为掌握树的逻辑结构和存储结构,熟练使用树遍历算法进行问题的求解。21世纪是一个经济高速发展、社会不断变革的时代,可以称之为大数据时代。在这种时代背景之下,怎样才能对各种各样的数据进行统计和归纳,获取有效的信息为我们服务,已成为摆在我们面前的重要工作课题之一。而随着高考的临近,各大高校对新生的录取工作也随之展开。每到开学之际,对大学中各个学院、专业、班级及其人数的统计与归纳更是重中之重。所以利用合理的统计方法是对大学数据统计的重要措施。

关键词:数据统计  大数据  树的存储结构  树的逻辑结构

章  绪  论

    1. 课设主要研究问题

1.1.1 问题描述

1.编写文件tree.h,实现树的孩子链存储结构。

2.使用tree.h,编写程序exp7.c实现大学的数据统计。

某大学的组织机构如下表所示,该数据存放在文本文件table.txt中(存储格式自定义),要求采用树存储并完成以下功能(可参课本例题7.3使用递归算法实现,也可考虑利用栈或队列进行非递归算法实现):

a.从table.txt文件中读数据到R数组中(数组数据类型自定义),由数组创建树T。b.采用括号表示输出树T。c.求计算机学院的专业数和班级数。c.求电信学院的学生数。e.销毁树。

1.2 课设应用的理论知识

1.2.1 树的定义

线性表、栈、队列、串是一对一的数据结构,而树是一对多的数据结构。

树(Tree)是n(n≥0)个结点的有限集。n=0时称为空树。在任意一棵非空树中:(1)有且仅有一个特定的称为根(Root)的结点;(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、……、Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)

树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树数称为结点的度(Degree)。度为0的结点称为叶结点(Leaf)或终端结点。度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。

结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲。同一个双亲的孩子之间互称为兄弟(Sibling)。结点的祖先是从根到该结点所经分支上的所有结点。

1.2.2 树的存储结构

树中某个结点的孩子可以有多个,这就意味着,无论按何种顺序将树中所有结点存储到数组中,结点的存储位置都无法直接反映逻辑关系。试想,数据元素挨个地存储,谁是谁地双亲,谁是谁的孩子呢?简单的顺序存储结构是不能满足树的实现要求的。

不过充分利用顺序存储和链式存储结构的特点,完全可以实现对树的存储结构的表示。这里要求孩子表示法。

(1)孩子表示法

由于树中每个结点可能有多棵子树,可以考虑用多重链表,即每个结点有多个指针域,其中每个指针指向一棵子树的根结点,我们把这种方法叫作多重链表表示法。不过树的每个结点的度,也就是它的孩子的个数是不相同的。

其中data是数据域,child1到childn是指针域,用来指向该结点的孩子结点。

这种方法对于树中各结点的度相差很大时,显然是很浪费空间的,因为有很多的结点,它的指针域都是空的。不过如果树中各结点的度相差很小时,那就意味着开辟的空间被充分利用了,这时存储结构的缺点反而变成优点了。

1.2.3树的遍历

树的遍历的定义:以某种方式访问树中的每一个结点,且仅访问一次。 树的遍历主要有先根遍历和后根遍历。

遍历是一种抽象操作,可以是对结点进行的各种处理。

遍历的实质:树结构(非线性结构)→线性结构。

遍历顺序:树通常有前序(根)遍历、后序(根)遍历和层序(次)遍历三种方式。

运行结果

程序代码

//头文件
//tree.h
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MaxSons 3
typedef char ElemType;
typedef struct node
{
    ElemType data[15];     //结点的值
    struct node *sons[MaxSons];    //指向孩子结点
}TSonNode;      //孩子链存储结构中的结点类型
typedef struct
{
    char N[15];
    char n[15];
}array;
//读取文件内容到数组R中
void ReadFile(array R[],FILE *fp,int &n)
{
     while((fscanf(fp,"%s",R[n].N))!=EOF&&(fscanf(fp,"%s",R[n].n))!=EOF)
        n++;
}
//创建一颗树
TSonNode *CreateTree(char str[],array R[],int n)
{
    TSonNode *t;
    int k,i=0,j=0;
    t=(TSonNode *)malloc(sizeof(TSonNode));
    strcpy(t->data,str);
    for(k=0;k<MaxSons;k++)
      t->sons[k]=NULL;
    while(i<n)
    {
       if(strcmp(R[i].N,str)==0)
       {
           t->sons[j]=CreateTree(R[i].n,R,n);
           j++;
       }
       i++;
    }
    return t;
}
//输出树(孩子链存储结构)
void DispTree(TSonNode *t)
{
     int i=0;
     if(t==NULL)
        printf("此树为空树!\n");
     else
     {
        printf("%s",t->data);
        if(t->sons[i]!=NULL)    //若t结点至少有一个孩子
        {
           printf("(");
           for(i=0;i<MaxSons;i++)
           {
               DispTree(t->sons[i]);
               if(t->sons[i+1]!=NULL)
                  printf(",");
               else
                  break;
           }
           printf(")");
        }
     }
}
//销毁树
void DestroyTree(TSonNode *t)
{
    if(t==NULL)
        printf("此树为空树!\n");
    else
    {
        for(int i=0;i<MaxSons;i++)
        {
            if(t->sons[i]!=NULL)
                DestroyTree(t->sons[i]);
            else
                break;
        }
        free(t);
    }
}
//查找某一结点
TSonNode *FindNode(TSonNode *t,char str[])
{
    TSonNode *p;
    if(t==NULL)
        return NULL;
    else
    {
        if(strcmp(t->data,str)==0)
           return t;
        else
        {
            for(int i=0;i<MaxSons;i++)
            {
                if(t->sons[i]!=NULL)
                {
                    p=FindNode(t->sons[i],str);
                    if(p!=NULL)
                      return p;
                }
            }
            return NULL;
        }
    }
}
//求某一结点的孩子个数
int ChildCount(TSonNode *p)
{
    int count=0;
    for(int i=0;i<MaxSons;i++)
    {
        if(p->sons[i]!=NULL)
            count++;
        else
            break;
    }
    return count;
}
//求某棵树中的叶子结点数
//本例中,叶子结点数等于班级数,一个叶子结点对应一个班级
int LeafCount(TSonNode *p)
{
    int count=0;
    if(p==NULL)
        return 0;
    else
    {
        if(p->sons[0]==NULL)
          count++;
        else
        {
            for(int i=0;i<MaxSons;i++)
            {
                if(p->sons[i]!=NULL)
                    count=count+LeafCount(p->sons[i]);
                else
                    break;
            }
        }
    }
    return count;
}
//求某棵树的叶子结点值的和
int LeafSumOfvalue(TSonNode *p)
{
    int sum=0;
    if(p==NULL)
        return 0;
    else
    {
        if(p->sons[0]==NULL)
           return atoi(p->data);
        else
        {
            for(int i=0;i<MaxSons;i++)
            {
                if(p->sons[i]!=NULL)
                   sum+=LeafSumOfvalue(p->sons[i]);
                else
                    break;
            }
        }
    }
    return sum;
}

//源文件
//exp7.cpp
#include<stdio.h>
#include<stdlib.h>
#include"tree.h"
#define MaxSize 66
int main()
{
    int n=0;
    TSonNode *t;
    array R[MaxSize];
    FILE *fp;
    if((fp=fopen("table.txt","r"))==NULL)      //以只读方式打开table.txt文件
    {
        printf("error!cannot open the file!");
        exit(1);
    }
    printf("读取文件内容存入数组R中\n");
    ReadFile(R,fp,n);
    printf("输出数组R:\n");
    for(int i=0;i<n;i++)
        printf("%s %s\n",R[i].N,R[i].n);  //输出R数组查看是否读取正确
    printf("\n由数组R创建树T,");
    t=CreateTree(R[0].N,R,n);   //创建一颗树
    printf("由括号表示输出树T:\n");
    DispTree(t);
    char str[10];
    printf("\n请输入学院名:");
    scanf("%s",str);
    printf("\n%s的专业数:%d\n",str,ChildCount(FindNode(t,str)));
    printf("%s的班级数:%d\n",str,LeafCount(FindNode(t,str)));
    printf("\n请输入学院名:");
    scanf("%s",str);
    printf("\n%s的学生数:%d\n",str,LeafSumOfvalue(FindNode(t,str)));
    printf("销毁树!\n");
    DestroyTree(t);
    return 0;
}


 

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X-MTing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值