数据结构与算法实验1——公司管理(二叉树)



实验一 公司组织管理

题目:

image.png

某公司利用链表管理员工之间的领导关系,如上图所示。

每名员工用链表中的一个节点表示,每个节点有name、next、prev和lead四个属性。以“王总”节点为例:

name(王总): 员工姓名,每个员工的姓名唯一;

next:指向和王总同级的后一位员工;

prev:指向和王总同级的前一位员工;

lead:指向直接受王总领导的员工。每一位员工直接领导最多1名员工,最少0名员工。

请你实现一个系统,接受4种命令作为输入,实现4种功能:

1.(输入)init

(执行)按照上图中的组织关系构造链表。

(输出)链表构造完成,现有x名员工

(说明)x为当前链表中的员工数目,这里应为9。

2.(输入)list

(执行)利用递归函数,从链表头节点(胡总)开始,“访问”每个节点。

定义“访问”:首先输出当前节点的name。如果当前节点既领导员工,又有后一位员工,则先“访问”当前节点领导的员工,再“访问”后一位员工;如果当前节点只领导员工,则“访问”当前节点领导的员工;如果当前节点只有后一位员工,则“访问”当前节点的后一位员工。

(输出)胡总 王总 张三 李四 小彭 小陈 老六 张总 黎总

(说明)首先先访问胡总,输出“胡总”;胡总没领导员工,访问后一名员工,王总;

输出“王总”,王总领导张三,访问张三;

输出“张三”,张三没领导员工,访问后一名员工,李四;

输出“李四”,李四领导小彭,访问小彭;

输出“小彭”,小彭没有领导员工,访问后一名员工,小陈。

输出“小陈”,小陈没领导员工,也无后一名员工,返回到李四,访问李四的后一名员工,老六。

输出“老六”,老六没领导员工,也无后一名员工,返回到王总,访问王总的后一名员工,张总。

输出“张总”,张总没领导员工,访问后一名员工,黎总。

输出“黎总”,黎总没领导员工,也无后一名员工,结束。

3.(输入)[参数1] lead by [参数2]

(执行)插入一个新节点,name为[参数1];令[参数2]节点的lead指针指向该新节点;插入完成后执行“list”命令。

(输出为list命令的输出)

(说明)保证[参数1]不与已有的name重复;保证[参数2]存在于链表中,且[参数2]节点没有领导员工。

4.(输入)[参数1] follow [参数2]

(执行)插入一个新节点,name为[参数1];令[参数2]节点的next指针指向[参数1]节点,[参数1]节点的prev指针指向[参数2]节点;插入完成后执行“list”命令。

(输出为list命令的输出)

(说明)保证[参数1]不与已有的name重复;保证[参数2]存在于链表中,且[参数2]节点没有后一个员工。

样例

(输入)init

(输出)链表构造完成,现有9名员工

(输入)list

(输出)胡总 王总 张三 李四 小彭 小陈 老六 张总 黎总

(输入)小张 follow 小陈

(输出)胡总 王总 张三 李四 小彭 小陈 小张 老六 张总 黎总

(输入)小卢 lead by 小陈

(输出)胡总 王总 张三 李四 小彭 小陈 小卢 小张 老六 张总 黎总

一、实验内容

公司组织管理:

某公司利用链式结构存储和管理员工之间的关系,每一名员工使用一个结点表示,并且含有四个属性name、next、prev和lead。

本实验要求实现一个系统,接收四种命令作为输入,实现四种功能:

1.init初始化

构造链表并且打印出员工的个数。

2.list遍历访问

使用递归函数访问每一个结点

3.加入lead元素

使用命令“[参数1] lead by [参数2]”加入元素,使参数2的元素领导参数1的元素

4.加入follow元素

使用“[参数1] follow [参数2]”命令加入元素,使参数2的元素跟在参数1 的元素后面。

二、实验过程及结果

