C++实现单链表的基本功能

本文详细介绍了如何使用C++实现单链表,包括链表节点结构、成员函数如插入、删除、查找和显示,以及头文件和源文件的编写。在实际操作中,作者遇到了头节点未正确初始化的问题,并分享了如何解决这个问题,提醒初学者在使用链表时应注意对头节点进行地址分配。
摘要由CSDN通过智能技术生成

链表是指使用链接的方式存储的线性表,一般一个单链表结点由数据域和指针域两个域组成如图1所示,其中数据域data存放该结点的数据域的值,指针域next存放该结点的后继结点的地址信息。

图1单链表的结点

2、单链表的头文件

#pragma once


#include<iostream>
#include<string.h>
struct StuNode//代表学生的节点
{
	int ID;//学号
	char name[10];//姓名

	struct StuNode *next;
};
typedef struct StuNode  StuNode;

class SLList
{

private:
	
	StuNode *head;//表头指针
	int length;

public:
	SLList();
	~SLList(void);
	bool IsEmpty(void)const { return head->next ==NULL; }//判断链表是否为空
	int Length()const { return this->length; }//返回链表长度
	int Find(StuNode &item)const;//根据学生的学号查找学生
	void DisPlay();//打印出链表中所有的学生信息
	void Delete(StuNode &item);//删除链表
	void Insert(const StuNode &item);//插入链表
};

3、单链表的.ccp文件


#include<string.h>
#include"sllist.h"
#include<iostream>
using namespace std;

SLList::SLList()
{
	this->head = NULL;
	this->length = 0;
}

SLList::~SLList()
{
	StuNode* temp;
	for (int i = 0; i < this->length; i++)
	{
		temp = head;
		head = head->next;
		delete temp;

	}
}

int SLList::Find( StuNode & item) const
{
	StuNode *temp = head;

	for (int i = 0; i < this->length; i++)
	{
		if (temp->next->ID == item.ID)
		{
			cout <<temp->next->name<<"的位置为:" << i << endl;
			return i;
		}
		temp = temp->next;
	}
	cout << "没有该学生" << endl;
	return -1;
}

void SLList::DisPlay()
{
	cout << "人员信息:" << endl;
	cout << endl;
	StuNode *temp = head;
	while (temp->next != NULL)
	{
		cout << "学号:" <<temp->next->ID<< endl;
		cout << "姓名:" << temp->next->name << endl;
		temp = temp->next;
		cout << endl;
	}	
}
void SLList::Insert(const StuNode &item)
{
	if (this->head == NULL)/*头节点插入数据*/
	{
		StuNode *hemp = new StuNode;
		this->head = hemp;
		StuNode *node = new StuNode;
		strcpy(node->name, item.name);
		node->ID = item.ID;

		this->head->next = node;
		node->next = NULL;
		this->length++;

		return;
	}
	else//尾节点插入数据
	{
		StuNode *temp = head;
		while (temp->next != NULL)
		{
			temp = temp->next;
		}

		StuNode *node = new StuNode;
		strcpy(node->name, item.name);
		node->ID = item.ID;

		temp->next = node;
		node->next = NULL;
		this->length++;

		return;
	}

	cout << "插入数据出错" << endl;

}

void SLList::Delete(StuNode & item)//根据学号删除链表中的信息
{
	int ret = 0;
	ret = Find(item);
	if (ret == -1)
	{
		cout << "没有该学生,无法删除" << endl;
		return;
	}
	else if (ret == 0)//头节点删除
	{
		StuNode *temp = this->head;//
		StuNode *stmp = temp->next;
		this->head->next = stmp->next;
		delete stmp;
		this->length--;


		return ;
	}
	else if (ret > 0 && ret < this->length)//中间删除
	{
		StuNode *temp = this->head;
		for (int i = 0; i <ret; i++)
		{
			temp = temp->next;
		}
		StuNode *stemp = temp->next;//与上面的删除同理
		temp->next = stemp->next;
		delete stemp;
		this->length--;

		return;
	}
	else
	{
		//尾节点删除
		StuNode *temp = this->head;
		while (temp->next->next != NULL)
		{
			temp = temp->next;
		}

		StuNode *ptem = temp->next;//保存住尾节点的地址
		temp->next = NULL;
		delete ptem;
		this->length--;

		return;
	}

	cout << "删除出错" << endl;

}


4、测试程序

#include"sllist.h"
#include<iostream>

using namespace std;

