数据结构 | C++ |链表的基本操作
关于构造函数
顺序存储结构的构造函数:要创建一个空数组,最大尺寸为MAXSIZE,并设置一个length变量表示数组的实际长度
链式存储结构的构造函数:要让elem (链表)/top (链栈)/rear&front (链队)/root (树) = nullptr
1.LinkList.h文件
//节点类
class Node {
public:
string ActName; //训练动作的名称
int sets; //组数
int reps; //次数
int weight; //重量
int mood; //训练感受
Node *next = nullptr; //必须初始化,否则p读取访问权限冲突
};
//链表类
class LinkList {
public:
LinkList(); //构造函数,用于初始化
~LinkList(); //销毁一个单链表;
void CreateLinkList(); //创建一个单链表
void MakeData(Node data); //数据套格式
void TravalLinkList(); //遍历线性表
int GetLength(); //获取线性表长度
void IsEmpty(); //判断单链表是否为空
int FindAtData(string data); //按值查找节点
void InsertElemAtEnd(); //在尾部插入指定的节点
void InsertElemAtIndex(int n); //在指定位置插入指定节点
void InsertElemAtHead(); //在头部插入指定节点
void DeleteElemAtEnd(); //在尾部删除节点
void DeleteAll(); //删除所有节点
void DeleteElemAtHead(); //在头部删除节点
void DeleteElemAtPoint(string data); //按值删除节点
private:
Node *elem;//头指针
};
//构造函数,用于初始化
LinkList::LinkList()
{
//此处链表类有头节点
elem = new Node();
elem->ActName = "空";
elem->reps = 0;
elem->sets = 0;
elem->weight = 0;
elem->mood = 0;
elem->next = nullptr;
}
//销毁一个单链表;
LinkList::~LinkList()
{//new出来的节点无法自动释放空间
Node *p = elem; Node *q = nullptr;
while (p)
{
q = p;
p = p->next;
delete q;
}
elem = nullptr;
}
//创建链表
void LinkList::CreateLinkList()
{
cout << "输入训练名称时,按q停止输入\n";
Node *p, *q;
p = elem;
bool n = true; int i = 1;
while (n)
{
q = new Node;
cout << "输入第" << i << "个动作名称\n"; cin >> q->ActName; if (q->ActName == "q") { n = false; break; }//用于退出循环
cout << "输入组数\n"; cin >>q->sets;
cout << "输入次数\n"; cin >> q->reps;
cout << "输入质量\n"; cin >>q->weight;
cout << "1 代表极差,5 代表极好\n"; cin >> q->mood;
cout << endl;
q->next = nullptr;
p->next = q;
p = p->next;
i++;
}
}
//套格式
void LinkList::MakeData(Node data)
{
cout << data.ActName << "\t" << data.sets << "组" << " × " << data.reps << "次" << "\t" << data.weight << "KG\t";
switch (data.mood)
{
case 1:cout << "Shit"; break;
case 2:cout << "No good"; break;
case 3:cout << "Normal"; break;
case 4:cout << "Fine"; break;
case 5:cout << "Nice"; break;
default:cout << "无效"; break;
}
cout << endl;
}
//遍历链表
void LinkList::TravalLinkList()
{
Node *p = elem;//指向头结点(空)
if (p == nullptr) { cout << "是空表!"; }
while (p->next != nullptr)
{
p = p->next;
MakeData(*p);
}
cout << endl;
}
//获取单链表的长
int LinkList::GetLength()
{
int count = 0;
Node *p = elem;
while (p->next != nullptr)
{
p = p->next;
count++;
}
return count;
}
//判断单链表是否为空
void LinkList::IsEmpty() {
if (elem->next == nullptr || elem == nullptr)
cout << "是空表\n";
else
cout << "非空表\n";
}
//按动作名称查找节点
int LinkList::FindAtData(string data)
{
Node *p = elem;//p指向头节点,因为可能没有首元节点
int j = 0;//计数器
if (p == nullptr || p->next == nullptr) { cout << "是空表" << endl; }
while (p&&p->ActName != data) //p未指向nullptr 且 值不符
{
p = p->next;
j++;
}
if (p)//意思是p还在表内
{
return j;
}
else
return 0;
}
//尾插法
void LinkList::InsertElemAtEnd()
{
Node *p, *q;
q = new Node;
cout << "输入新动作名称\n"; cin >> q->ActName;
cout << "输入组数\n"; cin >> q->sets;
cout << "输入次数\n"; cin >> q->reps;
cout << "输入质量\n"; cin >> q->weight;
cout << "1 代表极差,5 代表极好\n"; cin >> q->mood;
cout << endl;
q->next = nullptr;//用q指向一个新节点来储存值.
p = elem;
while (p->next != nullptr)//p指针循环至原链表最后一个结点
{
p = p->next;
}
p->next = q;//连接两个结点
p = q;
}
//按位插入节点
void LinkList::InsertElemAtIndex(int n)
{
if (n<0 || n>GetLength()) { cout << "超出链表范围"; }
else
{
Node *p, *q;
q = new Node;
cout << "输入新动作名称\n"; cin >> q->ActName;
cout << "输入组数\n"; cin >> q->sets;
cout << "输入次数\n"; cin >> q->reps;
cout << "输入质量\n"; cin >> q->weight;
cout << "1 代表极差,5 代表极好\n"; cin >> q->mood;
cout << endl;
q->next = nullptr;//用q指向一个新节点来储存值.
p = elem;
for (int i = 0; i < n - 1; i++)//循环n-1次,p指针指向待插入位置的前一个结点
{
p = p->next;
}
q->next = p->next;//新节点和下一个连接 先改变已有的链
p->next = q;//新节点和前一个连接 再新建链
}
}
//头插法
void LinkList::InsertElemAtHead()
{
Node *p, *q;
q = new Node;
cout << "输入新动作名称\n"; cin >> q->ActName;
cout << "输入组数\n"; cin >> q->sets;
cout << "输入次数\n"; cin >> q->reps;
cout << "输入质量\n"; cin >> q->weight;
cout << "1 代表极差,5 代表极好\n"; cin >> q->mood;
cout << endl;
q->next = nullptr;//用q指向一个新节点来储存值.
p = elem;
q->next = p->next;//p指向旧首元节点,变成q指向旧首元节点
p->next = q;
}
//在尾部删除节点
void LinkList::DeleteElemAtEnd()
{
Node *p = elem;
Node *q = nullptr;
if (p->next == nullptr) { cout << "是空表"; }
while (p->next != nullptr)
{
q = p; //最终,q指向倒数第二个
p = p->next;//最终,p指向最后一个
}
delete p;//回收p所指结点的内存空间
q->next = nullptr;//新的尾结点置空
}
//删除所有节点
void LinkList::DeleteAll()
{
Node *p = elem->next;//p指向首元结点
Node *q = nullptr;//创建一个q的空指针
while (p != nullptr)
{
q = p;//两个指针同时指向第一个数据
p = p->next;//p后移一位
elem->next = p;
q->next = nullptr;
delete q;//删除q所指向的对象后,还要不要把q本身置nullptr?
}
elem->next = nullptr;//好像是冗余语句
}
//在头部删除节点
void LinkList::DeleteElemAtHead()
{
Node *p = elem;
if (p == nullptr || p->next == nullptr)
{
cout << "是空表!" << endl;
}
else
{
p = p->next;
elem->next = p->next;
p->next = nullptr;
delete p;
/* 另一种实现代码
Node * q = nullptr; //创建一个占位节点
p = p->next;
q = p->next; //将头结点的下下个节点指向占位节点
delete p; //删除头结点的下一个节点
p = nullptr;
elem->next = q; //头结点的指针更换*/
}
}
//按值删除节点
void LinkList::DeleteElemAtPoint(string data)
{
Node *p = elem;
for (int i = 0; i <= FindAtData(data); i++)//循环至指定位置
{
p = p->next;
}
if (p == elem->next)
{
DeleteElemAtHead();
}
else
{
Node *q = elem->next;//q指向第一个数据
while (q->next != p)//让q指向p的前一个数据
{
q = q->next;
}
q->next = p->next;//删除节点
p->next = nullptr;
delete p;
p = nullptr;//与220行对比一下,可以不写
}
}
2.main()函数
//题目是"训练笔记"
using namespace std;
#include <iostream>
#include<string>
const int MAX = 100;
#include"LIst.h"
#include"LinkList.h"
int main()
{
LinkList LA;
cout << "1.创建表 2.打印全表 3.求表长\n";
cout << "4.判断空表 5.查找结点 6.在链尾插值\n";
cout << "7.在链头插值 8.按位插值 9.从链尾删值\n";
cout << "10.从链头删值 11.按值删除 12.删除所有值\n";
cout << "0.退出\n";
int i; string data; string pdata;
do {
cout << "键入操作\n";
cin >> i;
switch (i)
{
case 1:
LA.CreateLinkList();
break;
case 2:
LA.TravalLinkList();
break;
case 3:
cout << "表长为: " << LA.GetLength() << endl;//一般来说,void函数不必加cout语句,但其他非void类型函数要加.
break;
case 4:
LA.IsEmpty();
break;
case 5:
cout << "输入要查找的训练动作名称\n";
cin >> data;
cout << "要查找的值在第" << LA.FindAtData(data) << "位(第0位则不存在值)" << endl;
break;
case 6:
LA.InsertElemAtEnd();
LA.TravalLinkList();
cout << "\t插入成功!" << endl;
break;
case 7:
int headata;
cout << "输入要插入的值\n";
cin >> headata;
LA.InsertElemAtHead();
LA.TravalLinkList();
cout << "\t插入成功!" << endl;
break;
case 8:
int bit, bitdata;
cout << "输入要插入的位置\n";
cin >> bit;
cout << "输入要插入的值\n";
cin >> bitdata;
LA.InsertElemAtIndex(bit);
LA.TravalLinkList();
cout << "\t插入成功!" << endl;
break;
case 9:
LA.DeleteElemAtEnd();
LA.TravalLinkList();
cout << "\t删除成功!" << endl;
break;
case 10:
LA.DeleteElemAtHead();
LA.TravalLinkList();
cout << "\t删除成功!" << endl;
break;
case 11:
cout << "输入要删除的值\n";
cin >> pdata;
LA.DeleteElemAtPoint(pdata);
LA.TravalLinkList();
break;
case 12:
LA.DeleteAll();
LA.TravalLinkList();
cout << "删除成功!" << endl;
break;
default:cout << "输入代号错误!" << endl;
}
} while (i != 0);
system("pause");
return 0;
}
Tips:
- 在if语句中,if(p)意思是p指针还指向着表内的元素,没有变成NULL.

浙公网安备 33010602011771号