目的:通过实际操作单链表,掌握单链表的链式储存结构以及验证单链表及其操作的实现并进一步理解算法与程序的关系。
内容:用头插法建立带头结点的单链表并对已创建的单链表实现插入、删除、查找等基本操作。
特点:手动输入链表的数据、融入模板机制,可以自由选择输入数据的类型(int、char)
单链表类的定义
#include<iostream>
#include<iomanip> //使用了setw()
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); /*建立有n个元素的单链表*/
~LinkList();
void Insert(int i,T x); /*在第i个位置中插入元素值为X的结点*/
int Length(); /*求单链表的长度*/
T Get(int i); /*按位查找,在单链表中查找第i个结点的元素值*/
int Locate(T 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)
{
Node<T>*s;
first=new Node<T>;
first->next=NULL;
for(int i=0;i<n;i++)
{
s=new Node<T>;
s->data=a[i];
s->next=first->next; first->next=s;
}
}
template<class T>
LinkList<T>::~LinkList()
{
Node<T>*t;
while(first!=NULL)
{
t=first;
first=first->next;
delete t;
}
}
//单链表插入算法
template<class T>
void LinkList<T>::Insert(int i,T x)
{
Node<T>*p=first;
Node<T>*s;
int count=0;
while(p!=NULL&&count<i-1)
{
p=p->next;
count++;
}
if(p==NULL) throw "没有找到结点";
else
{
s=new Node<T>;
s->data=x;
s->next=p->next;
p->next=s;
}
}
//求线性表的长度
template<class T>
int LinkList<T>::Length()
{
Node<T>*p=first->next;
int count=0;
while(p!=NULL)
{
p=p->next;
count++;
}
return count;
}
//遍历线性表的数据
template<class T>
void LinkList<T>::PrintList()
{
Node<T>*q=first->next;
while(q!=NULL)
{
cout<<q->data<<endl;
q=q->next;
}
}
//按位查找数据
template<class T>
T LinkList<T>::Get(int i)
{
Node<T>*p=first->next;
int count=0;
if(p!=NULL)
{
while(count<i)
{
if(count==i-1)
{
cout<<'\n'<<p->data<<endl;
}
p=p->next;
count++;
}
}
else
{
return 0;
}
}
//按值查找数剧
template<class T>
int LinkList<T>::Locate(T x)
{
Node<T>*p=first->next;
int count;
for(count=1;p!=NULL;count++)
{
if(p->data==x)
{
return count;
}
p=p->next;
}
return 0;
}
//删除链表中第i个结点
template<class T>
T LinkList<T>::Delete(int i)
{
Node<T>*p=first;
int count=0;
if(p!=NULL)
{
while(count<i)
{
if(count==i-1)
{
Node<T>*q=p->next;
T x=q->data; //暂存被删除的结点
p->next=q->next;
delete q;
return x;
}
p=p->next;
count++;
}
}
else
{
throw "位置";
return 0;
}
}
主函数代码
int main()
{
int n;int w;
cout<<'\n'<<"请选择您要输入的数据类型:"<<endl;
cout<<"1.int类型"<<'\t'<<"2.char类型"<<'\n'<<endl;
cin>>w;
switch(w)
{
case 1:
{
int a[100];int i;
cout<<"请输入数组的大小"<<endl;
cin>>n;
cout<<"请输入数组元素:"<<endl; //头插法插入数据
for(i=0;i<n;i++)
{
cin>>a[i];
}
LinkList<int>one(a,n); //带参构造函数
cout<<'\n'<<"线性表的长"<<one.Length()<<endl;
cout<<'\n'<<"线性表中的内容:"<<endl;
one.PrintList(); //输出线性表的数据
//按位查找
int s;
cout<<'\n'<<"请输入要查找数据的序号:";
cin>>s;
cout<<'\n'<<"您所查询的数据以及所在的序号为:";
cout<<one.Get(s)<<endl;
//按值查找
int x;
cout<<'\n'<<"请输入要查找的数据:";
cin>>x;
cout<<"你所查找的值所在的位置为:"<<one.Locate(x)<<endl;
//按序号删除数据
int k;
cout<<'\n'<<"请输入需要删除的数据序号:";
cin>>k;
cout<<"删除成功!你所删除的数据为:"<<one.Delete(k)<<endl;
cout<<'\n'<<"线性表的内容为:"<<endl;
one.PrintList(); //输出线性表的数据
}
break;
case 2:
{
char a[100];int i;
cout<<"请输入数组的大小"<<endl;
cin>>n;
cout<<"请输入数组元素:"<<endl; //头插法插入数据
for(i=0;i<n;i++)
{
cin>>a[i];
}
LinkList<char>one(a,n); //带参构造函数
cout<<'\n'<<"线性表的长"<<one.Length()<<endl;
cout<<'\n'<<"线性表中的内容:"<<endl;
one.PrintList(); //输出线性表的数据
//按位查找
int s;
cout<<'\n'<<"请输入要查找数据的序号:";
cin>>s;
cout<<"您所查询的数据为:";
cout<<one.Get(s)<<endl;
//按值查找
char x;
cout<<"请输入要查找的数据:";
cin>>x;
cout<<one.Locate(x)<<endl;
//按序号删除数据
int k;
cout<<'\n'<<"请输入需要删除的数据序号:";
cin>>k;
cout<<"删除成功!你所删除的数据为:"<<one.Delete(k)<<endl;
cout<<'\n'<<"线性表的内容为:"<<endl;
one.PrintList(); //输出线性表的数据
}
break;
}
return 0;
}
输入数据为int类型时的输出结果
输入数据为char类型时的输出结果
心得:
1.单链表中,头指针指向第一个元素所在的结点,具有标识单链表的作用,在使用头插法时不需要移动头结点。
2.在单链表上实现插入和删除操作,无需移动结点,在工作指针指向合适的位置后,仅需修改结点之间的链接关系。
3.值得注意的是数组储存的下标是从0开始,而查询时的序号是从1开始,所以要注意查询的判断条件。