数据结构实验二:从文件中读取学生信息,并用快速排序法按成绩排序(C++)

一、题目

假设一学生信息文件中每个学生信息包括:学号(8位字符)、姓名(10个字符)、成绩(整型)及所用时间(整型),要求从该文件中读取每个学生的信息存入一双向循环链表中,然后按快速排序算法对其排序;排序的规则是:按成绩从高到低,成绩相同时所用时间少者在先,多者在后。要求输出排序后的结果。

二、关键知识点:

1.构造双向循环链表及其操作函数:

typedef struct //存放学生信息
{
	char No[9];
	char Name[11];
	int Score;
	int time;
}Student;

typedef struct DLNode //双向循环链表结点
{
	int i; //用于记录顺序,便于排序
    Student stu;
	DLNode*prior;
	DLNode*next;
}DLNode,*DLlist;

void InitList(DLlist& L) //建立链表头
{
	L = new DLNode;
	L->next = L;
	L->prior = L;
	L->i = 0;
}

void DestroyList(DLlist& L) //销毁链表
{
	delete L;
}

void ShowStuMsg(DLlist L)  //打印链表数据
{
	DLNode* p = L->next;
	while(p!=L)
	{
		std::cout << p->stu.No << " " << p->stu.Name << " " << p->stu.Score << " " << p->stu.time << std::endl;
		p = p->next;
	}
}

void InsertDLlist(DLlist& L, Student stu) //在链表末尾插入一个结点
{
	DLNode *p;
	p = new DLNode;

	p->next = L;
	p->prior = L->prior;
	L->prior->next = p;
	L->prior = p;

	strcpy(p->stu.No, stu.No);
	strcpy(p->stu.Name, stu.Name);
	p->stu.Score = stu.Score;
	p->stu.time = stu.time;
	p->i =( p->prior->i)+ 1;
}

2.从文件中读取信息:

使用文件的输入输出流,需要加上头文件fstream,以及名称空间std。读取文件信息用ifstream,注意使用的时候要当作类来用,先定义一个对象,给一个文件名字作为构造函数参数,然后类似cin的方式使用。循环结束的条件用eof(),当读取到文件末尾时返回1。

    ifstream fin(filename);//打开文件
	Student stu;
	while (!fin.eof()) //读取文件存入链表直到文件结尾
	{
		fin >> stu.No >> stu.Name >> stu.Score >> stu.time;
		InsertDLlist(L, stu);
	}
	fin.close();

3.快速排序算法:

首先构造一个交换结点数据的函数swap(),指针位置不变。因为直接换结点比较麻烦,所以选择交换stu的数据。

因为要从大到小排列,所以将中间值设为右边第一个值,其余操作也是与平常的相比镜像转一下,最后注意一种情况,当返回的指针指向链表末尾的结点时,要跳过,不然就会与链表的首结点排序导致出现错误。

void swap(DLNode *s, DLNode *t)//将s与t所指向的结点的数据互换。
{
	Student p =s->stu;	//保存s所指向的结点的数据

	strcpy(s->stu.No, t->stu.No); //把t结点的数据覆盖到s上
	strcpy(s->stu.Name, t->stu.Name);
	s->stu.Score = t->stu.Score;
	s->stu.time = t->stu.time;

	strcpy(t->stu.No, p.No);  //把s的数据覆盖到t上
	strcpy(t->stu.Name, p.Name);
	t->stu.Score = p.Score;
	t->stu.time = p.time;

}
DLNode* Partition(DLNode* L,DLNode* s, DLNode* t) //将s开始t结束的序列排列成左边比中间值大,右边比中间值小的形式
{
	DLNode p = *t; //将t的数据作为两边比较的中间值
	DLNode *q = t; //保存t指针的位置信息
	while(s->i < t->i)
	{		 
		while (s->i < t->i && s->stu.Score >= p.stu.Score) //指针往后移动,直到遇到比中间值小的数据停下
		    s = s->next;
		 while(s->i < t->i && t->stu.Score<=p.stu.Score)  //指针往前移动,直到遇到比中间值大的数据停下
			t = t->prior;

		 if (s->i != t->i)  //s,t指针未相遇时将它们指向的结点互换
			 swap(s, t);
	}
	swap(q, t); //s与t相遇,将中间值换到t的位置

	return t;  //返回中间值的位置
}

void QuickSort(DLNode* L,DLNode* s, DLNode* t)
{
	if (s->i < t->i)
	{
		DLNode* par = Partition(L,s,t); //排列,并返回将序列分为了两部分的中间结点指针

		if(par->next!=L)
			QuickSort(L,par->next, t); //将右边继续排列
		if(par->prior !=L)
			QuickSort(L,s,par->prior); //将左边继续排列
	}
}

三、完整的代码实现:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<fstream>
#include"DLinklist.h" //存放双向循环链表操作函数

using namespace std;
int main()
{
	DLlist L;  
	InitList(L);  //创建双向循环链表
	char filename[] = "StudentScore.txt";

	ifstream fin(filename);//打开文件
	Student stu;
	while (!fin.eof()) //读取文件存入链表直到文件结尾
	{
		fin >> stu.No >> stu.Name >> stu.Score >> stu.time;
		InsertDLlist(L, stu);
	}
	fin.close();	

	cout << "读取的学生信息:\n";
	ShowStuMsg(L);

    QuickSort(L,L->next, L->prior);

	DLNode* p = L->next;
	int flag = 1; 
	while (flag == 1) //将成绩相同的学生按考试时间排序
	{	
		flag = 0; //用来标记是否有排序操作,如果排序完成了就跳出循环
		while (p->next != L) //遍历链表
		{
			if (p->stu.Score == p->next->stu.Score) //与后一个学生成绩比较,如果相等就比较时间,如果时间长就交换一下
				if (p->stu.time > p->next->stu.time)
				{
					flag = 1;  //
					swap(p, p->next);
				}
			p = p->next; 
		}
		p = L->next;
	}

	cout << "排序后的结果:\n";
	ShowStuMsg(L);
	return 0;
}

运行结果:

 

  • 3
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值