数据结构 | 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:

  1. 在if语句中,if(p)意思是p指针还指向着表内的元素,没有变成NULL.
posted @ 2019-04-07 12:22  心碎人俱乐部  阅读(14)  评论(0)    收藏  举报