数据结构(面向对象方法与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;
}
控制台界面:


被折叠的 条评论
为什么被折叠?



