什么是链表?
采用链式存储的线性表称为链表。
链表有哪些分类?
从实现角度分为:动态链表(free,malloc),静态链表
从链接方式分为:单链表,循环链表,双向链表
这里主要学习从链接方式分类学习线性表的链式存储
单链表的定义
用一组地址任意的存储单元来存储线性表中的元素,每个元素信息由数据域和指针域构成(用指针域来表示元素之间的逻辑关系),这两部分构成的存储映像称为结点,由于每个节点的指针域只有一个,故称为单链表。
注意:为了便于对链表进行操作,通常会设置头节点。
单链表上的基本运算基本运算:建表,增删改查
具体操作
(1)插入数据
需求:链表中第 i 个结点之前插入结点e
算法思想:在链表中第 i 个结点之前插入结点需要找到并修改第 i-1 个结点的指针。首先将结点e的指针域指向结点i,再将结点i-1的指针域指向e。
注意:不能先将结点i-1的指针域指向结点e,这样会丢失结点i的存储地址信息。
算法实现:
int InsNode(LinkList L,int i,ElemType e ) //调用函数时,传输数据。在链表L中,第i个元素前插入元素e
{ Node *pre,*s;
pre=Get(L,i-1); //get函数获取获取到结点的 i-1的指针位置,该指针指向i节点的位置
if(!pre)
{ print("不能插入");
return error;
}
s=(Node*)malloc(sizeof(Node)); //将一个结点长度的内存空间,经过malloc转换为指针型,s表示插入元素e的指针
s->date=e; //将e赋值给s的数据域
s->next=pre->next;
pre->next=s;
return ok;
}
(2)建立单链表
头插法建表操作方法:
①首先要建立一个“空表”(头指针)
②输入数据元素an,建立结点并插入;
③输入数据元素an-1,建立结点并插入;
④依次类推,直至输入完a1结束。类似于上面讲的插入数据。
算法实现:
Linklist Createfromhead()
{ Linklist L;
Node *s;
int x;
L=(Linklist)malloc(sizeof(Node)); //初始化链表,创建链表
L->next=Null;
scanf("%d",&x); //输入要插入节点的数据
while(x!=-1) //判断数据类型
{ s=(Node*)malloc(sizeof(Node));
s->date=x;
s->next=L->next;
L->next=s;
scanf("%d",&x); //一次插入后,继续输入数据,循环
}
return L;
}
(3)查找
①按序号查找结点
原理:单链表是一种顺序存取结构, 为找第 i 个数据元素, 必须从头顺序扫描前 i-1 个数据元素,需要计数器 j 与指针 p 协调处理。
算法思想:指针从头节点开始移动(指针位于头结点时J=0),当满足p->next!=null并且此时j
注意:从头节点开始j=0,1,2,3,元素与序号对应,便于处理。
算法实现:
int GetNode(Linklist L,int i)
{ Node *p; int j;
if(i<0)
{ print("查询位置不合法!");
return Null;
}
p=L;
j=0;
while((p->next!=Null)&&(j<i))
{ p=p->next;
j++;
}
if(j==i) //不满足while的第二个条件,跳出循环
return p; //查找到结点
else //不满足while的
return Null;
}
②按值
查找查找其值为key的结点,若找到则返回该结点的指针,否则返回NULL
算法实现:
int Locate(Linklist L,ElemType key)
{ Node *p;
p=L->next; //从第一个结点开始比较
while(p!=Null) //条件成立执行
{ if(p->date!=key)
p=p->next;
else
break; //跳出循环体
}
return p;
}
(4)删除结点
在链表中删除第 i 个结点同样需要找到并修改第 i-1 个结点的指针
int DelNode(Linklist L,int i)
{ Node *p *r;
p=Get(L,i-1);
if(!p||!(p->next)) //p指针位置不存在;i结点指针位置不存在
{ print ("删除位置不合法”);
return error;
}
r=p->next;
p->next=r->next;
free(p); //释放结点i空间
return ok;
}
注意:如果链表只有5个元素,删除第10个元素,则p不存在,位置不合法;删除第6个元素,p指针位置存在,但是p->next不存在,位置不合法,所以两种条件判断删除位置是否合法。
int Length(Linklist L)
{ Node *p;int j;
p=L; j=0;
if(p->next!=Null)
{ j++;
p=p->next;
}
return j;
else
return 0;
}
1.什么是循环链表?
首尾相连的链表,即最后一个结点指针指向头节点或第一个结点。(也叫循环单链表)
已知:两个带头结点的循环单链表LA、LB,编写算法,将LA、LB合并为一个循环单链表,其头指针为LA。
算法思想:设置两循环链表的尾指针; 将第一条链表的尾指针指向第二条链表的第一个结点;将第二条链表的尾指针指向第一条链表的头指针;最后释放第二条链表的头指针,返回LA。
算法实现:
①带头指针的
Linklist Link1(Linklist LA,Linklist LB)
{
Node *p,*q;
p=LA;
q=LB;
while(p>next!=LA) p=p->next; //找到链表的尾指针
while(q->next!=LB) q=q->next;
q->next=LA; // LA=q->next;!!!错误的 LA地址覆盖q下一个指针指向的地址
p->next=LB->next;
free(LB);
return(LA);
}
时间复杂度:O(m+n)
Linklist Link2(Linklist RA,Linklist RB)
{
Node *p;
p=RA->next;
RA->next=RB->next-next;
free(RB->next);
RB->next=p;
return(RB);
}
时间复杂度O(1)