单链表的结点存储结构定义如下:
typedef struct Node
{
Datatype data;
struct Node *next;
}LNode,*LinkList;
LNode是结点类型,LinkList指向Lnode类型结点的指针类型,即LinkList等同于LNode*
要完成申请一块LNode类型的存储单元的操作,则需执行如下语句:
p=(LinkList)malloc(sizeof(LNode));
单链表的基本运算实现:
1建立单链表
(1)在链表的头部插入结点建立单链表
#define flag -1
void Create_LinkList1(ListList L)
{
LNode *s;
Datatype x;
scanf("%d",&x);
while(x!=flag){
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
s->next=L->next;
L->next=s;
scanf("%d",&x);
}
}
如果调用函数是main函数,主函数对建立单链表的调用如下:
void main()
{
LinkList L;
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
Create_LinkList1(L);
}
(2)在链表的尾部插入节点建立单链表
尾部插入元素读取数据元素的顺序为顺序
void Create_LinkList2(LinkList L)
{
LNode *r,*s;//s为指向当前插入元素的指针,r为尾指针
DataType x;
scanf("%d",&x);
r=L;
while(x!=flag)
{
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
s->next=r->next;
r=s;
scanf("%d",&x);
}
r->next=NULL;
}
2查找运算
(1)按序号查找
给定序号i查找出单链表第i个元素的结点指针
思路:从链表的第一个元素开始,判断当前结点是否是第i个结点,若是返回该结点的指针,否则下一个,直到链表结束为止。没有第i个节点返回空指针。
LNode *Get_LinkList(LinkList L,int i)
{
LNode *p;
int j;//j是计数器,用来判断当前结点是否是第i结点
p=L;
j=0;
while(p!=NULL&&j<i)
{
p=p->next;//判断当前结点p不是第i个且p非空,则p移向下一个
j++;
}
return p;
}
(2)按值查找
思路:从链表的第一个元素开始,判断当前结点值是否等于x,若是则返回该结点指针,否则继续后一个,直至链表结束。
LNode *Location_LinkList(LinkList L,Datatype x)
{
LNode *p;
p=L->next;
while(p!=NULL&&p->data!=x)
{
p=p->next;
}
return p;
}
3插入算法
(1)插入结点
设p指向单链表中某元素a的结点,s指向待插入的值为x的新节点,将s插入到p结点的后面,插入语句如下:
s->next=p->next;
p->next=s;
(2)单链表的插入运算
将一个值为x的节点插入到单链表的第i个位置,这就要求查找到第i-1个结点指针p,若p存在,在p后面执行插入新节点操作,否则结束
void Insert_LinkList(LinkList L,int i,Datatype x)
//在单链表L中第i个位置插入x结点
{
LNode *p,*s;
p=Get_LinkList(L,i-1);//寻找到第i-1个位置结点
if(p==NULL){
printf("插入位置不合法");
exit(1);
}
else{
s=(LinkList)malloc(sizeof(LNode));
s->data=x;
s->next=p->next;
p->next=s;
}
}
算法时间复杂度为O(n)
4删除运算
(1)删除结点
假设p指向单链表的某一结点,删除p结点的后继结点删除语句如下:
LNode *q=p->next;
p->next=p->next->next;
free(q);
(2)单链表的删除操作
删除单链表第i个位置结点,这就要求查找到第i-1个结点指针p
void Delete_LinkList(LinkList L,int i){
LNode *p,*q;
p=Get_LinkList(L,i-1);
if(p==NULL)
{
printf("删除位置不合法");
exit(1);
}
else{
if(p->next==NULL)
{
printf("删除位置不合法");
exit(1);
}
else{
q=p->next;
p->next=p->next->next;
free(q);
}
}
}
由上面运算,我们得出,在单链表上插入/删除一个结点,必须知道它的前驱结点;单链表不具有按符号随机访问的特点,只能从头指针开始一个个顺序进行。
5求表长运算
int Length_LinkList(LinkList L)
{
int l;
LNode *p;
p=L->next;
l=1;
while(p->next)
{
p=p->next;
i++;
}
return 1;
}
6打印链表
void print(LinkList L){
LNode *p;
p=L->next;
while(p){
printf("%d",p->data);
p=p->next;
}
}
7单链表的倒置
算法思路:依次取原链表的每一个节点,总是将其作为新链表当前的第一个节点插入到心链表中
void reverse(LinkList L){
LNode *p,*q;
p=L->next;
L->next=NULL;
while(p){
q=p;
p=p->next;
q->next=L->next;
L->next=q;
}
}