int main()
{
	
	StuNode s1,s2,s3;
	s1.ID = 20201;
	strcpy(s1.name, "张三");

	s2.ID = 20202;
	strcpy(s2.name, "李四");

	s3.ID = 20203;
	strcpy(s3.name, "王五");

	SLList a;
	a.Insert(s1);
	a.Insert(s2);
	a.Insert(s3);

	a.Find(s2);//查找李四 结点的位置是从0开始所以李四在结点的位置是1

	a.DisPlay();//展示链表中存储的所有信息
	cout << endl;

	a.Delete(s2);// 删除李四
	a.Find(s2);//查找链表否还有李四
	a.DisPlay();
	return 0;
}

5、测试的效果如图2所示
图2 链表的程序图

6、总结
刚开始写单链表的时候给头结点this->head=NULL初始化后,没有创建一个新结点,而是直接拿来用,程序一直运行不正确、之后在调试后才发现没有给头结点分配地址,这个错误浪费了好长时间,对于新手来说使用链表时要记得对头结点分配地址如下步骤

if (this->head == NULL)/*头节点插入数据*/
	{
		StuNode *hemp = new StuNode;//将原来this->head=NULL
		this->head = hemp;//使用new 重新创建一个结点复制给head
	}
#include <iostream> using namespace std; const int MaxSize=100; template <class T> //模板类 class SeqList { public: SeqList() {length=0;} //无参构造函数 SeqList(T a[],int n); //有参构造函数 ~SeqList(){} //析构函数 int Length() {return length;} //求线性表长度 T Get(int i); //按位查找 int Locate(T x); //按值查找 void Insert (int i, T x); // 插入函数 T Delete(int i); //删除函数 void PrintList(); //遍历线性表,按序号依次输出各个元素。 private: T data[MaxSize]; int length; }; template<class T> SeqList<T>::SeqList(T a[],int n) //有参构造函数 { if(n>MaxSize)throw"参数非法"; for(int i=0;i<n;i++) data[i]=a[i]; length=n; } template <class T> void SeqList<T>::Insert(int i,T x) //插入函数 { if (length>=MaxSize) throw "上溢"; if(i<1||i>length+1) throw "位置异常"; for (int j=length;j>=i;j--) data[j]=data[j-1]; data[i-1]=x; length++; } template <class T> T SeqList<T>::Get(int i) //按位查找函数 { if(i<1||i>length) throw "查找位置非法"; else return data[i-1]; } template <class T> int SeqList<T>::Locate(T x) //按值查找函数 { for (int i=0;i<length;i++) if (data[i]==x)return i+1; return 0; } template <class T> T SeqList<T>::Delete(int i) //删除函数 { if (int length=0)throw "下溢"; if(i<1||i>length)throw "位置异常"; T x=data[i-1]; for(int j=i;j<length;j++) data[j-1]=data[j]; length--; return x; } template<class T> void SeqList<T>::PrintList() // 遍历线性表 { for (int i=0;i<length;i++) cout<<data[i]<<" "; cout<<endl; } void menu() { cout<<" 欢迎,欢迎!"<<endl; cout<<" 1.插入查询"<<endl; cout<<" 2.删除函数"<<endl; cout<<" 3.求表长"<<endl; cout<<" 4.按值查找"<<endl; cout<<" 5.按位查找"<<endl; cout<<" 6.遍历线性表"<<endl; cout<<" 7.退出"<<endl; cout<<" "<<endl; cout<<" 请选择编号:"<<endl; } int main() { int i,j,x; int a[7]={12,15,24,56,67,68,86}; SeqList<int> s1(a,7); int flag=1; while(flag) { menu(); cin>>j; switch(j) { case 1: { try { cout<<"显示要插入的位序及数值:"<<endl; cin>>i>>x; cout<<endl; s1.Insert(i,x); s1.PrintList(); } catch (char *s){cout<<s<<endl;} }; break; case 2: { try { cout<<"输入元素所在位置"; cin>>i; x=s1.Delete(i); cout<<"已删除:"<<x<<endl; cout<<"删除数据后表变为:"<<endl; s1.PrintList(); } catch (char *s){cout<<s<<endl;} }; break; case 3: { try { s1.Length(); cout<<"线性表长度为:"<<s1.Length()<<endl; } catch(char *s){cout<<s<<endl;} }; break; case 4: { try { cout<<"输入查找数据x:"<<endl; cin>>x; s1.Locate(x); cout<<"所查数据在第"<<s1.Locate(x)<<"位"<<endl; } catch(char *s){cout<<s<<endl;} }; break; case 5: { try { cout<<"查找位置i="; cin>>i; s1.Get(i); cout<<"该位置元素为:"<<s1.Get(i)<<endl; } catch(char *s){cout<<s<<endl;} }; break; case 6: { try { s1.PrintList(); } catch(char *s){cout<<s<<endl;} }; break; case 7: flag=0; break; default:cout<<"错误!!!"<<endl; break; } } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值