使用结构体定义结点,每个结点有四个属性:

 使用typedef定义node类型。

(一)、init初始化

初始化过程中,我将录入题目中所给图片的每个结点之间的链表关系、每个结点的元素属性(如姓名)。但是由于我们的head结点在之后经常用到,为了防止在遍历过程更改,我使用静态变量huzong。

 

 

对于init初始化链表之后,我将使用:

printf("链表构造完成,现有%d名员工\n", 9+flag);  输出

其中的flag是加入的结点数量,在刚开始的时候是0,每次加入一个结点之后会增加1。

Flag的定义(静态变量):

执行init之后的程序表现:

 (二)、list遍历访问

使用递归函数对链表中的各个节点按照题目中的要求进行访问。

注意:要判断每个结点是否为NULL,否则调用head->next之类的时候,程序可能会报错;另外还要判断接下来要访问的next 或者lead是不是NULL,否则可能会打印处(null)字样。

程序执行结果:

(三)、加入lead元素

由结构[参数1] lead by [参数2],通过对于输入的字符串进行逐字符识别,识别出lead by 之后,会由该lead by的位置,找到参数1和参数2。

此时通过遍历原链表,找到name为参数2的结点,并构造一个新的结点,让该结点的name为参数1。

之后,我们将name为参数2的结点的lead指针指向新构造的结点。

由此,我们就实现了[参数1] lead by [参数2]的操作。

接下来调用list函数,实现对于列表中元素的遍历打印就好了。

程序执行效果展示:

(四)、加入follow元素

由结构[参数1] follow [参数2],通过对于输入的字符串进行逐字符识别,识别出follow 之后,会由该follow的位置,找到参数1和参数2。

此时通过遍历原链表,找到name为参数2的结点,并构造一个新的结点,让该结点的name为参数1。

之后,我们使name为参数2的结点的next指向新构建的结点,并且使新构建的结点的prev指向name为参数2 的结点。

由此我们就实现了follow的元素关系的链表构建。

接下来我们只需调用list函数,遍历并打印出链表的name信息就可以了。

程序执行效果展示:

三、实验心得

本次实验遇到诸多bug,让我感到不是在写code,更多的是在写bug。接下来我将讲述我的问题经历以及解决方案。

1.对于指针是否为NULL的判断缺失

在含有指针编程的时候,一定都要考虑到万一指针为NULL的情形,就如我在编写

void list(node* head)

{
    printf("%s ", head->name);
    if(head != NULL)
        if(head->lead != NULL)
            list(head->lead);
    if(head != NULL)
        if(head->next != NULL)
            list(head->next);
}

一开始并没有进行指针非空的判断,因此执行到该处时,程序都会崩溃。

另外head->lead != NULL 的判断也是必要的,虽然没有这个不会导致程序崩溃,但是经过list的遍历打印之后,链表中会出现很多(null)的结点,因此需要加上对于结点各属性指针的判空,才能打印出需要的list序列。

2.对于递归的理解不足

在下面的程序中,需要使用递归的方式:

我发现需要对于每层递归中find函数的值进行返回,

因为每次返回实际上只是返回到了上一层,如果只是在最后一层找到之后返回我想要的head,是不会返回到最上面一层的,只有通过每一层的a = find(…,…)的返回,才能够在main函数调用find()的时候得到返回值。

而反观遍历函数不需要返回是因为,我只是需要它打印出每个值即可,并不需要这个函数给出一个返回值。

node* find(node* head, char* ex_name)  //递归的构造(返回),并且需要判断条件。

{
    node* a = NULL;
    int i = 1;
    if(head!=NULL)
    {
        i = strcmp((head->name), ex_name);
    }
    if(i==0)
    {
        return head;
    }
    if(head->lead!=NULL)

        a = find(head->lead, ex_name);
    if(a!=NULL)
    {
        return a;
    }
    if(head->next!=NULL)
        a = find(head->next, ex_name);
    if(a!=NULL)
    {
        return a;
    }
}

