单链表(C++实现)

数据结构(面向对象方法与C++语言描述)(第2版)单链表内容整理

单链表

单链表的特点是长度可以很方便地进行扩充。

代码实现

环境:vs2019
头文件:LinkedList.h
源文件:main.cpp

LinkedList.h代码:

#pragma once

#include <iostream>

template<typename T>
struct LinkNode {											//链表结点的定义
	T data;													//数据域
	LinkNode<T>* link;										//链指针域
	LinkNode(LinkNode<T>* ptr = nullptr) { link = ptr; }	//仅初始化指针成员的构造函数
	LinkNode(const T& item, LinkNode<T>* ptr = nullptr)		//初始化数据与指针成员的构造函数
	{
		data = item;
		link = ptr;
	}
};

template<typename T>
class List {
public:
	List() { first = new LinkNode<T>; }						//构造函数
	List(const T& x) { first = new LinkNode<T>(x); }		//构造函数
	List(List<T>& L);										//拷贝构造函数
	~List() { makeEmpty(); }								//析构函数
	void makeEmpty();										//将链表置为空表
	int Length()const;										//计算链表的长度
	LinkNode<T>* getHead()const { return first; }			//返回附加头结点地址
	LinkNode<T>* Search(T x);								//搜索含数据x的元素
	LinkNode<T>* Locate(int i)const;						//搜索第i个元素的地址
	bool getData(int i, T& x)const;							//取出第i个元素的地址
	void setData(int i, T& x);								//用x修改第i个元素的值
	bool Insert(int i, T& x);								//在第i个元素后插入x
	bool Remove(int i, T& x);								//删除第i个元素,x返回该元素的值
	bool IsEmpty()const										//判表空否?空则返回true
	{
		return first->link == nullptr ? true : false;
	}
	bool IsFull()const { return false; }					//判表满否?不满则返回false
	void Sort();											//排序
	void input();											//输入
	void output();											//输出
	List<T>& operator=(List<T>& L);							//重载运算符=
	void inputFront(T endTag);								//前插法建立单链表
	void inputRear(T endTag);								//后插法建立单链表
protected:
	LinkNode<T>* first;										//链表的头指针
};

template<typename T>
inline List<T>::List(List<T>& L)
{
	//拷贝构造函数
	T value;
	LinkNode<T>* srcptr = L.getHead();						//被赋值表的附加头结点地址
	LinkNode<T>* destptr = first = new LinkNode<T>;
	while (srcptr->link != nullptr)							//逐个结点复制
	{
		value = srcptr->link->data;
		destptr->link = new LinkNode<T>(value);
		destptr = destptr->link;
		srcptr = srcptr->link;
	}
	destptr->link = nullptr;
}

template<typename T>
inline void List<T>::makeEmpty()
{
	//将链表置位空表
	LinkNode<T>* q;
	while (first->link != nullptr)							//当链不空时,删去链中所有结点
	{
		q = first->link;
		first->link = q->link;								//保存被删结点,从链上摘下该节点
		delete q;											//删除(仅保留一个表头节点)
	}
}

template<typename T>
inline int List<T>::Length() const
{
	//计算带附加头结点的单链表的长度
	LinkNode<T>* p = first->link;
	int count = 0;
	while (p != nullptr)									//循链扫描,寻找链尾
	{
		p = p->link;
		count++;
	}
	return count;
}

template<typename T>
inline LinkNode<T>* List<T>::Search(T x)
{
	//在表中搜索含数据x的节点,搜索成功时函数返回该节点地址;否则返回NULL值。
	LinkNode<T>* current = first->link;
	while (current != nullptr)
	{
		if (current->data == x) break;						//循链找含x结点
		else current = current->link;
	}
	return current;
}

template<typename T>
inline LinkNode<T>* List<T>::Locate(int i) const
{
	//定位函数。返回表中第i个元素的地址。若i<0或i超过表中结点个数,则返回NULL。
	if (i < 0) return nullptr;								//i不合理
	LinkNode<T>* current = first;
	int k = 0;
	while (current != nullptr && k < i)						//循链找第i个结点
	{
		current = current->link;
		k++;
	}
	return current;											//返回第i个结点地址,若返回NULL,表示i值太大
}

template<typename T>
inline bool List<T>::getData(int i, T& x) const
{
	//取出链表中第i个元素的值。
	if (i <= 0) return false;								//i值太小
	LinkNode<T>* current = Locate(i);
	if (current == nullptr) return false;					//i值太大
	else
	{
		x = current->data;
		return true;
	}
}

template<typename T>
inline void List<T>::setData(int i, T& x)
{
	//给链表中的第i个元素赋值x。
	if (i <= 0) return;										//i值太小
	LinkNode<T>* current = Locate(i);
	if (current == nullptr) return;							//i值太大
	else current->data = x;
}

template<typename T>
inline bool List<T>::Insert(int i, T& x)
{
	//将新元素x插入在链表中第i个结点之后。
	LinkNode<T>* current = Locate(i);
	if (current == nullptr) return false;					//插入不成功
	LinkNode<T>* newNode = new LinkNode<T>(x);
	if (newNode == nullptr)
	{
		std::cerr << "存储分配错误!" << std::endl;
		exit(1);
	}
	newNode->link = current->link;
	current->link = newNode;
	return true;											//插入成功
}

