C++链表类的三种使用方法(学生信息管理系统的实现)

回头学学C++与数据结构,巩固下基础。当然看完这篇博客是有作业的~

话不多说,进入主题。关于链表的学习,我想大家先对此的有个概念。然后再来看这篇博文,本文主要介绍三种方法使用链表类。当然前提是你得有个链表类,所以第一种方法就是自己创建一个链表,第二种方法是学习使用C++标准类库(STC)中的list,第三种是学习使用微软的标准类库(MFC)。

本文会介绍这三种方法,其中第三种方法实现了一个学生信息管理系统,大家看完之后,可以用第一种和第二种也来做一个学生管理系统,活学活用~

编译环境,windows平台,编译器选择VS2015。对表的操作无非是增删改查。

方法一:自己创建一个双向链表类

第一步:把链表类和节点结构体的声明放在List.h头文件

#pragma once
typedef int DATA;
struct SNode {
	DATA data;
	SNode *pPrev, *pNext;
};
typedef void* POSITION;//封装我们自己的节点,保证安全性

class List
{
	int m_nCount;//链表的长度
	SNode *m_pHead, *m_pTail;//头指针、尾指针的声明

public:
	List();
	~List();
	int GetCount() const
	{
		return m_nCount;
	}
	//这种单行的函数我们直接在定义的同时进行操作,编译器或将其编译成内联函数
	//由于它不修改成员变量所有可以加上const
 	POSITION GetHeadPosition() const
	{
		return m_pHead;
	}
	POSITION GetTailPosition() const
	{
		return m_pTail;
	}
	DATA GetNext(POSITION &pos);
	DATA GetPrev(POSITION &pos);
	void AddTail(DATA data);//从头添加
	void AddHead(DATA data);//从尾添加
	void SetAt(POSITION pos, DATA data);//修改
	void RemoveAt(POSITION pos);//删除
	void PrintH();//前向遍历
	void PrintT();//尾向遍历
	void RemoveAll();//清除堆空间
	DATA GetAt(POSITION &pos)//查找
	{
		return ((SNode*)pos)->data;
	}
};

第二步,编写cpp文件

#include "stdafx.h"//预编译头文件,如果你建的是空项目,不用加
#include "List.h"
#include<iostream>
using namespace std;

List::List()
{
	m_nCount = 0;
	m_pHead = nullptr;
	m_pTail = nullptr;
}


List::~List()
{
	RemoveAll();
}


DATA List::GetNext(POSITION & pos)
{
	SNode *p = (SNode*)pos;
	p = p->pNext;
	return p->data;
}

DATA List::GetPrev(POSITION & pos)
{
	SNode *p = (SNode*)pos;
	p = p->pPrev;
	return p->data;
	
}

void List::AddTail(DATA data)
{
	SNode *pNew = new SNode;
	pNew->data = data;
	pNew->pNext = nullptr;
	if(m_pTail)
	{
		pNew->pPrev = m_pTail;
		m_pTail->pNext = pNew;
	}
	else {
		m_pHead = pNew;
	}
	m_pTail = pNew;
	m_nCount++;

}

void List::AddHead(DATA data)
{
	SNode *pNew=new SNode;
	pNew->data = data;
	pNew->pNext = m_pHead;
	pNew->pPrev = nullptr;
	if (m_pHead)
		m_pHead->pPrev = pNew;
	else
		m_pTail =pNew;
	
	m_pHead = pNew;
	m_nCount++;


	
}

void List::SetAt(POSITION pos, DATA data)
{
	SNode *p = (SNode*)pos;
	p->data = data;
}

void List::RemoveAt(POSITION pos)
{
	SNode *p = (SNode*)pos,*q;
	if (p == m_pHead)
	{
		m_pHead = p->pNext;
		(p->pNext)->pPrev = nullptr;
	}
	else if(p == m_pTail) {
		m_pTail = p->pPrev;
		p->pPrev->pNext = nullptr;
	}
	else {
		
		p->pNext->pPrev = p->pPrev;
		p->pPrev->pNext = p->pNext;
	}
	delete q;
	m_nCount--;
	
}

