单链表的表示与实现
1、结点结构
2、存储结构
typedef struct LNode
{
ElemType data;//数据域
struct LNode *next; //指针域
}ListNode,*LinkList; //ListNode是链表的结点类型,LinkList是指向链表结点的指针类型
LinkList L; //L被定义为指向单链表的指针类型
ListNode *L;//与上等价
3、单链表上的基本运算
(1)初始化单链表
void InitList(LinkList *L) /* 初始化单链表*/
{
if((*L=(LinkList)malloc(sizeof(ListNode)))==NULL) /* 为头结点分配一个存储空间*/
exit(-1);
(*L)->next=NULL; /* 将单链表的头结点指针域置为空*/
}
void InitList(LinkList &L) /* 初始化单链表*/
{
if((L=(LinkList)malloc(sizeof(ListNode)))==NULL) /* 为头结点分配一个存储空间*/
exit(-1);
L->next=NULL; /* 将单链表的头结点指针域置为空*/
}
(2)单链表判空
int ListEmpty(LinkList L)
/*判断单链表是否为空*/
{
if(L->next==NULL) /*如果链表为空*/
return 1; /*返回1*/
else /*否则*/
return 0; /*返回0*/
}
(3)查找第i个结点
查找单链表中第i个结点。查找成功返回该结点的指针,否则返回NUL
ListNode *Get(LinkList L,int i)
/*查找单链表中第i个结点。查找成功返回该结点的指针,否则返回NUL*/
{
ListNode *p;
int j=0;
p=L;
if(ListEmpty(h)) /*查找第i个元素之前,判断链表是否为空*/
return NULL;
if(i<1) /*判断该序号是否合法*/
return NULL;
while(p->next!=NULL&&j<i)
{
p=p->next;
j++;
}
if(j==i) /*如果找到第i个结点*/
return p; /*返回指针p*/
else; /*否则*/
return NULL ;/*返回NULL*/
}
这是王道书中的代码算法
ListNote *Get(Listlist L,int i)
{
int j=1;//计数,从1开始
LNote *p=L->next;
if(i==0)
return L;
if(i<1)
return NULL;
while(p&&j<i)
{
p=p->next;
j++;
}
return p;
}
(4)查找线性表中元素值为e的元素
查找线性表中元素值为e的元素,查找成功返回对应元素的结点指针,否则返回NULL
ListNode *LocateElem(LinkList L,ElemType e)
/*查找线性表中元素值为e的元素,查找成功返回对应元素的结点指针,否则返回NULL */
{
ListNode *p;
p=L->next; /*指针p指向第一个结点*/
//前两句等价于ListNode *p=L->next;
while(p!=NULL&&p->data!=e)
p=p->next; /*则继续查找*/
return p; /*返回结点的指针*/
}
查找线性表中元素值为e的元素,查找成功返回对应元素的序号,否则返回0
int LocatePos(LinkList L,ElemType e)
/*查找线性表中元素值为e的元素,查找成功返回对应元素的序号,否则返回0*/
{
ListNode *p;
int i=1;
if(ListEmpty(L)) /*查找第i个元素之前,判断链表是否为空*/
return 0;
p=L->next; /*从第一个结点开始查找*/
while(p)//如果p不为空
{
if(p->data==e) /*找到与e相等的元素*/
return i; /*返回该序号*/
else /*否则*/
{
p=p->next; /*继续查找*/
i++;
}
}
if(!p) /*如果没有找到与e相等的元素,返回0,表示失败*/
return 0;
}
(5)第i个位置插入值e的结点
在单链表中第i个位置插入值e的结点。插入成功返回1,失败返回0
int InsertList(LinkList L,int i,ElemType e)
/*在单链表中第i个位置插入值e的结点。插入成功返回1,失败返回0*/
{
ListNode *p,*pre;
int j=0;
//==============这一部分可以调用GET函数=======
pre=L; /*指针p指向头结点*/
while(pre->next!=NULL&&j<i-1)/*找到第i-1个结点,即第i个结点的前驱结点*/
{
pre=pre->next;
j++;
}
if(j!=i-1) /*如果没找到,说明插入位置错误*/
{
printf("插入位置错");
return 0;
}
//===========替换为pre=Get(L,i-1)=========
/*新生成一个结点,并将e赋值给该结点的数据域*/
if((p=(ListNode*)malloc(sizeof(ListNode)))==NULL)
exit(-1);
p->data=e;
/*插入结点操作*/
p->next=pre->next;
pre->next=p;
return 1;
}
(6)删除单链表中的第i个位置的结点
方法一:先检查删除位置的合法性,然后查找第i-1个结点,将前驱结点直接指向后驱结点,再将其删除,时间复杂度为O(n)
int DeleteList(LinkList L,int i,DataType &e)
/*删除单链表中的第i个位置的结点。删除成功返回1,失败返回0*/
{
ListNode *pre,*p;
int j=0;
pre=L;
//==================这一部分可以调用GET函数=======
while(pre->next!=NULL&&pre->next->next!=NULL&&j<i-1)
/*在寻找的过程中确保被删除结点存在*/
{
pre=pre->next;
j++;
}
if(j!=i-1) /*如果没找到要删除的结点位置,说明删除位置错误*/
{
printf("删除位置错误");
return 0;
}
//================================
p=pre->next;
e=p->data;
/*将前驱结点的指针域指向要删除结点的下一个结点,也就是将p指向的结点与单链表断开*/
pre->next=p->next;
free(p); /*释放p指向的结点*/
return 1;
}
方法二:将后继结点q值赋给要删除的结点p,然后删除后继结点
q=p->next;//令q为p后继结点
p->data=p->next->data;//将p替换成后继结点q
p->next=q->next;
free(q);//释放掉后继
(7)求线性表的表长
求表长是不包括头结点的其他结点个数,下面算法是带有头结点的单链表。
int ListLength(LinkList L)
/*求线性表的表长*/
{
ListNode *p;
int count=0;
p=L;
while(p->next!=NULL)
{
p=p->next;
count++;
}
return count;
}
(8)销毁链表
void DestroyList(LinkList L)
/*销毁链表*/
{
ListNode *p,*q;
p=L;//p指向头结点
while(p!=NULL) //第一次循环时
{
q=p;//q指向头结点
p=p->next;//p指向第一个结点
free(q);//释放掉头结点,循此往复
}
}