前情提要
以下操作涉及模板类、类的继承、运算符重载,不认识可以先了解一下,当然链表的基本原理和操作也是要会的。
链表类元素和方法
该链表有两种类组成
node链表节点类类
template <typename T>
class node
{
public:
T data = 0;
node *next = nullptr;
// 节点类node的方法
node operator=(T Data);
operator T();
int length();
};
node的继承类head,表示表头
template <typename T>
class head : private node<T>
{
private:
int size;//表示链表长度
private:
int size = 0;
head pushBack(T Data);
head pushBack(head Head);
head pushBack(node<T> *Node);
//由于模板类的原因,该函数只能写在函数内部,具体原因后面解释
head popBack(int num = 1)
{
if (size > 0)
{
node<T> *temp1 = this;
node<T> *temp2 = end(num);
for (int i = 0; i < num; i++)
{
temp1 = temp2;
temp2 = temp2->next;
if (temp1->next != this->next)
{
delete temp1->next;
}
else
{
cout << "cut down a cirtual list" << endl;
}
temp1->next = nullptr;
}
size -= num;
}
return *this;
}
//别问为什么没有public,后面会加
}
链表类的方法详解
node类的方法
template <typename T>
int node<T>::length()
{
int length = 1;
node *temp = next;
while (temp != nullptr)
{
temp = temp->next;
length++;
}
return length;
}
head类的方法
// head链表操作的基本方法
template <typename T>
head<T> head<T>::pushBack(T Data)
{
// 申请空间
node<T> *n = new node<T>;
n->data = Data;
n->next = nullptr; // 初始化
end()->next = n;
size++;
return *this;
}
template <typename T>
head<T> head<T>::pushBack(head<T> Head)
{
end()->next = Head.next;
if (Head.next != this->next)
size += Head.size;
else
size++;
return *this;
}
template <typename T>
head<T> head<T>::pushBack(node<T> *Node)
{
end()->next = Node;
size += Node->length();
return *this;
}
运算符重载类方法
运算符重载就是链表运算符化的重点内容
node类的运算符重载
template <typename T>
node<T>::operator T()
{
return data;
}
head类的运算符重载,把以下内容写到head类里
public:
int length()
{
return size;
}
head operator-=(int num)
{
return popBack(num);
}
head operator--(int)
{
return popBack();
}
head operator+=(head Node)
{
return pushBack(Node);
}
head operator+=(node<T> &Node)
{
return pushBack(&Node);
}
friend head operator+(head x, head y)
{
return x.pushBack(y);
}
friend head operator+(T Data, head n)
{
return n.pushBack(Data);
}
friend head operator+(head n, T Data)
{
return n.pushBack(Data);
}
head operator+=(T Data)
{
return pushBack(Data);
}
//链表的数组运算重载
node<T> &operator[](int index)
{
node<T> *temp = this->next;
for (int i = 0; i < index && temp->next != nullptr; i++)
{
temp = temp->next;
}
if (temp->next == nullptr)
cout << "index out of range" << endl;
return *temp;
}
//链表的标准输出重载
friend ostream &operator<<(ostream &out, head n)
{
node<T> *temp = n.next;
node<T> *head = n.next;
if (temp != nullptr)
{
out << temp->data;
temp = temp->next;
}
else
return out;
while (temp != nullptr)
{
if (temp == head)
{
out << " -> head(list cirtual)";
break;
}
out << " -> " << temp->data;
temp = temp->next;
}
return out;
}
注意事项
有些类函数不能只在类里写声明,还有写函数本体。
例如下面函数,返回值是模板类,传入的值确实一个固定的类型,当我们调用这个函数时,模板无法判断用户调用的类型,无法成功构建模板函数。
head popBack(int num = 1)
以下的函数则可以只在在模板类内部写声明
head pushBack(T Data);
head pushBack(head Head);
head pushBack(node<T> *Node);
因为该函数的传入的值是模板类型,编译器可以根据用户调用的函数时传入函数的数据类型构建模板函数
解决方法
不符合以上标准的模板函数直接在模板类内部写函数本体,这样用户在声明模板类时,编译器就可以根据用户声明类模板的特定数据类型构建相应的模板函数。
演示效果
主函数
int main()
{
head<int> a; // 声明一个int类型的链表
head<int> b; // 这就体现了模板类的方便之处,不需要为每一种数据类型的链表都写一套函数
// 链表赋值符号化
a += 1; // += 表示在链表尾部插入相应的值
a += 2;
a += 3;
b += 4;
b += 5;
b += 6;
// 链表的标准化输出
cout << "a = " << a << endl; // '<<'运算符重载
// 链表访问与读取操作数组化
cout << "a[1] = " << a[1] << endl; // 链表第二个元素读取
a[1] = 10; // 链表第二个元素赋值
cout << "a = "<< a << endl;
// 链表合并符号化
cout << "b = "<< b << endl;
a += b; // 将a链表的表尾接到b的表头上
cout << "a += b => " << a << endl; // 输出转接后的链表a
return 0;
}
终端输出结果
更多内容待后续开发!