void List::PrintH()
{
	SNode *p = m_pHead;
	while (p)
	{
		cout << p->data << endl;
		p = p->pNext;
	}
}


void List::PrintT()
{
	SNode *p = m_pTail;
	while (p)
	{
		cout << p->data << endl;
		p = p->pPrev;
	}
}


void List::RemoveAll()
{
	SNode *p = m_pHead,*q;
	while (p)
	{
		q = p;
		p = p->pNext;
		delete q;
	}
	m_pHead = m_pTail = nullptr;
	m_nCount = 0;

}

第三步,测试链表

#include "stdafx.h"
#include"List.h"
#include<iostream>
using namespace std;
int main()
{
	List list;
	list.AddHead(1);
	list.AddHead(2);
	list.AddHead(3);
	list.AddHead(4);
	list.AddHead(5);
	list.AddTail(11);
	list.AddTail(12);
	list.AddTail(13);
	list.AddTail(14);
	list.AddTail(15);
	list.PrintH();
	cout << endl;
	list.PrintT();
	cout << endl;
	list.RemoveAt(list.GetHeadPosition());
	list.PrintH();
	cout << endl;
    return 0;
}



方法二:使用C++标准库中的List类


注意C++标准库不受平台限制,只要包含头文件#include<list.h>
我们把它封装成我们自己的类来测试~二次封装,方便测试,嘿嘿。
同样:

#pragma once
#include <list>
typedef int DATA;

class MySTCList
{
	std::list<DATA> m_list;
public:
	MySTCList();
	~MySTCList();
	static bool SortBy(DATA data1, DATA data2);
	void AddHead(DATA data);
	void Delete(DATA data);
	void Modify(DATA data);
	bool Search(DATA data);
	void Print();
	void AddTail(DATA data);
	void Sort();
};

#include "stdafx.h"
#include "MySTCList.h"
#include<iostream>
using namespace std;
typedef bool(*MyFunc)(DATA data1, DATA data2);
MySTCList::MySTCList()
{
}


MySTCList::~MySTCList()
{
}

void MySTCList::AddHead(DATA data)
{
	m_list.push_front(data);
}
	


void MySTCList::Delete(DATA data)
{
	list<DATA>::iterator it = m_list.begin();
	while (it != m_list.end()) 
	{
		if (*it == data)
		{
			m_list.erase(it);
			break;
		}
		it++;
	}
}


void MySTCList::Modify(DATA data)
{
	DATA d;
	cout << "你要把" << data << "改成:" << endl;
	cin >> d;
	list<DATA>::iterator it = m_list.begin();
	while (it!= m_list.end())
	{
		if (*it == data)
		{
			*it = d;
			
		}
		it++;
	}
}


bool MySTCList::Search(DATA data)
{
	bool b=false;
	list<DATA>::iterator it = m_list.begin();
	while (it!= m_list.end())
	{
		if (*it == data)
		{
			b = true;
		}
		it++;
	}
	return b;
}


void MySTCList::Print()
{
	list<DATA>::iterator it = m_list.begin();
	while (it != m_list.end())
	{
		cout << *it << endl;
		it++;
	}
}


void MySTCList::AddTail(DATA data)
{
	m_list.push_back(data);
}


void MySTCList::Sort()
{
	MyFunc ByWhich = SortBy;
	m_list.sort(ByWhich);

}

bool MySTCList::SortBy(DATA data1,DATA data2)
{
	return data1 > data2;
}

#include "stdafx.h"
#include"MySTCList.h"
#include<iostream>
using namespace std;

int main()
{
	MySTCList m1;
	m1.AddTail(1);
	m1.AddTail(5);
	m1.AddTail(3);
	m1.AddTail(4);
	m1.AddTail(7);
	m1.AddTail(5);
	m1.AddTail(9);
	m1.AddTail(2);
	m1.Print();
	cout << endl;
	m1.Sort();
	m1.Print();
	cout << endl;
    return 0;
}



