2013
本篇文章是对用C语言实现单链表的各种操作进行了详细的分析介绍,需要的朋友参考下
最近,从新复习了一下数据结构中比较重要的几个部分,现在把自己的成果记录下来,主要就是仿照严蔚敏的《数据结构》(C 语言版),中的例子和后面的习题进行改编的。首先,是单链表的各种实现,其中,包含了一些常考的知识点。例如,单链表的逆置,单链表的合并,找到单链表的中间节点等的算法实现。
下面这个是单链表的结构体的定义:
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LinkList;
下面的基本的单链表的操作:其中,有一些宏,没有给出他们的一些定义,者可以通过,严蔚敏的《数据结构》(C 语言版),查看得到。
/* 功能:构建一个空的带头节点的单链表*/
Status InitList (struct LNode **L)
{
(*L) = (struct LNode *)malloc(sizeof(struct LNode)); //产生头节点
if(!*L)
exit(OVERFLOW);
(*L)->next = NULL;
return OK;
}
/*销毁线性表*/
Status DestroyList(struct LNode *L)
{
struct LNode *q;
while(L)
{
q = L->next;
free(L);
L = q;
}
return OK;
}
/*将L重置为空表*/
Status ClearList(struct LNode *L)
{
LinkList *p,*q;
p = L->next;
while(p)
{
q = p->next;
free(p);
p = q;
}
L->next = NULL;
return OK;
}
/*判断链表是否为空表*/
Status ListEmpty(LinkList *L)
{
if(L->next)
{
return FALSE;
}
else
{
return TRUE;
}
}
/*返回单链表中元素的个数*/
int ListLength(struct LNode *L)
{
int i=0;
LinkList *p = L->next;
while(p)
{
i++;
p = p->next;
}
return i;
}
/* L为带头节点的单链表的头指针,当第i个元素存在时,其值赋给e,并返回OK */
Status GetElem(struct LNode *L,int i,ElemType *e)
{
int j=1;
LinkList *p = L->next;
while(p && j
{
p = p->next;
j++;
}
if(!p || j>i)
return ERROR;
*e = p->data;
return OK;
}
/*返回L中第一个与e满足关系compare()的数据元素的位序,
若给存在返回值为0,compare()是数据元素的判定函数*/
int LocateElem(struct LNode *L,ElemType e,Status(*compare) (ElemType,ElemType))
{
int i =0;
LinkList *p = L->next;
while(p)
{
i++;
if(compare(p->data,e))
return i;
p=p->next;
}
return 0;
}
/*所cur_e是L中的数据元素,且给就第一个,则用pre_e返回它的前驱*/
Status PriorElem(struct LNode *L,ElemType cur_e,ElemType *pre_e)
{
LinkList *q,*p=L->next;
while(p->next)
{
q = p->next;//q指向p的后继
if(q->data == cur_e)
{
*pre_e = p->data;
return OK;
}
p = q;
}
return INFEASIBLE;
}
/* 若cur_e是L中的数据元素,且不是最后一个,则用next_e返回它的后继*/
Status NextElem(struct LNode *L,ElemType cur_e,ElemType *next_e)
{
LinkList *p;
p = L->next;
while(p->next)
{
if(p->data == cur_e)
{
* next_e = p->next->data;
return OK;
}
p = p->next;
}
return INFEASIBLE;
}
/* 在带头节点的单链表L中的第i个位置之前插入元素e*/
Status ListInsert(struct LNode *L,int i,ElemType e)
{
int j =0;
struct LNode *p=L,*s=NULL;
while(p && j
{
p=p->next;
j++;
}
if(!p || j>i-1)
return ERROR;
s = (struct LNode *)malloc(sizeof(struct LNode));
if(!s)
printf("malloc error~\n");
// p->next = s;
s->data = e;
// p->next = s;
s->next = p->next;
p->next = s;
//s->next = NULL;
// p = s;
return OK;
}
/*在带头节点的单链表中删除第i个元素,并有e返回其值*/
Status ListDelete(LinkList *L,int i,ElemType *e)
{
LinkList *p=L,*q;
int j=0;
while(p->next && j< i-1)
{
p = p->next;
j++;
}
if(!p->next || j>i-1)
return ERROR;
q = p->next;
p->next = q->next;
*e = q->data;
free(q);
return OK;
}
/* 依次对L的每个元素调用vi(),打印输出语句*/
Status ListTraverse(struct LNode *L,void (*vi)(ElemType))
{
LinkList *p = L->next;
while(p)
{
vi(p->data);
p = p->next;
}
printf("\n");
return OK;
}
/* 对单链表进行排序处理*/
struct LNode *sort(struct LNode *head)
{
LinkList *p;
int n,i,j;
int temp;
n = ListLength(head);
if(head == NULL || head->next == NULL)
return head;
p = head->next;
for(j =1;j
{
p = head->next;
for( i =0;i
{
if(p->data > p->next->data)
{
temp = p->data;
p->data = p->next->data;
p->next->data = temp;
}
p = p->next;
}
}
return head;
}
/*对单链表进行逆置*/
LinkList *reverse(LinkList *head)
{
LinkList *p1,*p2 = NULL,*p3 = NULL;
if(head == NULL || head->next == NULL)
return head;
p1 = head->next;
while(p1!=NULL)
{
p3 = p1->next;
p1->next = p2;
p2 = p1;
p1 = p3;
}
head->next = p2;
// head = p2;
return head;
}
Status equal(ElemType c1,ElemType c2)
{
if(c1== c2)
return TRUE;
else
return FALSE;
}
/*将所有在线性表Lb中但不在La中的数据元素插入到La 中*/
void Union(LinkList *La,LinkList *Lb)
{
ElemType *e;
int La_len,Lb_len;
int i;
La_len = ListLength(La);
Lb_len = ListLength(Lb);
for(i=1;i<=Lb_len;i++)
{
GetElem(Lb,i,e); //取Lb中第i个元素赋给e
if(!LocateElem(La,*e,equal))//La中不存在和e相同的元素,则插入
ListInsert(La,++La_len,*e);
}
}
void print(ElemType c)
{
printf("%4d",c);
}
/* 合并两个单链表,La和Lb中的数据是按非递减排列,归并后的Lc还是安非递减排列*/
void MergeList(LinkList *La,LinkList *Lb,LinkList **Lc)
{
int i =1,j=1,k=0;
int La_len,Lb_len;
ElemType *ai,*bj;
ai = (ElemType *)malloc(sizeof(ElemType));
bj = (ElemType *)malloc(sizeof(ElemType));
InitList(Lc);
La_len = ListLength(La);
Lb_len = ListLength(Lb);
while(i<=La_len && j<=Lb_len)
{
GetElem(La,i,ai);
GetElem(Lb,j,bj);
if(*ai
{
ListInsert(*Lc,++k,*ai);
++i;
}
else
{
ListInsert(*Lc,++k,*bj);
++j;
}
}
while(i<=La_len)
{
GetElem(La,i++,ai);
ListInsert(*Lc,++k,*ai);
}
while(j<=Lb_len)
{
GetElem(Lb,j++,bj);
ListInsert(*Lc,++k,*bj);
}
}
/*只遍历一次,找到单链表中的中间节点
1 定义两个指针,一个指针每次移动两个步长(快指针),另一个指针每次移动一个数据(慢指针)
2. 当快指针到达链表尾部的时候,慢指针就到了链表的中间节点
在程序中也可以判断一个单链表是否有环,如果快指针一定能够追赶上慢指针,否则就会以NULL结束*/
LinkList *Searchmid(LinkList * head)
{
if(NULL == head)
return NULL;
if(head->next == NULL)
return head;
if(head->next->next == NULL)
return head;
LinkList *mid= head;
LinkList *p = mid->next;
while((p != NULL) && (NULL !=p->next))
{
mid = mid->next;
p = p->next->next;
}
return mid;
}
下面主要是单链表的一个测试的程序。
Status comp(ElemType c1,ElemType c2)
{
if(c1==c2)
return TRUE;
else
return FALSE;
}
void visit(ElemType c)
{
printf("%4d",c);
}
void main()
{
LinkList *L;
LinkList *mid;
mid = (struct LNode *)malloc(sizeof(struct LNode));
ElemType *e,e0,*e1;
Status i;
int j,k;
e = (ElemType *)malloc(sizeof(ElemType));
e1 = (ElemType *)malloc(sizeof(ElemType));
i = InitList(&L);
for(j=1;j<=6;j++)
{
i = ListInsert(L,1,j);
}
printf("在L的表头依次插入1~6后:L=");
ListTraverse(L,visit);
printf("L中间节点的值为mid=:");
mid = Searchmid(L);
printf("%d\n",mid->data);
printf("L逆置后的输出:L=");
ListTraverse(reverse(L),visit);
printf("L排序后依次为:L=");
ListTraverse(sort(L),visit);
i = ListEmpty(L);
printf("L 是否为空:i=%d(1:是,0:否)\n",i);
i = ClearList(L);
printf("清空L后:L=");
ListTraverse(L,visit);
i = ListEmpty(L);
printf("L是否为空:i=%d\n",i);
for(j=1;j<=10;j++)
{
ListInsert(L,j,j);
}
printf("在L的表尾依次插入1~10后:L=");
ListTraverse(L,visit);
GetElem(L,5,e);
printf("第5个元素的值为:%d\n",*e);
for(j=0;j<=1;j++)
{
k = LocateElem(L,j,comp);
if(k)
printf("第%d个元素的值为%d\n",k,j);
else
printf("没有值为%d的元素\n",j);
}
for(j=1;j<=2;j++)
{
GetElem(L,j,e1);
i = PriorElem(L,*e1,e);
if(i== INFEASIBLE)
printf("元素%d无前驱\n",*e1);
else
printf("元素%d的前驱为:%d\n",*e1,*e);
}
for(j=ListLength(L) -1;j<=ListLength(L);j++)
{
GetElem(L,j,e1);
i = NextElem(L,*e1,e);
if(i==INFEASIBLE)
printf("元素%d无后继\n",*e1);
else
printf("元素%d的后继为:%d\n",*e1,*e);
}
k = ListLength(L);
for(j=k+1;j>=k;j--)
{
i = ListDelete(L,j,e);
if(i==ERROR)
printf("删除第%d个数据失败\n",j);
else
printf("删除的元素为:%d\n",*e);
}
printf("依次输出L的元素:");
ListTraverse(L,visit);
DestroyList(L);
printf("销毁L后:L=%u\n",L);
printf("*************************************************\n");
LinkList *La,*Lb;
i = InitList(&La);
if(i==1)
for(j=1;j<=5;j++)
i= ListInsert(La,j,j);
printf("La=");
ListTraverse(La,print);
InitList(&Lb);
for(j=1;j<=5;j++)
i = ListInsert(Lb,j,2*j);
printf("Lb = ");
ListTraverse(Lb,print);
Union(La,Lb);
printf("new La=");
ListTraverse(La,print);
printf("*************************************************\n");
LinkList *La_1,*Lb_1,*Lc_1;
int a[4]={3,5,8,11},b[7]= {2,6,8,9,11,15,20};
InitList(&La_1);
for(j=1;j<=4;j++)
ListInsert(La_1,j,a[j-1]);
printf("La_1=");
ListTraverse(La_1,print);
InitList(&Lb_1);
for(j=1;j<=7;j++)
ListInsert(Lb_1,j,b[j-1]);
printf("Lb_1=");
ListTraverse(Lb_1,print);
MergeList(La_1,Lb_1,&Lc_1);
printf("Lc_1=");
ListTraverse(Lc_1,print);
}
下面是在Linux下的部分运行结果:
在L的表头依次插入1~6后:L= 6 5 4 3 2 1
L中间节点的值为mid=:4
L逆置后的输出:L= 1 2 3 4 5 6
L排序后依次为:L= 1 2 3 4 5 6
L 是否为空:i=0(1:是,0:否)
清空L后:L=
L是否为空:i=1
在L的表尾依次插入1~10后:L= 1 2 3 4 5 6 7 8 9 10
第5个元素的值为:5
没有值为0的元素
第1个元素的值为1
元素1无前驱
元素2的前驱为:1
元素9的后继为:10
元素10无后继
删除第11个数据失败
删除的元素为:10
依次输出L的元素: 1 2 3 4 5 6 7 8 9
销毁L后:L=7954544
*************************************************
La= 1 2 3 4 5
Lb = 2 4 6 8 10
new La= 1 2 3 4 5 6 8 10
*************************************************
La_1= 3 5 8 11
Lb_1= 2 6 8 9 11 15 20
Lc_1= 2 3 5 6 8 8 9 11 11 15 20