C语言描述:单向链表的相关操作


#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode
{
	ElemType data;//有效数据域 
	struct LNode *next;//下一个结点的地址 
}LNode;
typedef LNode* LinkList;//引用链表的参数是头指针,所以把结点型地址命名为LinkList 
//建立空表:为头结点分配内存,头结点的地址域为空 
void InitList(LinkList *L)
{
	*L = (LNode*)malloc(sizeof(LNode));//为头结点分配内存,地址返回链表的头指针 
	if(*L==NULL)    exit(-1);//动态分配内存必须检测返回地址判断是否成功分配 
	(*L)->next = NULL;//头结点地址域为NULL 
}
//销毁单向链表:free(头结点和表头到表尾的所有结点的地址)  
void DestroyList(LinkList *L)
{
	LNode* p;
	while(*L)
	{
		p = (*L)->next;
		free(*L);//free(p):释放p指向的内存,归还给操作做系统。
		*L = p;  //p变量仍存在,仍旧指向已经恢复自由的原先内存,一般还需要让p=NULL 
	}
}
//清空单链表:free(表头和表尾的所有结点,保留头结点并使其地址域为NULL) 
void ClearList(LinkList *L)
{
	LNode*q,*p = (*L)->next;//指向表头,而不是头结点 
	while(p)
	{
		q = p;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
}
//判断单项链表是否为空 
bool EmptyList(LinkList L)
{
	return L->next?false:true;
}
//返回单向链表的长度 
int LengthList(LinkList L)
{
	LNode* p = L->next;
	int i = 0;//计数器 
	while(p)//数据流 
	{
		i++;
		p = p->next;
	}
	return i;
}
//得到链表某个位置的结点值 
bool GetElem(LinkList L,int i,ElemType* e)
{//1<=i<=length 
	if(i<1)
	{
		printf("i的值不合理!\n");
		return false;
	}
	int j = 0;
	LNode* p = p->next;
	while(p&&j<i-1)//检测i是否>length 
	{
		p = p->next;
		j++;
	}
	if(!p)//pls+1状态是每个循环结束后的最终状态值 
	{
		printf("i的值不合理!\n");
		return false;
	}
	*e = p->data;
	return true; 
}
//在第i个位置前插入新结点:i<=i<=length+1 
bool InsertList(LinkList L,int i,ElemType e)
{//寻找第i-1个结点,满足0<=i-1<=length,i的值自然合理 
	if(i-1<0)
	{
		printf("i的值不合理!\n");
		return false;
	}
	LNode*p = L;//指向头结点 
	int j = 0;
	while(p&&j<i-1)//有两种理解方式:数据流,流下一个计数一次,流i-1次停止 
	{             //p切换指i-1次,直到p指向最后一个结点后停止
		p = p->next; 
		j++;
	}
	if(!p)
	{
		printf("i的值不合理!\n");
		return false;
	}//p指向第i-1个结点 
	LNode* q;
	q = (LNode*)malloc(sizeof(LNode));//构建要插入的新结点 
	q->data = e;
	q->next = p->next;//新节点保存第i个的地址 
	p->next = q;//第i-1个结点保存新结点的地址 
	return true; 
} 
//删除某个位置的结点:1<=i<=length 
bool DeleteList(LinkList L,int i,ElemType *e)
{//寻找第i-1个结点 0<=i<=length-1 
	if(i-1<0)
	{
		printf("i的值不合理!\n");
		return false;
	}
	LNode* p = L;
	int j = 0;
	while(p&&j<i-1)
	{
		p = p->next;
		j++;
	}
	if(!p||p->next==NULL)//pls+1或指向最后一个结点说明i值不合理 
	{
		printf("i的值不合理!\n");
		return false;
	}
	p->next = p->next->next;
	return true;
	
}
int LocateList(LinkList L,ElemType e)
{
    int i = 1;
	LNode*p = L->next;
	while(p)//数据流 
	{
		if(p->data==e)
		return i;
		p = p->next;//满足切换下一个数据的要求,如果p=p->next->next,是跳跃切换 
		i++;
	}
	if(!p)
	return 0;
}
void TraverseList(LinkList L)
{
	LNode* p = L->next;
	while(p)
	{
		printf("%d  ",p->data);
		p = p->next;
	}
	printf("\n");
}
// 输入n个元素的值,依次插在表头,建立带头结点结构的单向链表L 
 void CreateList(LinkList *L,int n) 
 { 
   int i;
   LinkList p;
   *L=(LinkList)malloc(sizeof(struct LNode));
   (*L)->next=NULL; //为头结点分配内存 
   printf("请输入%d个数据\n",n);
   for(i=n;i>0;--i)
   {
     p=(LinkList)malloc(sizeof(struct LNode)); 
     scanf("%d",&p->data); 
     p->next=(*L)->next; 
     (*L)->next=p;
   }
 }
//输入n个元素的值,依次插在表尾,建立带表头结构的单链线性表 
 void CreateList2(LinkList *L,int n)
 { 
   int i;
   LinkList p,q;
   *L=(LinkList)malloc(sizeof(struct LNode)); // 生成头结点 
   (*L)->next=NULL;
   q=*L;//q指向表尾 
   printf("请输入%d个数据\n",n);
   for(i=1;i<=n;i++)
   {
     p=(LinkList)malloc(sizeof(struct LNode));
     scanf("%d",&p->data);
     q->next=p;
     q=q->next;//q始终指向表尾 
   }
   p->next=NULL;
 }
 //已知单向链表La和Lb的元素按值非递减排列。
 //归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列 
void MergeList(LinkList La,LinkList *Lb,LinkList *Lc)
 { 
   LinkList pa=La->next,pb=(*Lb)->next,pc;
   *Lc=pc=La; 
   while(pa&&pb)
     if(pa->data<=pb->data)
     {
       pc->next=pa;
       pc=pa;
       pa=pa->next;
     }
     else
     {
       pc->next=pb;
       pc=pb;
       pb=pb->next;
     }
   pc->next=pa?pa:pb; 
   free(*Lb); 
   Lb=NULL;
 }
 /********************************************************************
 int main()//测试MergeList
 {
   int n=5;
   LinkList La,Lb,Lc;
   printf("按非递减顺序, ");
   CreateList2(&La,n); // 正位序输入n个元素的值 
   printf("La="); 
   TraverseList(La);
   printf("按非递增顺序, ");
   CreateList(&Lb,n); 
   printf("Lb="); 
   TraverseList(Lb);
   MergeList(La,&Lb,&Lc); 
   printf("Lc="); 
   TraverseList(Lc);
   return 0;
 }
 ************************************************************/
int main()
{
	LinkList L;
	ElemType e;
	InitList(&L);
	int i;
	for(i=1;i<5;i++)
	{
		InsertList(L,i,i);	
	}
	printf("遍历单向链表\n");
	TraverseList(L);
	printf("在第5个位置插入11\n");
	InsertList(L,5,11);
	printf("遍历单向链表\n");
	TraverseList(L);
	printf("在第7个位置插入100\n");
	InsertList(L,7,100);
	printf("遍历单向链表\n");
	TraverseList(L);
	printf("删除第6个位置结点\n");
	DeleteList(L,6,&e);
	printf("遍历单向链表\n");
	TraverseList(L);
	printf("删除第0个位置结点\n");
	DeleteList(L,0,&e);
	printf("遍历单向链表\n");
	TraverseList(L);
	DeleteList(L,5,&e);
	printf("遍历单向链表\n");
	TraverseList(L);
}

先找到课本,熟悉单向链表的结构;         关键词: 头结点,头指针,表头,表尾,数据域,地址域(指针域)
1,生成空表销毁链表               2,清空链表                 3,是否为空表               4,表长                  5,查找第i个结点的值
6,查找第一个等于e的结点在链表的位置                      7,插入                         8,删除                    9,遍历                             10,正序插入结点到单链表                               11,逆序插入结点到单链表                   12,将两个有序链表合并成一个有序链表
13,测试10,11,12的MAIN函数                  14,测试1-9的MAIN函数

练习题   (1)合并La,Lb,去掉重复结点
             (2)排序单向链表
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct LNode
{
	ElemType data;//有效数据域 
	struct LNode *next;//下一个结点的地址 
}LNode;
typedef LNode* LinkList;//引用链表的参数是头指针,所以把结点型地址命名为LinkList 
//建立空表:为头结点分配内存,头结点的地址域为空 
void InitList(LinkList *L)
{
	*L = (LNode*)malloc(sizeof(LNode));//为头结点分配内存,地址返回链表的头指针 
	if(*L==NULL)    exit(-1);//动态分配内存必须检测返回地址判断是否成功分配 
	(*L)->next = NULL;//头结点地址域为NULL 
}
//销毁单向链表:free(头结点和表头到表尾的所有结点的地址)  
void DestroyList(LinkList *L)
{
	LNode* p;
	while(*L)
	{
		p = (*L)->next;
		free(*L);//free(p):释放p指向的内存,归还给操作做系统。
		*L = p;  //p变量仍存在,仍旧指向已经恢复自由的原先内存,一般还需要让p=NULL 
	}
}
//清空单链表:free(表头和表尾的所有结点,保留头结点并使其地址域为NULL) 
void ClearList(LinkList *L)
{
	LNode*q,*p = (*L)->next;//指向表头,而不是头结点 
	while(p)
	{
		q = p;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
}
//判断单项链表是否为空 
bool EmptyList(LinkList L)
{
	return L->next?false:true;
}
//返回单向链表的长度 
int LengthList(LinkList L)
{
	LNode* p = L->next;
	int i = 0;//计数器 
	while(p)//数据流 
	{
		i++;
		p = p->next;
	}
	return i;
}
//得到链表某个位置的结点值 
bool GetElem(LinkList L,int i,ElemType* e)
{//1<=i<=length 
	if(i<1)
	{
		printf("i的值不合理!\n");
		return false;
	}
	int j = 0;
	LNode* p = p->next;
	while(p&&j<i-1)//检测i是否>length 
	{
		p = p->next;
		j++;
	}
	if(!p)//pls+1状态是每个循环结束后的最终状态值 
	{
		printf("i的值不合理!\n");
		return false;
	}
	*e = p->data;
	return true; 
}
//在第i个位置前插入新结点:i<=i<=length+1 
bool InsertList(LinkList L,int i,ElemType e)
{//寻找第i-1个结点,满足0<=i-1<=length,i的值自然合理 
	if(i-1<0)
	{
		printf("i的值不合理!\n");
		return false;
	}
	LNode*p = L;//指向头结点 
	int j = 0;
	while(p&&j<i-1)//有两种理解方式:数据流,流下一个计数一次,流i-1次停止 
	{             //p切换指i-1次,直到p指向最后一个结点后停止
		p = p->next; 
		j++;
	}
	if(!p)
	{
		printf("i的值不合理!\n");
		return false;
	}//p指向第i-1个结点 
	LNode* q;
	q = (LNode*)malloc(sizeof(LNode));//构建要插入的新结点 
	q->data = e;
	q->next = p->next;//新节点保存第i个的地址 
	p->next = q;//第i-1个结点保存新结点的地址 
	return true; 
} 
//删除某个位置的结点:1<=i<=length 
bool DeleteList(LinkList L,int i,ElemType *e)
{//寻找第i-1个结点 0<=i<=length-1 
	if(i-1<0)
	{
		printf("i的值不合理!\n");
		return false;
	}
	LNode* p = L;
	int j = 0;
	while(p&&j<i-1)
	{
		p = p->next;
		j++;
	}
	if(!p||p->next==NULL)//pls+1或指向最后一个结点说明i值不合理 
	{
		printf("i的值不合理!\n");
		return false;
	}
	p->next = p->next->next;
	return true;
	
}
int LocateList(LinkList L,ElemType e)
{
    int i = 1;
	LNode*p = L->next;
	while(p)//数据流 
	{
		if(p->data==e)
		return i;
		p = p->next;//满足切换下一个数据的要求,如果p=p->next->next,是跳跃切换 
		i++;
	}
	if(!p)
	return 0;
}
void TraverseList(LinkList L)
{
	LNode* p = L->next;
	while(p)
	{
		printf("%d  ",p->data);
		p = p->next;
	}
	printf("\n");
}
// 输入n个元素的值,依次插在表头,建立带头结点结构的单向链表L 
 void CreateList(LinkList *L,int n) 
 { 
   int i;
   LinkList p;
   *L=(LinkList)malloc(sizeof(struct LNode));
   (*L)->next=NULL; //为头结点分配内存 
   printf("请输入%d个数据\n",n);
   for(i=n;i>0;--i)
   {
     p=(LinkList)malloc(sizeof(struct LNode)); 
     scanf("%d",&p->data); 
     p->next=(*L)->next; 
     (*L)->next=p;
   }
 }
//输入n个元素的值,依次插在表尾,建立带表头结构的单链线性表 
 void CreateList2(LinkList *L,int n)
 { 
   int i;
   LinkList p,q;
   *L=(LinkList)malloc(sizeof(struct LNode)); // 生成头结点 
   (*L)->next=NULL;
   q=*L;//q指向表尾 
   printf("请输入%d个数据\n",n);
   for(i=1;i<=n;i++)
   {
     p=(LinkList)malloc(sizeof(struct LNode));
     scanf("%d",&p->data);
     q->next=p;
     q=q->next;//q始终指向表尾 
   }
   p->next=NULL;
 }
 //已知单向链表La和Lb的元素按值非递减排列。
 //归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列 
void MergeList(LinkList La,LinkList *Lb,LinkList *Lc)
 { 
   LinkList pa=La->next,pb=(*Lb)->next,pc;
   *Lc=pc=La; 
   while(pa&&pb)
     if(pa->data<=pb->data)
     {
       pc->next=pa;
       pc=pa;
       pa=pa->next;
     }
     else
     {
       pc->next=pb;
       pc=pb;
       pb=pb->next;
     }
   pc->next=pa?pa:pb; 
   free(*Lb); 
   Lb=NULL;
 }
 /********************************************************************
 int main()//测试MergeList
 {
   int n=5;
   LinkList La,Lb,Lc;
   printf("按非递减顺序, ");
   CreateList2(&La,n); // 正位序输入n个元素的值 
   printf("La="); 
   TraverseList(La);
   printf("按非递增顺序, ");
   CreateList(&Lb,n); 
   printf("Lb="); 
   TraverseList(Lb);
   MergeList(La,&Lb,&Lc); 
   printf("Lc="); 
   TraverseList(Lc);
   return 0;
 }
 ************************************************************/
int main()
{
	LinkList L;
	ElemType e;
	InitList(&L);
	int i;
	for(i=1;i<5;i++)
	{
		InsertList(L,i,i);	
	}
	printf("遍历单向链表\n");
	TraverseList(L);
	printf("在第5个位置插入11\n");
	InsertList(L,5,11);
	printf("遍历单向链表\n");
	TraverseList(L);
	printf("在第7个位置插入100\n");
	InsertList(L,7,100);
	printf("遍历单向链表\n");
	TraverseList(L);
	printf("删除第6个位置结点\n");
	DeleteList(L,6,&e);
	printf("遍历单向链表\n");
	TraverseList(L);
	printf("删除第0个位置结点\n");
	DeleteList(L,0,&e);
	printf("遍历单向链表\n");
	TraverseList(L);
	DeleteList(L,5,&e);
	printf("遍历单向链表\n");
	TraverseList(L);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值