单链表是用一组任意的存储单元存放线性表的元素。这组存储单元可以不连续,相对于顺序表需要预留存储空间,链式存储利用内存更加合理。
为了正确的表示元素之间的关系,每个存储单元既要存储数据元素,又要存储后继元素所在的地址信息。这两部分组成了数据元素的存储映像—结点。
结点的定义:
template<typename T>
struct Node{
T data;
Node<T> *next;
}
单链表的基础操作
单链表的初始化
生成只有头结点的单链表,即让头结点的指针域为空。判断单链表是否只有头结点,即判断first->next是否为空。
first=new Node<T>;
first->next=NULL;
单链表的建立
单链表建立有两种方法,头插法和尾插法。
头插法:每次将申请到的结点插在头结点之后,需要改变头结点的指针域与新插入结点的指针域。即将头结点的指针域(NULL)赋值给新结点的指针域,再将新结点的新结点的地址赋值给头结点的指针域。依次进行,直到全部插入。
first=new Node;
first->next=NULL;
for(int i=0;i<n;i++){
Node *s=new Node;
s->data=a[i];
s->next=first->next;
first->next=s;
}
尾插法:每次将新申请的结点插入到终端节点之后,需要增添尾指针,让尾指针初始指向头结点,再将新申请的结点的地址赋值给尾指针,尾指针后移为新申请的结点。重复进行直到插入完成。
first=new Node;
first->next=NULL;
Node *r;
r=first;
for(int i=0;i<n;i++){
Node *s=new Node;
s->data=a[i];
r->next=s;
r=s;
}
r->next=NULL;
单链表的遍历
设置一个工作指针p,让工作指针初始指向首元结点,然后重复执行输出p的指针域,p指针后移,直到p为空。
Node *p;
p=first->next;
while(p){
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
单链表的删除(某一个结点)
设置一个工作指针p,初始化为指向头结点,累加器初始化。查找需要删除的结点的前一个结点并将工作指针p指向该结点。如果p不存在或者p的后继结点不存在,则删除失败;否则,存储要被删除的元素,将p指向结点的下一个结点储存的下一个结点的地址取出赋值给p的指针域,删除待删结点。
Node *p,*q;
p=first;
int count=0;
while(p&&count<i-1){
count++;
p=p->next;
}
if(count==i-1){
q=p->next;
p->next=q->next;
delete q;
}
单链表的销毁
单链表的销毁即从头结点开始依次删除申请的结点,直到全部删除完成。删除方法与单链表中删除某一结点的方法相似。
Node *p=first;
while(first){
first=first->next;
delete p;
p=first;
}
单链表的查找
单链表的查找与顺序表的查找相似,也分为按位查找与按值查找。不同点在于链表的存储空间不一定连续,所以不能执行++操作,需要借用工作指针向下一个移动。
//按位查找
Node *p=first->next;
int count=1;
while(p!=NULL&&count<i)//i为要查找的结点的位置
{
p=p->next;
count++;
}
if(p==NULL) throw"查找位置错误";
else return p->data;
//按值查找
Node *p=first->next;
int count=1;
while(p!=NULL)
{
if(p->data==x) return count;//x为要查找结点的数据元素
p=p->next;
count++;
}