2.1单链表的建立
1.建立一个带头结点的单链表:L={12,13,21,24}。数据元素的值由键盘输入。
2.实验要点及说明
单链表的建立有头插入法和尾插入法。本实验以尾插法为例建立单链表。单链表的结点结构除了数据域外,只含有一个指针域。注意:头结点的建立方法,新元素的插入的位置及指针的变化。单链表的建立示意图:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define OK 1
#define ERROR -1
#define OVERFLOW 0
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList; // LinkList为结构指针类型
int InitList_L(LinkList *L) //建立一个只含有头结点的空链表
{
*L = (LinkList)malloc(sizeof(LNode));
if(!(*L))
exit(OVERFLOW);
(*L)->next = NULL;
return OK;
}
int TravseList_L(LinkList L) //遍历单链表
{
LinkList p;
p = L->next;
while(p)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
return OK;
}
int CreateList_L(LinkList L,int n) //建立含有n个元素的单链表(尾插法)
{
LinkList p,q;
int i;
printf("Input the datas: ");
q = L; //q指向链表的头结点
for(i=0; i<n; i++)
{
p = (LinkList)malloc(sizeof(LNode)); //申请新结点
scanf("%d",&p->data);
p->next = q->next; //新元素插入表尾
q->next = p; //q指向当前链表尾
q = p;
}
return OK;
}
void main()
{
int n;
LinkList L;
InitList_L(&L);
printf("Input the length of the list L: ");
scanf("%d",&n);
CreateList_L(L,n);
printf("Output the datas: ");
TravseList_L(L);
}
3.思考题
如果采用头插入法,即每次在单链表的首元素位置插入新元素建立单链表,该如何修改上面的程序呢?链表结点的排列有什么变化?
链表的结构排列与输入顺序相反
int CreateList_L(LinkList L,int n)
{
LinkList p,q;
int i;
printf("Input the datas:");
q = L; //q指向链表的头结点
for(i=0;i<n;i++)
{
p = (LinkList)malloc(sizeof(LNode)); //申请新结点
scanf("%d",&p->data);
p->next = q->next;
q->next = p;
}
return OK;
}
2.2单链表的查找
1.从键盘输入n个整数,建立带头结点的单链表。然后查找表中是否存在第i个元素,若存在,返回第i个元素的存储位置(地址),否则返回NULL。
2.实验要点及说明
参考程序中通过调用GetElem_L函数在表中查找第i个结点。其中p控制找到表中下一个结点,直至指向第i个结点或为空(NULL);j控制计数
3.参考代码
#include "LinkList.h" //源代码见实验2.1单链表的建立
LNode* GetElem_L(LinkList L,int i) //查找第i个元素
{
LNode *p;
int j;
p = L;
j = 0;
if(i<=0)
return NULL;
while(p->next != NULL && j<i)
{
p = p->next;
++j;
}
if(i==j) //取第i个元素的地址
return p;
else
return NULL;
}
void main() //单链表查找的主函数
{
int i,n;
LinkList L;
LNode *p;
InitList_L(&L);
printf("Input the length of the list L: ");
scanf("%d",&n);
CreateList_L(L,n);
printf("Input the search location: ");
scanf("%d",&i);
if(p=GetElem_L(L,i))
printf("The data in the %dth location is %d\n",i,p->data);
else
printf("Can't find the right location!\n");
printf("Output the datas: ");
TravseList_L(L);
}
4.思考题
(1)在带头结点的单链表中查找元素x,若找到,返回其存储位置,否则返回NULL,程序代码应该做如何修改
LNode* GetElem_L(LinkList L,int x) //查找元素 x
{
LNode *p;
int j;
p = L;
j = 0;
while(p->next != NULL)
{
p = p->next;
++j;
if(p->data == x) //取第i个元素的地址
return p;
}
return NULL;
}
(2)在值递增有序的带头结点的单链表中,查找大于元素X的最小结点的值。
//4.(2)有序带头结点链表中查找大于x的最小结点的值
LNode* GetElem_2_L(LinkList L,int x)
{
LNode *p;
int j;
p = L;
j = 0;
while(p->next != NULL)
{
p = p->next;
++j;
if(p->data > x) //取第i个元素的地址
return p;
}
return NULL;
}
2.3单链表元素的插入
1.建立一个含有N个元素的带头结点的单链表,然后在表中第i个元素之前插入新元素e
2.实验要求及说明
由单链表的结构特点,要在第i个元素之前插入新元素e,应该先找到第i-1个元素,若指定的i<1或i>表长+1,则出错。程序中通过调用ListInsert_L函数完成查找、插入操作。单链表插入操作示意图如下:
3.参考代码
#include "LinkList.h" //源代码见实验2.1单链表的建立
int CreateList_L(LinkList L) //采用头插法建立单链表
{
LinkList p=L,s;
int flag=1,e;
while(flag)
{
printf("Input the datas and input -1 End: ");
scanf("%d",&e);
if(e!=-1)
{
s = (LinkList)malloc(sizeof(LNode));
s->data=e;
s->next = p->next;
p->next = s;
}
else flag=0;
}
return OK;
}
int ListInsert_L(LinkList L,int i,int e) //在表的第i个元素之前插入新元素e
{
LNode *p,*s;
int j;
p = L;
j = 0;
while(p && j<i-1) //查找表中第i-1个结点
{
p = p->next;
++j;
}
if(!p || j >i-1)
return ERROR;
s = (LinkList)malloc(sizeof(LNode)); //申请新结点S
s->data = e;
s->next = p->next; //插入新结点S
p->next = s;
return OK;
}
void main()
{
int i,e;
LinkList L;
InitList_L(&L);
CreateList_L(L);
TravseList_L(L);
printf("Input the insert location: ");
scanf("%d",&i);
printf("Input the insert data: ");
scanf("%d",&e);
if(ListInsert_L(L,i,e)==1)
{
printf("Output the datas: ");
TravseList_L(L);
}
else
printf("Can't insert the data!\n");
}
4.思考题
(1)如何将新结点e插入到表中x结点之后或者第i个结点之后?程序代码做如何改动?
将ListInsert_L()函数中的while(p &&j<i-1) 改成while(p &&j<i)即可
(2)在有序链表L中,如何使得插入新结点e之后仍保持L的有序性?
//对比e的值再进行插入
//在插入新结点e之后仍保持L的有序性
int ListInsert_2_L(LinkList L,int e)
{
LNode *p,*q,*s;
p = L;
while(p->next != NULL)
{
if(p->data < e)
break;
q = p;
p = p->next;
}
s = (LinkList)malloc(sizeof(LNode)); //申请新结点s
s->data = e;
s->next = q->next; //插入新结点s
q->next = s;
return OK;
}
2.4单链表元素的删除
1.建立一个带头结点的单链表,然后删除表中的第i个元素,并由变量*e返回其值
2.实验要求及说明
算法中需要找到第i个结点的直接前驱结点的地址。调用ListDelete_L函数完成元素的查找、删除操作。函数中设置了两个指针变量p、q。若查找成功,p指向第i-1个结点,q指向第i个结点。单链表元素的删除示意图如下。
3.参考代码
#include "LinkList.h" //源代码见实验2.1单链表的建立
int ListDelete_L(LinkList L,int i,int *e)//若表中存在第i个结点,删除之并由变量*e返回其值
{
LNode *p,*q;
int j;
p = L;
j = 0;
while(p->next && j<i-1)
{
p = p->next;
++j;
}
if(!(p->next)||j>i-1)
return ERROR;
q = p->next; //q指向第i个结点
p->next = q->next; //删除第i个结点
*e = q->data;
free(q);
return OK;
}
void main()
{
int i,n,e;
LinkList L;
InitList_L(&L);
printf("Input the length of the list L: ");
scanf("%d",&n);
CreateList_L(L,n);
TravseList_L(L);
printf("Input the delete location: ");
scanf("%d",&i);
if(ListDelete_L(L,i,&e)==1)
{
printf("Output the datas:");
TravseList_L(L);
}
else
printf("Can't find the delete data!\n");
}
4.思考题
(1)假设单链表里面有数值相同的结点,请问如何删除这些节点呢?或者如何做到只删除其中一个?
//删除所有值为x的结点
int ListDelete_1_L(LinkList L,int x,int *e)
{
LNode *p,*q;
p = L;
while(p->next != NULL)
{
q = p;
p = p->next;
if(p->data == x)
{
q->next = p->next;
*e = q->data;
free(p);
p = q;
}
}
return OK;
}
(2)如何删除表中所有的结点,并释放其所占的存储空间?
//删除表中所有节点
int ListDelete_2_L(LinkList L)
{
printf("delete L...\n");
LNode *p,*q;
p = L;
q = p;
while(p->next != NULL)
{
p = q->next;
q->next = p->next;
free(p);
p = q;
}
free(q);
printf("Successfully deleted list L\n");
}
2.5循环单链表的建立及查找
循环链表可以作为计算机网络的“发送窗口”“接收窗口”。依次来进行流量控制。
1.建立一个带头结点的含n个元素的循环单链表并遍历。若表中存在第i个结点,用变量*e返回其值,否则做出错处理。
2.实验要求及说明
注意循环单链表的尾结点指针域的变换,注意查找元素时循环条件与在非循环单链表中的不同,即要将原来判断指针是否为NULL变为判断指针是否指向头结点。
3.参考代码
// CreateCLinkList.c
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define OK 1
#define ERROR -1
#define OVERFLOW 0
typedef struct LNode
{ // 结点类型定义
int data;
struct LNode *next;
}LNode, *LinkList;
int InitList_CL( LinkList *L ) // 生成只含头结点的空循环单链表
{
*L = (LinkList)malloc(sizeof(LNode));
if(!(*L))
exit(OVERFLOW);
(*L)->next = *L;
return OK;
}
int CreateList_CL( LinkList L, int n )
{ // 按尾插入法建立含n个元素的循环单链表
LNode *p, *q;
int i;
printf ("Input the datas: ");
q = L;
for(i=0; i<n; i++)
{
p = (LNode *)malloc(sizeof(LNode)); // p指向新结点
scanf ("%d",&p->data);
p->next = q->next;
q->next = p;
q = p; // q指向表尾结点
}
return OK;
}
int GetElem_CL( LinkList L, int i, int *e )
{ // 在表中查找第i个元素。若存在,由变量*e带回其值,否则返回ERROR
LNode *p;
int j;
p = L->next;
j = 1;
while( p!=L && j<i )
{
p = p->next;
++j;
}
if ( p==L || j>i ) return ERROR;
*e = p->data;
return OK;
}
int TraverseList_CL( LinkList L )
{ // 遍历循环单链表L
LNode *p;
p = L->next;
while( p!=L )
{
printf ("%d ",p->data);
p = p->next;
}
printf("\n");
return OK;
}
void main()
{
LinkList L;
int i, n, e;
InitList_CL(&L);
printf("Input the Length of the Circle LinkList: ");
scanf ("%d",&n);
CreateList_CL( L, n );
printf("Output the Circle LinkList: ");
TraverseList_CL( L );
printf("Input the search location: ");
scanf ("%d",&i);
if(GetElem_CL(L, i, &e)==1)
printf("The data in %dth location is %d\n",i,e);
else
printf("Can't find the data!\n");
}
4.思考题
(1)如何在循环链表中添加元素和删除元素,可以直观认为就是“扩大窗口”“缩小窗口”,删除第i个元素或者删除值为x的元素?
//删除第i个元素,并返回值
int ListDelete_CL(LinkList L,int i,int *e)
{
LNode *p,*q;
int j;
p = L->next;
j = 1;
while(p != L && j<i-1)
{
p = p->next;
++j;
}
if(!(p->next) || j>i-1)
return ERROR;
q = p->next; //q指向第i个结点
p->next = q->next; //删除第i个节点
*e = q->data;
free(q);
return OK;
}
//删除所有值为x的结点
int ListDelete_1_CL(LinkList L,int x,int *e)
{
LNode *p,*q;
p = L->next;
while(p != L)
{
q = p;
p = p->next;
if(p->data == x)
{
q->next = p->next;
*e = p->data;
free(p);
p = q;
}
}
return OK;
}
(2)如何将两个带头结点的循环单链表LA,LB进行合并成一个循环单链表LA?
int ListMerge_CL(LinkList A,LinkList B)
{
LNode *p,*q,*e;
p = A->next;
q = B->next;
while(p!=A)
{
e = p;
p = p->next;
}
e->next = q;
while(q!=B)
{
e = q;
q = q->next;
}
e->next = A;
free(B);
return OK;
}
void main()
{
LinkList A,B;
int n;
printf("Input the Length of the Circle LinkList LA: ");
scanf ("%d",&n);
InitList_CL(&A);
CreateList_CL(A, n);
printf("Output the Circle LinkList LA: ");
TraverseList_CL(A);
printf("Input the Length of the Circle LinkList LB: ");
scanf ("%d",&n);
InitList_CL(&B);
CreateList_CL(B, n);
printf("Output the Circle LinkList LB: ");
TraverseList_CL(B);
ListMerge_CL(A,B);
printf("Output the Circle LinkList LA: ");
TraverseList_CL(A);
}