方法三:使用微软的标准类库的list


上面的测试显得有点单调,这次我们用微软的list类做一个学生管理系统。
注意这次编译必须采用微软的VS编辑器哦,在编译之前要设置项目属性-配置属性-常规-项目默认值-MFC的使用-在DLL共享中使用MFC
下面贴代码:

#pragma once
#include"afxtempl.h"

typedef struct SUser
{
	int num;
	char name[20];
	double score;
}DATA;

class Student
{
	CList<DATA> m_list;
	int Menu();
public:
	Student();
	~Student();
	void Start();
	void Print();
	void Delete();
	void Add();
	bool Check();
	void Load();
	void Save();
	void Modify();
	void Sort();
	void Search();
	void SortW(int i);
	void PrintW(POSITION *p);
	int SortMenu();
};

#include "stdafx.h"
#include "Student.h"
#include <iostream>
using namespace std;

typedef bool(*BY_FUNC)(DATA &p, DATA &q);

Student::Student()
{
}


Student::~Student()
{
}


int Student::Menu()
{
	int i;
	printf("\n\t\t欢迎使用学生信息管理系统3.0版\n");
	printf("\t\t1.添加学生信息\n");
	printf("\t\t2.修改学生信息\n");
	printf("\t\t3.删除学生信息\n");
	printf("\t\t4.查询学生信息\n");
	printf("\t\t5.对学生信息排序\n");
	printf("\t\t6.显示学生信息\n");
	printf("\t\t7.退出\n");
	cin >> i;
	switch (i)
	{
	case 1:
		Add(); break;
	case 2:
		Modify(); break;
	case 3:
		Delete(); break;
	case 4:
		Search(); break;
	case 5:
		while(SortMenu()); break;
	case 6:
		Print(); break;
	case 7:
		Save(); i = 0; break;
	}
	return i;

}


void Student::Start()
{
	while (Menu())
		;
}


void Student::Print()
{
	POSITION p = m_list.GetHeadPosition();
	DATA d;
	while (p)
	{
		d = m_list.GetAt(p);
		cout << d.num << " " << d.name << " " << d.score << endl;;
		m_list.GetNext(p);
	}
}


void Student::Delete()
{
	int i;
	cout << "请输入删除的学生的学号:" << endl;
	cin >> i;
	POSITION p = m_list.GetHeadPosition();
	while (p)
	{
		if (m_list.GetAt(p).num == i)
		{
			m_list.RemoveAt(p);
			//Save();
			return;
		}
		m_list.GetNext(p);
	}
	printf("未能找到该学号!\n");
}


void Student::Add()
{
	DATA d;
	printf("请输入学号、姓名和成绩(用空格隔开):\n");
	cin >> d.num >> d.name >> d.score;
	m_list.AddTail(d);
	//Save();
}


bool Student::Check()
{
	return false;
}

void Student::Load()
{
	FILE *pf = fopen("stud.txt", "r");
	if (!pf)
	{
		cout << "打开文件异常" << endl;
		return;
	}
	DATA d;
	while (fread(&d, 1, sizeof(DATA), pf) == sizeof(d))
	{
		m_list.AddTail(d);
	}
	fclose(pf);
}

void Student::Save()
{
	FILE *pf = fopen("stud.txt", "w");
	if (!pf)
	{
		cout << "保存文件异常" << endl;
		return;
	}
	POSITION p = m_list.GetHeadPosition();
	while(p)
	{
		DATA d = m_list.GetAt(p);//不能放在外面定义
		fwrite(&d, 1, sizeof(DATA), pf);
		m_list.GetNext(p);
	}
	fclose(pf);
}
	


