0.引言
多重链表的练习。
1.题目说明
一所有40000名学生和2500门课程的大学需要生成两种类型的报告。第一个报告列出每个班的注册者,第二个报告列出每个学生注册的班级。常用的实现方法是使用二维数组,这样一个数组将有1亿项。平均一个学生注册三门课程,因此实际上有意义的数据只有120000项,大约占0.1%。
数据结构定义:
用两个链表做索引,分别存储课程节点和学生节点,注册节点为多重链表。课程为固定的课程,先初始化好;然后从学生的角度进行注册。
整个数据结构的入口为CTList (Course Table List)
和STList (Student Table List)
两个链表,多重链表的节点(注册上的节点)就是挂在这两个链表上的,遍历查询打印报告,分别输出这两个链表就是了!
2.代码实现
代码实现按照书中图片上进行注册。
#include <iostream>
#include <algorithm>
using namespace std;
#define COURSE_NUM 5
#define STUDNET_NUM 6
typedef struct student *PtrToS;
typedef struct course *PtrToC;
typedef struct RegisterNode *PtrToR;
typedef PtrToS SList;
typedef PtrToC CList;
typedef PtrToR RList;
struct RegisterNode
{
SList Stu;
CList Cou;
};
struct student
{
string name;
RList Next;
};
struct course
{
//bool FirstRegister = true;
string name;
RList Next;
};
//课表
typedef struct coursetable *PtrToCT;
typedef PtrToCT CTList;
struct coursetable
{
CList Cou;
CTList Next;
};
//学生名册
typedef struct studenttable *PtrToST;
typedef PtrToST STList;
struct studenttable
{
SList Stu;
STList Next;
};
string CourseName(int tmp)
{
switch (tmp)
{
case 1: return "C1";
case 2: return "C2";
case 3: return "C3";
case 4: return "C4";
case 5: return "C5";
case 6: return "-1";//占位,最后一位while循环不会输出
default: break;
}
}
void InitCourseTable(CTList *CTL)
{
CTList p,tail; CList tmpP,tmpTail;
*CTL = (CTList)malloc(sizeof(coursetable));
//为什么使用new不用malloc,参考
//https://blog.csdn.net/fb_941219/article/details/106968262
tmpTail = (CList)new(course);
tmpTail->name = CourseName(1);
tmpTail->Next = NULL;//这里是后面需要注册上去的指针
(*CTL)->Cou = tmpTail;
(*CTL)->Next = NULL;
tail = *CTL;
for (int i = 1; i <= COURSE_NUM; i++)
{
p = (CTList)malloc(sizeof(coursetable));
tmpP = (CList)new(course);
tmpP->name = CourseName(i+1);
tmpP->Next = NULL;//这里是后面需要注册上去的指针
p->Cou = tmpP;
tail->Next = p;
tail = p;
}
tail->Next = NULL;//记住最后一位的指针需要置为NUll
}
void DisplayCourseTable(CTList *CTL)
{
CTList ctl;
ctl = *CTL;
cout << "course contents:" << endl;
while (ctl->Next)
{
cout << ctl->Cou->name.c_str() << " ";//字符串还不能直接cout,需要.c_str()
ctl = ctl->Next;
}
}
//void InitStudentNode(STList *STL)
//{
// SList tmpTail;
// *STL = (STList)malloc(sizeof(studenttable));
// tmpTail = (SList)new(student);
// tmpTail->name = "-1";
// tmpTail->Next = NULL;//这里是后面需要注册上去的指针
// (*STL)->Stu = tmpTail;
// (*STL)->Next = NULL;
//}
//
//void InsertStudentNode(STList *STL,string StuName)
//{
// STList stl; SList tmpStu;
// stl = (STList)malloc(sizeof(studenttable));
// tmpStu = (SList)new(student);
// tmpStu->name = StuName;
// tmpStu->Next = NULL;//这里是后面需要注册上去的指针
// stl->Stu = tmpStu;
// stl->Next = NULL;
//
// (*STL)->Next = stl;
// (*STL) = stl;
//}
//
void InitStudentTable(STList *STL, string StuName)
{
STList stl; SList stu;
*STL = (STList)malloc(sizeof(studenttable));
(*STL)->Stu = (SList)new(student);
(*STL)->Stu->name = StuName;
(*STL)->Stu->Next = NULL;//这里是后面需要注册上去的指针
(*STL)->Next = NULL;
}
void InsertStudentTable(STList *STL, string StuName)
{
STList stl,tail; SList stu;
tail = *STL;
while (tail->Next!=NULL)
{
tail = tail->Next;
}
stl = (STList)malloc(sizeof(studenttable));
stl->Stu = (SList)new(student);
//stu = (SList)new(student);
//stu->name = StuName;
//stu->Next = NULL;//这里是后面需要注册上去的指针
//stl->Stu = stu;
stl->Stu->name = StuName;
stl->Stu->Next = NULL;
tail->Next = stl;
tail = stl;
tail->Next = NULL;
}
//创建一个注册节点
void CreateRegisterNode(RList *RL, string StuName, string CouName)
{
RList rl;
rl = (PtrToR)malloc(sizeof(RegisterNode));
rl->Stu = (SList)new(student);
rl->Cou = (CList)new(course);
rl->Stu->name = StuName;
rl->Stu->Next = NULL;
rl->Cou->name = CouName;
rl->Cou->Next = NULL;
*RL = rl;
}
//返回某一课程节点
CList FindCourseName(CTList* CTL, string CourseCname)
{
CTList ctl;
ctl = *CTL;
while (ctl->Next != NULL && ctl->Cou->name != CourseCname)
ctl = ctl->Next;
return ctl->Cou;
}
bool FirstTimeRegister = true;
//一个学生可以选多门课程,学生注册,一个学生一个学生的注册
void RegisterStudent(CTList* CTL, STList *STL, string StuName, string CouName[],int CourseNum)
{
if (FirstTimeRegister)
{
InitStudentTable(STL,StuName);
//InitStudentNode(STL);
//(*STL)->Stu->name = StuName;
FirstTimeRegister = false;
}else {
//InsertStudentNode(STL, StuName);
InsertStudentTable(STL,StuName);
}
CList cl; RList rl; STList stl;
stl = *STL;
while (stl->Next!=NULL) stl = stl->Next;//学生节点移动到最后一位
for (int i=0; i<CourseNum; i++)
{
RList RL;//创建注册节点
CreateRegisterNode(&RL, StuName, CouName[i]);
if (stl->Stu->Next==NULL)//学生选的第一门课
{
stl->Stu->Next = RL;
}else {
rl = stl->Stu->Next;
while (rl->Stu->Next != NULL) rl = rl->Stu->Next;
rl->Stu->Next = RL;
}
cl = FindCourseName(CTL,CouName[i]);
if (cl->Next == NULL)
{
cl->Next = RL;//该门课程第一次被选
}else{
rl = cl->Next;
while (rl->Cou->Next != NULL) rl = rl->Cou->Next;
rl->Cou->Next = RL;
}
}
}
//打印某一门课程的所有选课学生
void DisplayStudentsOfOneCourse(CList *CL)
{
CList cl;
cl = *CL;
while (cl->Next != NULL)
{
cout << cl->Next->Stu->name.c_str() << " ";
cl = cl->Next->Cou;
}
}
//打印每个课程的选课学生
void DisplayCTL(CTList *CTL)
{
CTList ctl; SList sl; CList cl;
ctl = *CTL;
cout <<endl<< "students of this course:" << endl;
while (ctl->Next)
{
cout <<endl<< ctl->Cou->name.c_str() << " : ";
cl = ctl->Cou;
DisplayStudentsOfOneCourse(&cl);
ctl = ctl->Next;
}
cout<<endl;
}
//打印某一个学生选的所有课程
void DisplayCoursesOfOneStudent(SList *SL,string StuName)
{
SList sl;
sl = *SL;
while (sl->Next != NULL)
{
if (sl->Next->Stu->name==StuName)
{
cout << sl->Next->Cou->name.c_str() << " ";
sl = sl->Next->Stu;
}else sl = sl->Next->Stu;
}
//输出最后一位学生
}
//打印每个学生的选课情况
void DisplaySTL(STList *STL)
{
STList stl; CList cl; SList sl;
stl = *STL;
cout << endl << "courses of this student:" << endl;
while (stl->Next)
{
cout << endl << stl->Stu->name.c_str() << " : ";
sl = stl->Stu;
DisplayCoursesOfOneStudent(&sl, stl->Stu->name);
stl = stl->Next;
}
sl = stl->Stu;
cout << endl << stl->Stu->name.c_str() << " : ";
DisplayCoursesOfOneStudent(&sl, stl->Stu->name);//输出最后一位
cout << endl << endl;
}
void StudentCourseTest()
{
CTList CTL;
InitCourseTable(&CTL);
DisplayCourseTable(&CTL);
STList STL;
string S1 = "S1", S2 = "S2", S3 = "S3", S4 = "S4", S5 = "S5";
string Course1[] = { "C1","C3" }, Course2[] = { "C2","C4" },
Course3[] = { "C1","C3" }, Course4[] = { "C1","C3" ,"C4"},
Course5[] = { "C2","C3" };
int CourseNum1 = sizeof(Course1) / sizeof(string),
CourseNum2 = sizeof(Course2) / sizeof(string),
CourseNum3 = sizeof(Course3) / sizeof(string),
CourseNum4 = sizeof(Course4) / sizeof(string),
CourseNum5 = sizeof(Course5) / sizeof(string);
RegisterStudent(&CTL, &STL, S1, Course1 ,CourseNum1);
RegisterStudent(&CTL, &STL, S2, Course2, CourseNum2);
RegisterStudent(&CTL, &STL, S3, Course3, CourseNum3);
RegisterStudent(&CTL, &STL, S4, Course4, CourseNum4);
RegisterStudent(&CTL, &STL, S5, Course5, CourseNum5);
DisplayCTL(&CTL);//打印每门课程的选课学生
DisplaySTL(&STL);//打印每个学生所选的课程
}
int main(int argc, char** argv)
{
//StructPolynomialTest();
//ListPolynomialTest();
//RadioSortTest();
StudentCourseTest();
system("pause");
return 0;
}
心得:基础数据结构的定义不要定义复杂了,不然代码实现过程中很绕,容易把自己给绕进去了!!!