3.对于string初始化的问题

由于我们需要判定某个string中是否含有某个值,那么就需要string初始为空字符串,否则在匹配字符的时候可能不会找到结尾的’\0’。

有几种方式

在初始化时初始为””或者”a”(这样除了第一位之外全部为\0)

另外还有一种方式:在实例化的时候使用memset()。

而切忌使用strcpy,因为这样无法将初始化之后的string的后面置空。

另外,在自己使用完一个字符串之后,如果想要重复使用,一定要先使用memset()进行置空操作。

另外,在结构体中,不能够初始化字符串,例如:

问题具体描述:c - I get an error when I initialize a string in a structure - Stack Overflow

解决的方案就是使用类与对象的方式初始化字符串,或者是在我进行实例化的时候逐个对于结点的name属性使用memeset()操作进行置空。

实验全部代码:

#include <stdio.h>
#include <string.h>
#include <malloc.h>

typedef struct node
{
    char name[50];
    struct node* next;
    struct node* prev;
    struct node* lead;

} node;

static int flag = 0;
static node* nodes[100];
static int q=0;
static node* huzong;

node* init()
{
    node* wangzong = (node*)malloc(sizeof(node));
    node* zhangzong = (node*)malloc(sizeof(node));
    node* lizong = (node*)malloc(sizeof(node));
    node* zhangsan = (node*)malloc(sizeof(node));
    node* lisi = (node*)malloc(sizeof(node));
    node* laoliu = (node*)malloc(sizeof(node));
    node* xiaopeng = (node*)malloc(sizeof(node));
    node* xiaochen = (node*)malloc(sizeof(node));
    strcpy(huzong->name, "胡总");
    huzong->lead = NULL;
    huzong->prev = NULL;
    huzong->next = wangzong;
    strcpy(wangzong->name, "王总");
    wangzong->lead = zhangsan;
    wangzong->prev = huzong;
    wangzong->next = zhangzong;
    strcpy(zhangzong->name, "张总");
    zhangzong->lead = NULL;
    zhangzong->prev = wangzong;
    zhangzong->next = lizong;
    strcpy(lizong->name, "黎总");
    lizong->lead = NULL;
    lizong->prev = zhangzong;
    lizong->next = NULL;
    strcpy(zhangsan->name, "张三");
    zhangsan->lead = NULL;
    zhangsan->prev = NULL;
    zhangsan->next = lisi;
    strcpy(lisi->name, "李四");
    lisi->lead = xiaopeng;
    lisi->prev = zhangsan;
    lisi->next = laoliu;
    strcpy(laoliu->name, "老六");
    laoliu->lead = NULL;
    laoliu->prev = lisi;
    laoliu->next = NULL;
    strcpy(xiaopeng->name, "小彭");
    xiaopeng->lead = NULL;
    xiaopeng->prev = NULL;
    xiaopeng->next = xiaochen;
    strcpy(xiaochen->name, "小陈");
    xiaochen->lead = NULL;
    xiaochen->prev = xiaopeng;
    xiaochen->next = NULL;
    return huzong;
}

void list(node* head)
{
    printf("%s ", head->name);
    if(head != NULL)
        if(head->lead != NULL)
            list(head->lead);
    if(head != NULL)
        if(head->next != NULL)
            list(head->next);

}

node* find(node* head, char* ex_name)  //递归的构造(返回),并且需要判断条件。
{
    node* a = NULL;
    int i = 1;

    if(head!=NULL)
    {
        i = strcmp((head->name), ex_name);
    }
    if(i==0)
    {

        return head;
    }
    if(head->lead!=NULL)
        a = find(head->lead, ex_name);
    if(a!=NULL)
    {
        return a;
    }
    if(head->next!=NULL)
        a = find(head->next, ex_name);
    if(a!=NULL)
    {
        return a;
    }
}

