在此之前,我整理了用顺序表存储线性表的方法,但是顺序表具有以下缺点:
- 列表内容插入和删除非常费劲。需要移动大量元素。
- 表的容量难以确定。因为顺序表中数组的长度需要事先确定,所以难以确定合适的规模。
- 造成存储空间的“碎片”。数组要求连续的存储空间,若不连续则不能使用,造成存储空间的“碎片”现象。
这一次,我们尝试用单链表存储线性表。
有空的话,可以尝试用循环链表和双链表来改善,是个很高级的东西。
一、 单链表的存储方法
通过每个指针的指针域连接线性表的数据元素。
二、单链表的实现
利用结构体类型来描述单链表的结点
template<class T>
struct Node
{
T data; //指针域
Node<T> * next; //数据域
};
将线性表的抽象数据类型定义在单链表存储结构下用C++中的class实现。
template<class T>
class LinkList
{
public:
LinkList();
LinkList(T a[], int n);
~LinkList();
int Length(); //求单链表的长度
T Get(int i); //按位查找,查找第i个结点的元素值
int Locate(T x); //按值查找,查找元素值为x的结点的位置
void Insert(int i, T x); //在第i个位置插入元素值为x的结点
T Delete(int i); //删除第i个结点
void PrintList(); //遍历
private:
Node<T> * first; //单链表的头指针
};
1.构造函数
①无参构造函数
template<class T>
LinkList<T>::LinkList()
{
first = new Node<T>;
first->next = NULL;
}
②有参构造函数
template<class T>
LinkList<T>::LinkList(T a[], int n)
{
first = new Node<T>;
first->next = NULL;
/*
1.头插法建立单链表
for(int i = 0; i < n; i++)
{
Node<T> * s = new Node<T>;
s->data = a[i];
s->next = first->next; //将节点s插到头节点之后
first->next = s;
}
*/
// 2.尾插法建立单链表
Node<T> * r = first; //尾指针初始化
for(int i = 0; i < n; i++)
{
Node<T> * s = new Node<T>;
s->data = a[i];
r->next = s;
r = s;
}
r->next = NULL;
}
2.按位查找算法 Get
template<class T>
T LinkList<T>::Get(int i)
{
//工作指针p和累加器count初始化
Node<T> * p = first->next;
int count = 1;
while(p != NULL && count < i)
{
p = p->next;
count++;
}
if(p == NULL)
throw "位置异常";
else
return p->data;
}
3.按值查找算法 Locate
template<class T>
int LinkList<T>::Locate(T x)
{
Node<T> * p = first->next;
int count = 1; //用来记录光标的位置
while(p != NULL)
{
if(p->data == x)
return count;
p = p->next;
}
return 0; //退出循环表示查找失败
}
4.插入算法
void LinkList<T>::Insert(int i, T x) //在第i个位置插入元素x
{
Node<T> * p = first;
int count = 0;
//找出第i-1个元素
while(p != NULL && count < i - 1)
{
p = p->next; //工作指针p向后移
count++;
}
if(p == NULL)
throw "位置异常";
else
{
Node<T> * s = new Node<T>;
s->data = x;
s->next = p->next;
p->next = s;
}
}
5.删除算法
template<class T>
T LinkList<T>::Delete(int i)
{
Node<T> * p = first;
int count = 0;
while(p != NULL && count < i - 1)
{
p = p->next;
count++;
}
if(p == NULL)
throw "位置异常";
else
{
//暂存被删节点
Node<T> * q = p->next;
int x = q->data;
p->next = q->next;
delete q;
return x;
}
}
7.求链表的长度
int LinkList<T>::Length()
{
//工作指针p和累加器count初始化
Node<T> * p = first->next;
int count = 0;
while(p != NULL)
{
count++;
p = p->next;
}
return count;
}
8.遍历
void LinkList<T>::PrintList()
{
Node<T> * p = first->next;
while(p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
9.析构函数算法
template<class T>
LinkList<T>::~LinkList()
{
Node<T> *q = new Node<T>;
while(first != NULL) //释放单链表的每个结点的存储空间
{
q = first; //暂存被释放结点
first = first->next; //first指向被释放结点的下一个结点
delete q;
}
}
完整代码如下:
#include <iostream>
#define maxSize 100
using namespace std;
template<class T>
struct Node
{
T data; //指针域
Node<T> * next; //数据域
};
template<class T>
class LinkList
{
public:
LinkList();
LinkList(T a[], int n);
~LinkList();
int Length(); //求单链表的长度
T Get(int i); //按位查找,查找第i个结点的元素值
int Locate(T x); //按值查找,查找元素值为x的结点的位置
void Insert(int i, T x); //在第i个位置插入元素值为x的结点
T Delete(int i); //删除第i个结点
void PrintList(); //遍历
private:
Node<T> * first; //单链表的头指针
};
template<class T>
LinkList<T>::LinkList()
{
first = new Node<T>;
first->next = NULL;
}
template<class T>
LinkList<T>::LinkList(T a[], int n)
{
first = new Node<T>;
first->next = NULL;
/*
1.头插法建立单链表
for(int i = 0; i < n; i++)
{
Node<T> * s = new Node<T>;
s->data = a[i];
s->next = first->next; //将节点s插到头节点之后
first->next = s;
}
*/
// 2.尾插法建立单链表
Node<T> * r = first; //尾指针初始化
for(int i = 0; i < n; i++)
{
Node<T> * s = new Node<T>;
s->data = a[i];
r->next = s;
r = s;
}
r->next = NULL;
}
template<class T>
void LinkList<T>::PrintList()
{
Node<T> * p = first->next;
while(p != NULL)
{
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
template<class T>
int LinkList<T>::Length()
{
//工作指针p和累加器count初始化
Node<T> * p = first->next;
int count = 0;
while(p != NULL)
{
count++;
p = p->next;
}
return count;
}
template<class T>
T LinkList<T>::Get(int i)
{
//工作指针p和累加器count初始化
Node<T> * p = first->next;
int count = 1;
while(p != NULL && count < i)
{
p = p->next;
count++;
}
if(p == NULL)
throw "位置异常";
else
return p->data;
}
template<class T>
int LinkList<T>::Locate(T x)
{
Node<T> * p = first->next;
int count = 1; //用来记录光标的位置
while(p != NULL)
{
if(p->data == x)
return count;
p = p->next;
}
return 0; //退出循环表示查找失败
}
template<class T>
void LinkList<T>::Insert(int i, T x) //在第i个位置插入元素x
{
Node<T> * p = first;
int count = 0;
//找出第i-1个元素
while(p != NULL && count < i - 1)
{
p = p->next; //工作指针p向后移
count++;
}
if(p == NULL)
throw "位置异常";
else
{
Node<T> * s = new Node<T>;
s->data = x;
s->next = p->next;
p->next = s;
}
}
template<class T>
T LinkList<T>::Delete(int i)
{
Node<T> * p = first;
int count = 0;
while(p != NULL && count < i - 1)
{
p = p->next;
count++;
}
if(p == NULL)
throw "位置异常";
else
{
//暂存被删节点
Node<T> * q = p->next;
int x = q->data;
p->next = q->next;
delete q;
return x;
}
}
template<class T>
LinkList<T>::~LinkList()
{
Node<T> *q = new Node<T>;
while(first != NULL) //释放单链表的每个结点的存储空间
{
q = first; //暂存被释放结点
first = first->next; //first指向被释放结点的下一个结点
delete q;
}
}
int main()
{
int a[maxSize], i, SearchPos, NewPos, NewItem, DelPos ;
int n = 0;
//创建顺序表
cout << "请输入顺序表长度:" ;
cin >> n ; //输入样本数目(表长)
cout << "请输入表中所有元素:";
for (i = 0 ; i < n; i++)
{
cin >> a[i] ;
}
LinkList<int> linkList(a, n);
cout << "该顺序表为:";
linkList.PrintList(); //显示顺序表
cout << "请输入所查找的元素的位置:" ;
cin >> SearchPos ; //输入查找位置
cout << "该位置的元素为:" << linkList.Get(SearchPos) << endl ; //输出查找的数据元素值
cout << "请输入所插入元素的值:" ;
cin >> NewItem ; //插入位置输入
cout << "请输入所插入的元素的位置:" ;
cin >> NewPos ; //插入元素输入
linkList.Insert(NewPos, NewItem) ; //新数据插入顺序表中
cout << "插入后的顺序表为:" ;
linkList.PrintList(); //插入数据后,输出新的顺序表
cout << "请输入所删除元素的位置:" ;
cin >> DelPos ; //输入删除元素位置
linkList.Delete(DelPos) ; //按位置删除数据
cout << "删除后的顺序表为:" ;
linkList.PrintList();
return 0 ;
}