回头学学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;
}
好了,代码来那个看起来有点大啊,慢慢看吧~年轻人嘛,要慢下性子来~别忘了我们的作业哦