前言
在前面的文章中,对于线性表的学习,笔者只是简单的实现了顺序方式的线性表、链式方式的
线性表。对于静态链表、双向链表、和循环链表都未去做一个具体的总结。笔者以为只要掌握住
线性表的特点,逻辑特点、物理特点后面的几种实现方式也是有前面的演化而来的,只是说他们
是由于某些原因二出于这样的设计吧。
例如静态链表的设计就是针对某些程序设计语言没有指针这个数据类型而演变设计的。因此
笔者并不打算一一的去实现。
不过既然学习了线性表,也应该要有所应用的。下面简单的实现一个学生健康管理系统。
输入输出都是在控制台的。
源代码:
// HealthMag.cpp : 定义控制台应用程序的入口点。
//
/**
我只能说现在vs的这一套太jb蛋疼了*/
#include "stdafx.h"
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define NAMELEN 8 //学生姓名的最大长度
#define CLASSLEN 4//班级名的最大长度
//记录的结构
struct student
{
char name[NAMELEN+1];//包括'\0'
long num;//学号信息
char sex;//性别信息
int age;
char class_name[CLASSLEN+1];
int health;//健康状况
};
typedef student ElemType;//链表的结点的数据域的元素类型为结构体
char state[3][9]={"健康 ","一般 ","神经衰弱"};
FILE *fp;//文件指针全局变量
/**链式线性表数据结构*/
typedef struct LNode
{
ElemType data;//节点数据信息域
struct LNode * next;//指向下一个节点的指针
}LNode ,*LinkList;
/**不带头结点的链式线性表的实现*/
void initList(LinkList &l)
{
l= NULL;
}
int insert(LinkList &l,int i,ElemType e)
{
int j=1;
LinkList p = l,s;
if(i<1)
{
return -1;
}
s = (LinkList)malloc(sizeof(LNode));
s->data = e;
if(i==1)
{
s->next = l;
l=s;
}
else
{
while(p&&j<i-1)
{
p = p ->next;
j++;
}
if(!p)
return -1;
s->next = p->next;
p->next =s;
}
return 1;
}
/*输出学生的信息情况*/
void print(student s)
{
printf_s("%-8s %6ld",s.name,s.num);
if(s.sex=='m')
{
printf_s(" 男");
}
else
printf_s(" 女");
printf_s("%5d %-4s",s.age,s.class_name);
printf_s("%9s\n",state[s.health]);//打印出三种健康状况的一种
}
int insertAscend(LinkList &l ,ElemType e,int(*cmp)(ElemType,ElemType))
{
;
LinkList q = l;
if(!l||cmp(e,l->data)<=0)
{
//插在表头
insert(l,1,e);
}
else
{
while(q->next&&cmp(q->next->data,e)<0)
{
q=q->next;
}
insert(q,2,e);
}
return 1;
}
/*进行数据录入*/
void readIn(student s)
{
//通过控制台输入结点信息
printf_s("请输入学生姓名(<=%d个字符):",NAMELEN);
scanf_s("%s",s.name,9);
printf_s("\n请输入学号");
scanf_s("%ld",&s.num);
printf_s("\n请输入性别(m:男 f:女):");
scanf_s("%*c%c",&s.sex);
printf_s("\n请输入年龄:");
scanf_s("%d",&s.age);
printf_s("\n请输入班级(<=%d个字符):",CLASSLEN);
scanf_s("%s",s.class_name,5);
printf_s("请输入健康状况(0:%s 1:%s 2:%s):",state[0],state[1],state[2]);
scanf_s("%d",&s.health);
}
/**将结点以一个记录的形式写到文件中去*/
void writeToFile(student s)
{
fwrite(&s,sizeof(student),1,fp);
}
/**从文件中读取信息,每次读取的是一个student的长度*/
int readFromFile(student &s)
{
int i;
i=fread(&s,sizeof(student),1,fp);
if(i==1)
{
return 1;//读取文件成功
}
else
return -1;//读取文件失败
}
/**通过学号来实现比较排序*/
int cmp(ElemType s1,ElemType s2)
{
return (int)(s1.num - s2.num);
}
void modify(LinkList &l,ElemType s)
{
//修改结点的内容,并按学号将结点s非降序的插入链表L中
char data[80];//接受数据的输入
print(s);//显示结点的原内容
printf_s("请输入带改项的内容,不修改的项直接以回车符结束保持原值:");
printf_s("\n请输入姓名(<=%d个字符):",NAMELEN);
gets_s(data);
if(strlen(data))
{
strcpy_s(s.name,data);
}
printf_s("\n请输入学号:\n");
gets_s(data);
if(strlen(data))
{
s.num = atol(data);//字符串转换为Long Int
}
printf_s("\n请输入性别(m:男 f:女):");
gets_s(data);
if(strlen(data))
{
s.sex=data[0];
}
printf_s("\n请输入年龄:");
gets_s(data);
if(strlen(data))
{
s.age = atoi(data);
}
printf_s("\n请输入班级(<=%d个字符):",CLASSLEN);
gets_s(data);
if(strlen(data))
{
strcpy_s(s.class_name,data);
}
printf_s("\n请输入健康状况(0:%s 1:%s 2:%s)",state[0],state[1],state[2]);
if(strlen(data))
{
s.health = atoi(data);
}
insertAscend(l,s,cmp);//将结点非降序插入链表中
}
int equal_num(ElemType e1,ElemType e2)
{
if(e1.num == e2.num)
return 1;
else
return -1;
}
int equal_name(ElemType e1,ElemType e2)
{
if(strcmp(e1.name,e2.name))
return -1;
else
return 1;
}
/***/
int locateElem(LinkList l,ElemType e,int(cmp)(ElemType,ElemType))
{
int i = 0;
LinkList p = l;
while(p)
{
i++;
if(cmp(p->data,e))
return i;
p=p->next;
}
return 0;
}
LinkList point(LinkList l,ElemType e,int(equal)(ElemType,ElemType),LinkList &p)
{
int i,j;
i = locateElem(l,e,equal);
if(i)
{
if(i==1)
{
p=NULL;
return l;
}
p=l;
for(j=2;j<i;j++)
{
p=p->next;
}
return p->next;
}
return NULL;
}
int listDelete(LinkList &l,int i,ElemType &e)
{
int j=1;
LinkList p=l,q;
if(i=1)
{
l=p->next;
e = p->data;
free(p);
}
else
{
while(p->next&&j<i-1)
{
p=p->next;
j++;
}
if(!p->next||j>i-1)
{
return 0;
}
q=p->next;
p->next=q->next;
e =q->data;
free(q);
}
return 1;
}
/**根据学号或者姓名删除记录*/
int delete_element(LinkList &l,ElemType &e,int(equal)(ElemType,ElemType))
{
LinkList p ,q;
q = point(l,e,equal,p);
if(q)
{
if(p)
listDelete(p,2,e);
else
listDelete(l,1,e);
return 1;
}
return 0;
}
void listTraverse(LinkList l,void(vi)(ElemType))
{
LinkList p = l;
while(p)
{
vi(p->data);
p=p->next;
}
printf_s("\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
student stu[4] ={{"张三",1001,'m',19,"计01",0},
{"张曼",1003,'f',18,"计02",1},
{"周玉",1002,'f',18,"计03",2},
{"李四",1004,'m',21,"计01",1}};
int i,j,flag=1;
char filename[13];//保存文件的名字
ElemType e;
LinkList l,p,q;
initList(l);
while (flag)
{
printf_s("\n1:将结构体数组student中的记录按学号的非降序插入链表中\n");
printf_s("2:将文件中的记录按学号非降序插入链表\n");
printf_s("3:键盘输入新纪录,并将其按学号的非降序插入链表\n");
printf_s("4:删除链表中第一个有给定学号的记录\n");
printf_s("5:删除链表中第一个有给定姓名的记录\n");
printf_s("6:修改链表中第一个有给定学号的记录\n");
printf_s("7:修改链表中第一个有给定姓名的记录\n");
printf_s("8:查找链表中第一个有给定学号的记录\n");
printf_s("9:查找链表中第一个有给定姓名的记录\n");
printf_s("10:显示所有的记录\n11:将链表中所有的记录存入文件\n12:结束");
printf_s("\n请选择操作命令:");
scanf_s("%d",&i);
switch(i)
{
case 1:for(j=0;j<4;j++)
insertAscend(l,stu[j],cmp);
break;
case 2:printf_s("请输入文件名:");
scanf_s("%s",filename);
if((fopen_s(&fp,filename,"rb"))!=0)
printf_s("文件打开失败");
else
{
while (readFromFile(e))
{
insertAscend(l,e,cmp);
fclose(fp);
}
}
break;
case 3:readIn(e);
insertAscend(l,e,cmp);
break;
case 4:printf_s("\n请输入带删除的学生的学号");
scanf_s("%ld",&e.num);
if(!delete_element(l,e,equal_num))
printf_s("\n没有学生为%ld的记录",e.num);
//未完待续!
break;
case 5:printf_s("\n请输入待删除的学生的姓名");
scanf_s("%*c%s",e.name);
if(!delete_element(l,e,equal_name))
printf_s("\n没有学生为%s的记录",e.name);
break;
case 6:printf_s("\n请输入待修改的学生的学号");
scanf_s("%ld",&e.num);
if(!delete_element(l,e,equal_num))
printf_s("\n没有学生为%ld的记录",e.num);
else
modify(l,e);
break;
case 7:printf_s("\n请输入待修改的学生的学号");
scanf_s("%*c%s",e.name);
if(!delete_element(l,e,equal_name))
printf_s("\n没有学生为%s的记录",e.name);
else
modify(l,e);
break;
case 8:printf_s("\n请输入待查找的学生的学号");
scanf_s("%ld",&e.num);
if(!(q=point(l,e,equal_num,p)))
printf_s("\n没有学生为%ld的记录",e.num);
else
print(q->data);
break;
case 9:printf_s("\n请输入待查找的学生的姓名");
scanf_s("%*c%s",e.name);
if(!(q=point(l,e,equal_name,p)))
printf_s("\n没有学生为%s的记录",e.name);
else
print(q->data);
break;
case 10:printf_s(" 姓名 学号 性别 年龄 班级 健康状况\n");
listTraverse(l,print);
break;
case 11:printf_s("请输入文件名:");
scanf_s("%s",filename);
printf_s("开始打开文件");
errno_t err;
if (err=((fopen_s(&fp,filename,"w")))!=0)
{
printf_s("打开文件失败");
}
else
{
listTraverse(l,writeToFile);
fclose(fp);
}
break;
case 12:
flag=0;
}
}
return 0;
}