void Student::Modify()
{
	int i;
	DATA d;
	cout << "请输入要修改的学生学号:" << endl;
	cin >> i;
	POSITION p = m_list.GetHeadPosition();
	while (p)
	{
		if (m_list.GetAt(p).num == i)
		{
			printf("请输入新的姓名和成绩:\n");
			d.num = i;
			cin >> d.name >> d.score;
			m_list.SetAt(p, d);
			Save();
			return;
		}
		m_list.GetNext(p);
	}
	printf("没有找到该学号的学生信息!\n");
}

void Student::Sort()
{
	POSITION p = m_list.GetHeadPosition();
	POSITION q, m;
	DATA d;
	while (p)
	{
		q = m = p;
		m_list.GetNext(q);
		while (q)
		{
			if (m_list.GetAt(m).score > m_list.GetAt(q).score)
				m = q;
			m_list.GetNext(q);
		}
		if (m != p)
		{
			d = m_list.GetAt(m);
			m_list.SetAt(m, m_list.GetAt(p));
			m_list.SetAt(p, d);
		}
		m_list.GetNext(p);
	}
}



void Student::Search()
{
	int i;
	DATA d;
	cout << "请输入要查寻的学生学号:" << endl;
	cin >> i;
	POSITION p = m_list.GetHeadPosition();
	while (p)
	{
		if (m_list.GetAt(p).num == i)
		{
			d = m_list.GetAt(p);
			cout << d.num << " " << d.name << " " << d.score << endl;
		}
		m_list.GetNext(p);
	}
	printf("没有找到该学号的学生信息!\n");
}

bool ByNum(DATA &p, DATA &q)
{
	return p.num > q.num;
}
bool ByName(DATA &p, DATA &q)
{
	//int strcmp ( char const *s1, char const *s2);
	//如果s1小于s2,strcmp函数返回一个小于零的值。如果s1大于s2,函数返回一个大于零的值。如果两个字符串相等,函数就返回零。
	return (strcmp(p.name, q.name) > 0) ? true:false;
}
bool ByScore(DATA &p, DATA &q)
{
	return p.score > q.score;
}

void Student::SortW(int i)
{
	BY_FUNC cmp[] = { ByNum,ByName,ByScore };
	int n = m_list.GetCount();
	POSITION p = m_list.GetHeadPosition();
	POSITION *ps = new POSITION[n+1];
	int x = 0, y=0;
	while (ps[x++]=p)
	{
		m_list.GetNext(p);
	}

	x = 0;

	int min;
	POSITION q;
	while (x < n-1)
	{
		min = x;
		y = x + 1;
		while (y<n)
		{
			//if (m_list.GetAt(ps[min]).score > m_list.GetAt(ps[y]).score)
			if(cmp[i-1](m_list.GetAt(ps[min]), m_list.GetAt(ps[y])))
				min =y;
			y++;
		}
		q = ps[min];
		ps[min] = ps[x];
		ps[x] = q;
		x++;
	}
	PrintW(ps);
}


void Student::PrintW(POSITION *ps)
{
	int i = 0;
	cout << "学号\t姓名\t数学成绩" << endl;
	while (ps[i])
	{
		DATA d = m_list.GetAt(ps[i]);
		cout << d.num << "\t" << d.name << "\t" << d.score << endl;
		++i;
	}
	system("pause");
}


int Student::SortMenu()
{
	system("cls");
	int i;
	printf("\t\t请输入排序类型:\n");
	printf("\t\t1.按照学号排序\n");
	printf("\t\t2.按照姓名排序\n");
	printf("\t\t3.按照成绩排序\n");
	printf("\t\t4.返回主菜单\n");
	cin >> i;
	switch (i)
	{
	case 1:
	case 2:
	case 3:
		SortW(i); break;
	case 4:
		i = 0;
		break;
	}
	
	return i;

}

// Stud_ld3.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include"Student.h"

int main()
{
	Student st;
	st.Load();
	st.Start();
    return 0;
}


好了,代码来那个看起来有点大啊,慢慢看吧~年轻人嘛,要慢下性子来~别忘了我们的作业哦




猜你喜欢

转载自blog.csdn.net/sinat_27614619/article/details/53307810