1、头文件
首先创建LinkList.h
头文件,一般类的声明和成员函数的实现都是分文件编写的,但这里用的是模板编程,就放在一个文件夹下了,你可以用inline
内联函数实现。
#pragma once
template<class T>
class LinkNode
{
template<class T>
friend class LinkList; //将链表类声明为友元,以便访问私有属性
public:
LinkNode()
{
next = NULL; //每new一个结点时,将他置空,串进链表才设next
}
protected:
T data;
LinkNode<T>* next;
};
template<class T>
class LinkList
{
public:
LinkList();
~LinkList();
//在第k个位置插入元素x,返回插入后的线性表
LinkList<T>& insert(int k, const T& x);
//判断表是否为空,空返回true
bool isEmpty() const;
//返回表中的元素个数
int getLength() const;
//将表中第k个元素保存到x中,若不存在则返回false
bool getData(int k, T& x);
//将表中第k个元素修改为x,若不存在则返回false
bool modifyData(int k, const T& x);
//返回x在表中的位置,如果不在表里返回0
int find(const T& x);
//按位置删除第k个元素,并把它保存到x中,返回删除后的线性表
LinkList<T>& removebyIndex(const int k, T& x);
//按元素删除查找的元素,并把它保存到y中,返回删除后的线性表
LinkList<T>& removebyValue(const T& x, T& y);
void outPut(ostream& out) const;
protected:
LinkNode<T>* head; //指向链表的头结点指针
};
template<class T>
LinkList<T>::LinkList()
{
//创建空单向链表
head = new LinkNode<T> (); //创建头结点
}
template<class T>
LinkList<T>::~LinkList()
{
T x;
int len = getLength();
for (int i = len; i > 0; i--)
{
removebyIndex(i, x);
}
}
template<class T>
LinkList<T>& LinkList<T>::insert(int k, const T& x)
{
LinkNode<T>* newNode = new LinkNode<T>; //创建待插入的新结点
newNode->data = x; //赋值data
int len = getLength();
if (k<1 || k>len + 1)
{
cout << "元素下标越界,插入失败!" << endl;
return *this;
}
LinkNode<T>* p = head; //找到头结点
for (int i = 1; i < k; i++) //遍历找到插入位置的前驱结点(k-1)位置
{
p = p->next;
}
//核心
newNode->next = p->next;
p->next = newNode;
return *this;
}
template<class T>
bool LinkList<T>::isEmpty() const
{
return head->next == NULL;
}
template<class T>
int LinkList<T>::getLength() const
{
int len = 0;
LinkNode<T>* p = head->next; //从第一个有元素的位置开始遍历
while (p)
{
len++;
p = p->next;
}
return len;
}
template<class T>
bool LinkList<T>::getData(int k, T& x)
{
if (k<0 || k>getLength())
{
cout << "元素下标越界,未找到该位置!" << endl;
return false;
}
LinkNode<T>* p = head ->next; //找到第一个有元素的结点
for (int i = 1; i < k; i++) //遍历找到插入位置的前驱结点(k-1)位置
{
p = p->next;
}
x = p->data; //将p的信息赋值给x
return true;
}
template<class T>
bool LinkList<T>::modifyData(int k, const T& x)
{
if (k<0 || k>getLength())
{
cout << "元素下标越界,未找到该位置!" << endl;
return false;
}
LinkNode<T>* p = head->next; //找到第一个有元素的结点
for (int i = 1; i < k; i++) //遍历找到插入位置的前驱结点(k-1)位置
{
p = p->next;
}
p->data = x; //将p的信息修改为x
return true;
}
template<class T>
int LinkList<T>::find(const T& x)
{
LinkNode<T>* p = head->next; //指向第一个有元素的结点
int index = 0; //记录找到元素的下标
while (p != NULL && p->data != x)
{
p = p->next;
index++;
}
if (p != NULL)
{
return index;
}
else
return 0;
}
template<class T>
LinkList<T>& LinkList<T>::removebyIndex(const int k, T& x)
{
if ( k<1 || k>getLength() + 1 )
{
cout << "元素下标越界,删除失败!" << endl;
}
getData(k, x);
//cout << x << endl; //测试
LinkNode<T>* p = head; //找到头结点
for (int i = 1; i < k; i++) //遍历找到插入位置的前驱结点(k-1)位置
{
p = p->next;
}
LinkNode<T>* pDele = p->next; //临时结点用于记录待删除结点,方便后面释放,第二个用途是直接将p->next指向pDele->next
p->next = pDele->next;
delete pDele;
return *this;
}
template<class T>
LinkList<T>& LinkList<T>::removebyValue(const T& x, T& y)
{
int index = find(x);
if (index != 0)
{
return removebyIndex(index + 1, y);
}
else
{
cout << "没有此元素!" << endl;
return *this;
}
}
//实现顺序表的输出
template<class T>
void LinkList<T>::outPut(ostream& out) const
{
LinkNode<T>* p = head->next;
int len = getLength();
for (int i = 0; i < len; i++)
{
out << p->data << endl;
p = p->next;
}
}
//全局函数
//重载运算符<<
template<class T>
ostream& operator <<(ostream& out, const LinkList<T>& x)
{
x.outPut(out);
return out;
}
2、测试程序
可以看出这与C++源码实现的链表在功能上还是很相像的。
#include<iostream>
using namespace std;
#include"LinkList.h"
int main()
{
LinkList<int> list;
list.insert(1, 10);
list.insert(2, 70);
list.insert(3, 20);
list.insert(2, 1);
list.insert(5, 6);
list.insert(6, 3);
cout << list << endl;
list.modifyData(6, 100);
cout << list << endl;
int i = list.find(100);
cout << i << endl;
int x = 0;
list.removebyIndex(4, x); //这里删除的是第四个位置的数据,不是下标为四的数据
cout << list << endl;
list.removebyValue(70, x);
cout << list << endl;
return 0;
}