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