引言
介绍链表之前,先来说一下顺序表,即数组的缺点:
- 顺序表在存储数据时,不易插入和删除数据;
- 顺序表的存储空间利用率和运行效率都不高;
为了解决上述缺点,线性表可以采用另一种存储结构—链式存储结构。
单链表
定义
(链表没特殊说明默认为单链表)链表是通过一组地址任意的存储单元来存储数据元素的存储结构;这些存储单元可以连续,也可以不连续。
1.单链表结点结构
2.头指针
头指针的作用有两个:
1.标识链表,即链表的名字;
2.存储链表中第一个结点的地址;
3.尾指针
尾指针即链表的最后一个结点,没有后继,因此指针域必须置空,即NULL。
单链表的创建
1.头插法创建单链表
创建步骤:
1.建立头节点Head,另其指针域置空;
2.生成新节点p(申请空间失败的话返回Head);
3.读入数据到p的数据域;
4.将结点p插入到Head之后。
5.重复步骤2~4。
图文表示:
代码实现:
返回值是链表的头节点;
LinkList *CreateLink(){
//头插法
LinkList *head,*p;
head=(LinkList *)malloc(sizeof(LinkList));//获得的地址转换为 ListLink *类型
if(head==NULL)return head;
head->next=NULL;
int x;
cin>>x;
while(x!=0){
p=(LinkList *)malloc(sizeof(LinkList));
p->data=x;
p->next=head->next;
head->next=p;
cin>>x;
}
return head;
}
2.尾插法创建单链表
尾插法与头插法类似,只是将p结点连入尾结点之后。
代码实现:
LinkList *CreateLink2(){
//尾插法
LinkList *head,*p,*tail;
head=(LinkList *)malloc(sizeof(LinkList));//每次申请空间时,严谨的做法是判断申请是否成功
if(head==NULL)return head;
head->next=NULL;
tail=head;
int x;
cin>>x;
while(x!=0){
p=(LinkList *)malloc(sizeof(LinkList));
p->data=x;
tail->next=p;
tail=p;
tail->next=NULL;
cin>>x;
}
return head;
}
单链表的基本操作
1.单链表的遍历
链表的遍历就是从头节点开始,依次访问链表中的每一个结点;在遍历过程中也可以设置一个计数器,计算链表的长度。
代码实现:
void Print_Link(LinkList *head){
LinkList *p=head->next;
int num=0; //num为计数器,其结果为链表长度
while(p!=NULL){
cout<<p->data<<endl;
p=p->next;
num+=1;
}
}
2.单链表的查找
查找方式分为两种,一种是根据序号查找;一种是根据值去查找。
根据值查找:
LinkList *GetByNum(LinkList *head,int num){
LinkList *p=head->next;
while(p!=NULL){
if(p->data==num)return p;//找到返回结点指针
p=p->next;
}
return NULL;//找不到返回NULL
}
根据节点查找:
LinkList *GetById(LinkList *head,int i){
int j=0;
if(i<=0)return NULL;//保证序号合法
LinkList *p=head;
while(p->next!=NULL){
p=p->next;
j+=1;//以头节点指向的节点为序号1对应的节点
}
if(i==j)return p;
return NULL;
}
3.单链表的插入
链表插入方式分为两种,一种是后插;一种是前插。
后插:
示意图
代码实现
void InsertAfter(LinkList *p,LinkList *s){
//在p节点之后插入s节点
s->next=p->next;
p->next=s;
}
前插与后插的思想类似:
1.先找出节点p的前驱节点q;
2.对q进行后插;
4.单链表的删除
int Delete_LinkList(LinkList *head,LinkList *p){
//删除指定节点p
LinkList *r;
if(p->next!=NULL){//如果p有后继节点
p->data=p->next->data;
r=p->next;
p->next=r->next;
free(r); //释放空间
return 1;
}
else {//p没有后继节点
r=head;
while(r->next!=p)
r=r->next;
LinkList *q=r->next;
r->next=q->next;
free(q);
}
}
静态链表
与单链表的操作基本一直,只是指针指向下标;用下标作为起到唯一标识作用的“地址”。
struct LinkList{
int data;
int next;
};