单链表的存储结构描述如下
typedef struct Node
{
ElemType data;
struct Node* next;
}Node,*LIninkList;
LinkList和Node同为结构指针类型,这两种类型等价。通常习惯上用LinkList说明指针变量,如,使用LinkList L,则L为单链表头指针,从而提高程序可读性。用Node来定义指向单链表中结点的指针,如Node *p,则p为指向单链表中结点的指针变量。
1.初始化单链表
InitList(LinkList *L)
{
*L=(LinkList)malloc(sizeof(Node));//建立头结点
(*L)->next=NULL;//建立空的单链表L
}
注意:L是指向单链表的头结点的指针,用来接收主程序中待初始化单链表的头指针变量的地址,*L相当于主程序中待初始化单链表的头指针变量。
2.建立单链表
(1).头插法
得到的链表逻辑顺序与输入元素顺序相反
void CreatFromHead(LinkList L)
{
//L是带头结点的空链表头指针
Node *s;
char c;
int flag=1;
while(flag)//输入‘$’时,flag=0,结束
{
c=getchar();
if(c!='$')
{
s=(Node*)malloc(sizeof(Node));
s->data=c;
s->next=L->next; //s指向L指的位置
L->next=s; //L指向s,顺序不能乱,乱了就找不到数据了
}
else flag=0;
}
}
(2).尾插法
将新结点插入到当前单链表的表尾,为此需要增加一个尾指针r,使之指向单链表表尾(方便指向插入的结点)
void CreatFromTail(LinkList L)
{
Node *r,*s;
int flag=1;
r=L;//r初值指向头结点
while(flag)
{
c=getchar();
if(c!='$')
{
s=(Node *)malloc(sizeof(Node));
s->data=c;
r->next=s;
r=s;
}
else
{
flag=0;
r->next=NULL;
}
}
}
3.查找
(1).按序号查找
要查找带头结点的单链表中的第i个元素,需要从头扫描,可设置j为计数器,当j=i时,指针p指向的结点就是要找的第i个结点。
Node* Get(LinkList L,int i)
{
int j;
Node *p;
if(i<=0)
return NULL;
p=L;
j=0;
while((p->next!=NULL)&&(j<i))
{
p=p->next;
j++;
}
if(i==j)
return p;
else
return NULL;
}
(2).按值查找
Node* Locate(LinkList L,ElemType key)
{
Node *p;
p=L->next;
while(p!=NULL)
if(p->data!=key)
p=p->next;
else
break;
return p;
}
4.求单链表长度
int ListLength(LinkList L)
{
Node *p;
p=L->next;
j=0;
while(p!=NULL)
{
p=p->next;
j++;
}
return j;
}
5.单链表插入操作
1.查找(找位置):在单链表中找到第i-1个结点并由指针pre指示。
2.申请:申请新结点s,并将其数据域的值设为e;
3.插入挂链:通过修改指针域将新结点s挂入单链表L。
void InsList(LinkList L,int i,ElemType e)
{
Node *p,*s;
int k;
if(i<=0)
return ERROR;
pre=L;
k=0;
while(pre!=NULL&&k<i-1)
{
pre=pre->next;
k=k+1 //将pre指向第i-1个结点;
}
if(pre==NULL)
{
printf("插入位置不合理");
return ERROR;
}
s=(Node*)malloc(sizeof(Node));
s->data=e;
s->next=pre->next; //指针s指向pre指向的位置
pre->next=s; //pre指向s
return OK;
}
6.单链表的删除操作
1.查找:通过计数方法找到第i-1个结点并由指针pre表示。
2.删除第i个结点并释放空间。
int DelList(LinkList L,int i;ElemType *e)
{
Node *pre,*r;
int k;
pre=L;k=0;
while(pre->next!=NULL&&k<i-1)//查找第i-1个结点
{
pre=pre->next;
k=k+1;
}
if(pre->next==NULL)
{
printf("删除结点位置不合理");
return ERROR;
}
r=pre->next; //r指向第i个结点
pre->next=r->next;//pre指向第i+1个结点
*e=r->data;
free(r);//释放结点空间
return OK;
}
7.合并两个有序单链表
LinkList MregeLinkList(LinkList LA,LinkList LB)
{
Node *pa,*pb;
LinkList LC;//将LC初始置空表,pa和pb分别指向单链表LA,LB中第一个结点,r初值LC
//并且r始终指向LC表尾
pa=LA->next;
pb=LB->next;
LC=LA;//用LA头结点作为LC头结点
LC->next=NULL;
r=LC;
while(pa!=NULL&&pb!=NULL)
{
if(pa->data<=pb->data)
{
r->next=pa;//r指向pa
r=pa;//r移动至pa;
pa=pa->next;//pa移动至下一结点
}
else
{
r->next=pb;
r=pb;
pb=pb->next;
}
}
if(pa)//若LA未完,将LA中后续元素链到新表LC中
r->next=pa;
else
r->next=pb;
free(LB);
return LC;
}