template<typename T>
inline bool List<T>::Remove(int i, T& x)
{
	//将链表中的第i个元素扇区,通过引用型参数x返回该元素的值。
	LinkNode<T>* current = Locate(i - 1);
	if (current == nullptr || current->link == nullptr)	return false;
	//删除不成功
	LinkNode<T>* del = current->link;						//重新拉链,将被删结点从链中摘下
	current->link = del->link;
	x = del->data;
	delete del;												//取出被删结点中的数据值
	return true;
}

template<typename T>
inline void List<T>::Sort()
{
}

template<typename T>
inline void List<T>::input()
{
}

template<typename T>
inline void List<T>::output()
{
	//单链表的输出函数:将单链表中所有数据按逻辑顺序输出到屏幕上。
	std::cout << "链表中的元素为:" << std::endl;
	LinkNode<T>* current = first->link;
	while (current != nullptr)
	{
		std::cout << current->data << " ";
		current = current->link;
	}
	std::cout << std::endl;
}

template<typename T>
inline List<T>& List<T>::operator=(List<T>& L)
{
	//重载函数:赋值操作,形式如 A = B,其中 A 是调用此操作的List对象,B 是参数表中的
	//引用型参数L结合的实参。
	makeEmpty();
	T value;
	LinkNode<T>* srcptr = L.getHead();						//被复制表的附加头结点地址
	LinkNode<T>* destptr = first = new LinkNode<T>;
	while (srcptr->link != nullptr)							//逐个结点复制
	{
		value = srcptr->link->data;
		destptr->link = new LinkNode<T>(value);
		destptr = destptr->link;
		srcptr = srcptr->link;
	}
	destptr->link = nullptr;
	return *this;											//返回操作对象地址
}

template<typename T>
inline void List<T>::inputFront(T endTag)
{
	//endTag是约定的输入序列结束的标志。如果输入序列是正整数,endTag可以是0或负数;
	//如果输入序列是字符,endTag可以是字符集中不会出现的字符,如"\0"。
	LinkNode<T>* newNode;
	T val;
	makeEmpty();
	std::cin >> val;
	while (val != endTag)
	{
		newNode = new LinkNode<T>(val);						//创建新结点
		if (newNode == nullptr)
		{
			std::cerr << "存储分配错误!" << std::endl;
			exit(1);
		}
		newNode->link = first->link;
		first->link = newNode;								//插入到表最前端
		std::cin >> val;
	}
}

template<typename T>
inline void List<T>::inputRear(T endTag)
{
	//endTag是约定的输入序列结束的标志
	LinkNode<T>* newNode, * last;
	T val;
	makeEmpty();
	std::cin >> val;
	last = first;
	while (val != endTag)									//last指向表尾
	{
		newNode = new LinkNode<T>(val);
		if (newNode == nullptr)
		{
			std::cerr << "存储分配错误!" << std::endl;
			exit(1);
		}
		last->link = newNode;
		last = newNode;
		std::cin >> val;									//插入到表末端
	}
	last->link = nullptr;									//表首位,这一句实际可省略
}

main.cpp代码:

#include "LinkedList.h"

int main()
{
	List<int> L1;
	List<int> L2;
	int val = 0;
	bool flag = false;

	std::cout << "Q:测试IsEmpty()  链表是否为空" << std::endl;
	flag = L1.IsEmpty();
	if (flag) std::cout << "链表为空" << std::endl;
	else std::cout << "链表不为空" << std::endl;

	std::cout << "Q:测试inputFront()  前插法建立单链表" << std::endl;
	L1.inputFront(-1);
	L1.output();

	std::cout << "Q:测试IsEmpty()  链表是否为空" << std::endl;
	flag = L1.IsEmpty();
	if (flag) std::cout << "链表为空" << std::endl;
	else std::cout << "链表不为空" << std::endl;

	std::cout << "Q:测试Length()  链表的长度为:" << std::endl;
	std::cout << L1.Length() << std::endl;

	std::cout << "Q:测试getData()  取第3个元素的值:" << std::endl;
	L1.getData(3, val);
	std::cout << val << std::endl;

	std::cout << "Q:测试setData()  修改第6个元素的值为99" << std::endl;
	val = 99;
	L1.setData(6, val);
	L1.output();

	std::cout << "Q:测试Insert()  在第8个元素后插入77" << std::endl;
	val = 77;
	L1.Insert(8, val);
	L1.output();

	std::cout << "Q:测试Remove()  删除第3个元素" << std::endl;
	L1.Remove(3, val);
	std::cout << "Q:删除的元素为:" << val << std::endl;
	L1.output();

	std::cout << "Q:测试inputRear()  后插法建立单链表" << std::endl;
	L2.inputRear(-1);
	L2.output();

	std::cout << "Q:测试operator=()  赋值单链表" << std::endl;
	L2 = L1;
	L2.output();

	return 0;
}

控制台界面:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值