void lead(node* new_node, node* existing)
{
    existing->lead = new_node;
    new_node->lead = NULL;
    new_node->next = NULL;
    new_node->prev = NULL;
}

void follow(node* new_node, node* existing)
{
    existing->next = new_node;
    new_node->prev = NULL;
    new_node->lead = NULL;
    new_node->next = NULL;
}


int main()
{
    huzong = (node*)malloc(sizeof(node));
    for(q = 0; q<100; q++)
{
    nodes[q] = (node*)malloc(sizeof(node));
    nodes[q]->lead = NULL;
    memset(nodes[q]->name, 0x00, sizeof(char)*50);
    nodes[q]->next = NULL;
    nodes[q]->prev = NULL;
}
    char input[100]="a";
    char new_name[50]="a";
    char ex_name[50]="a";
    node* head;
    node* temp = NULL;
    head = init();

    while(1)
    {
        head = huzong;
        memset(input, 0x00, sizeof (char) * 100);// memset的用法好好用
        gets(input);
        for(int i = 0; i < 50; i++)
        {
            //init初始化实现
            if(input[i]=='i'&&input[i+1]=='n'&&input[i+2]=='i'
                    &&input[i+3]=='t')
            {
                init();
                printf("链表构造完成,现有%d名员工\n", 9+flag);
            }
            //list遍历功能实现
            if(input[i]=='l'&&input[i+1]=='i'&&input[i+2]=='s'
                    &&input[i+3]=='t')
            {
                list(head);
                printf("\n");
            }
            //lead功能实现
            if(input[i]=='l'&&input[i+1]=='e'&&input[i+2]=='a'
                    &&input[i+3]=='d'&&input[i+5]=='b'&&input[i+6]=='y')
            {
                for(int j=0; j<=i-2; j++)
                {
                    new_name[j] = input[j];

                }
                for(int k=i+8; k<=i+25; k++)
                {
                    ex_name[k-i-8] = input[k]; //如果x_name溢出,将会污染到newname的位置
                }
                //node* new_node = (node*)malloc(sizeof(node));
                strcpy(nodes[flag]->name, new_name);

                temp = find(head, ex_name);

                temp->lead = nodes[flag];

                nodes[flag]->lead = NULL;
                nodes[flag]->next = NULL;
                nodes[flag]->prev = NULL;
                list(head);
                printf("\n");
                flag++;
            }

            if(input[i]=='f'&&input[i+1]=='o'&&input[i+2]=='l'
                    &&input[i+3]=='l'&&input[i+4]=='o'&&input[i+5]=='w')
            {
                memset(new_name, 0x00, sizeof(char)*50);
                for(int j=0; j<=i-2; j++)
                {
                    new_name[j] = input[j];

                }
                for(int k=i+7; k<=i+30; k++)
                {
                    ex_name[k-i-7] = input[k]; //如果ex_name溢出,将会污染到newname的位置
                }
                strcpy(nodes[flag]->name, new_name);

                temp = find(head, ex_name);

                temp->next = nodes[flag];

                nodes[flag]->lead = NULL;
                nodes[flag]->next = NULL;
                nodes[flag]->prev = temp;
                list(head);
                printf("\n");
                flag++;
            }



        }

    }
}

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《人事信息管理系统》简 介   《人事信息管理》是一个协助各单位科学、全面、高效地进行人事管理的系统,它参考了哈佛人力资源管理理论,根植于国内人事管理的实际情况,实用而科学。   在内容上,它包括了人事变动(新进员工登记、员工离职登记和人事变更管理)、考勤(考勤、加班、出差管理等)、员工培训(培训管理和学历记录)、考核与奖惩、人事档案完整资料(基本资料、人事合同、生理状况、户籍、政治情况、投保管理、担保情况等)等内容。   在操作上,它集输入、维护、查询、筛选、统计和各种处理为一体,信息导入导出方便共享,灵活、专业的报表设计,形象、增强的数据处理,完美的信息图形分析,用户可自定义自开发这些功能! 可以概述为如下特点:功能强大,易学易会,信息共享,随心设计,SQL语句处理信息,无代码开发。 一、《人事管理》能够做什么 1、 科学管理员工档案,优化分类,全面反映员工情况 2、 管理人事变动信息,优化人员配置 3、 管理考勤信息,保证工作秩序 4、 纪律员工培训信息,保证员工量才使用 5、 管理员工奖惩信息,促进员工积极向上 二、《人事管理》的功能结构   信息内容(信息表)是核心,输入、处理、报表(输出)、分析是应用:系统围绕信息内容(信息表),来实现输入、处理、报表(输出)、分析等功能。 输入功能:含“设计录入格式”、“模式录入”、“表格界面”等三大界面。可利用“设计录入格式”界面根据自己的喜好设计录入界面;可任意选择“模式录入”和“表格界面”两大输入界面进行输入工作。   输出功能:含“报表显示”、“报表修改”、“新建报表”三大界面。可利用“报表显示”界面对所需输出的报表进行模拟显示和打印;可在“报表修改”界面中对报表格式进行修改设计;可在“新建报表”界面中导入自己制作的报表图形,来自行设计报表。   处理功能:其中包括“横向筛选”、“纵向筛选”、“计算操作”、“信息增强处理”四种功能。可在“横向筛选”和“纵向筛选”中进行信息筛选,在“计算操作”中进行字段计算处理,在“信息增强处理”中对数据进行处理。   分析功能:即图形分析,可在“信息分析”界面对所需分析的数据进行图形分析。系统具有强大的图形分析设计功能,单击“图形编辑”按钮,可在“图形编辑”窗口中设计各种精美的图形。   三、使用和增加你所需的基础管理内容 1、 对需要增加的内容从应用的角度分析,确定需要管理的基础信息。 2、 增加管理内容要从信息表开始。 3、 设置计算字段和建立运算树。 4、 设计输出报表和分析图表。 5、 根据结果与目的的对比,优化信息表设计。 四、处理信息 为了适应信息处理的各种需求,系统设计开发了“运算树”,采用SQL语句处理信息。所有的处理过程均对用户透明,同时用户也可以自己设计处理过程。 五、信息表的作用 1、 维护和存储基础信息,作为应用的原始数据。 2、 用于查询、筛选和统计。 3、 作为运算处理的中间和最终数据,用于报表和分析图形数据源。 六、制作报表 1、 报表的两种形式 报表有单记录表和多记录表两种形式。 2、 报表的分区(只适用于多记录表) 一般一张多记录表分标题区、表头区、细节区、汇总区、报表区、页头区、页脚区等七个区域。 3、 报表设计技巧 1)增加报表设计区域:单击系统工具栏上的“隐藏文档管理树”按钮,然后单击“报表设计”区工具栏上的“属性检查框”前面的小方框,使小方框中的“√”消失,即可使“报表设计”区增加到最大。 2)使所需控件到达最上层:选择所需控件,单击“报表设计”区工具栏上的“前面检查框”的小方框,使小方框内出现“√”,即可使所需控件到达最上层。 3)复制控件:选择所需复制的控件,单击“报表设计”区工具栏上的“复制当前对象”按钮,然后将鼠标移动到所选控件的边框上,按下左键并拖动所复制的控件到所需位置即可。 4)选定控件:单击“报表设计”区工具栏上的“控件选择”组合框的下拉按钮,在该框中选择所需控件名,即可选定控件。 七、设计有意义的分析图表   本系统除可以打印输出报表外,还可以打印输出图形,可单击系统工具栏上的“信息分析”按钮,出现“图形分析”界面,单击该界面工具栏上的“图形编辑”按钮,出现“图形编辑”窗口,可在该窗口中对分析图表进行编辑(在“图形编辑”窗口中可对分析图表进行微调)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值