【数据结构】单链表的c语言实现

单链表的c语言实现

链表是通过一组任意的存储单元来存储线性表中的数据元素,这些存储单元可以是连续的也可以是不连续的。为了建立起数据元素之间的关系,对于每个数据元素除了存放数据元素自身的信息外,还必须有包含的指示该元素直接后继元素存储位置的信息,这两部分信息组成一个结点,即每个结点都有至少包括两个域,一个域存储数据元素信息,称为数据域,另一个域存储直接后继的地址,称为指针域。

开始程序之前,先简单了解一下单链表中的一些基本概念

  • 头结点:在开始结点之前的结点(可有可无),其值域不包含任何信息,也可以包含链表长度等信息。
  • 开始结点:第一个元素所在的结点。
  • 头指针:永远指向链表中第一个结点的位置,如果链表有头结点,头指针指向头结点;否则,头指针指向开始结点,即第一个节点。
  • 带有头节点单链表头指针head指向头结点。头指针head始终不等于NULL,head->next等于NULL的时候链表为空。
  • 不带头结点的单链表头指针head指向开始结点,当head等于NULL时链表为空。
  • 头结点和头指针的区别:头指针是一个指针,头指针指向链表的第一个结点(如果链表有头结点,头指针指向头结点;否则,头指针指向开始结点);头结点是一个实际存在的点,它包含有数据域和指针域。头指针什么时候都应该存在,而头节点可有可无。

定义单链表结构体

typedef struct Node								//定义一个结构体
{
	elemtype data;
	struct Node *next;
}Node;
typedef struct Node *LinkList;

初始化单链表操作

int InitList(LinkList *L)							//带有头节点的单链表的初始化
{
	(*L) = (LinkList)malloc(sizeof(Node));				//开辟空间
	if (!L)
	{
		printf("分配内存失败!\n");
		exit(0);
	}
	(*L)->next = NULL;									//使头节点next为NULL,即表示空链表
	return 0;
}

头插法创建单链表

void CreateListHead(LinkList *L)			//头插法创建一个单链表
{
	int i, n;
	LinkList p;										//声明一个指针p
	(*L) = (LinkList)malloc(sizeof(Node));			
	(*L)->next = NULL;								//先建立一个带头节点的空链表
	printf("请输入您要插入元素的个数:");
	scanf("%d", &n);
	printf("请输入你要插入的元素值(用空格隔开):");
	for (i = 0; i < n; i++)								
	{
		p = (LinkList)malloc(sizeof(Node));					//生成新节点
		scanf("%d", &p->data);							
		p->next = (*L)->next;							
		(*L)->next = p;										//插入到表头
	}
}

头插法算法思路

  1. 声明一指针p和计数器变量i及要输入元素的个数n
  2. 初始化一空链表L
  3. 让L的头节点的指针指向NULL,即建立一个带头节点的单链表
  4. 输入要插入元素的个数及各元素值
  5. 循环
    • 生成一个新节点赋值给p
    • 输入元素值p->data
    • 将p插入到头节点和前一新节点之间

尾插法创建单链表

void CreateListTail(LinkList *L)			//尾插法创建一个单链表
{
	int i, n;
	LinkList p,r;							
	(*L) = (LinkList)malloc(sizeof(Node));
	r = *L;											//r为指向尾部的节点的指针
	printf("请输入您要插入元素的个数:");
	scanf("%d", &n);
	printf("请输入你要插入的元素值(用空格隔开):");
	for (i = 0; i < n; i++)
	{
		p = (LinkList)malloc(sizeof(Node));				//生成新节点
		scanf("%d", &p->data);
		r->next = p;									//将表尾终端节点的指针指向新节点
		r = p;											//将当前的新节点定义为表尾终端节点
	}
	r->next = NULL;										//表示单链表结束
}

尾插法和头插法大同小异,只是头插法使倒序排列,尾插法是正序排列,尾插法也符合我们正常的先来后到的思维

计算单链表的长度

int LengthList(LinkList *L)					//计算链表长度
{
	int length = 0;							//计算链表长度
	LinkList p;
	p = (*L)->next;						//使p指向链表的第一个节点
	while (p)							
	{
		length++;						
		p = p->next;
	}
	return length;					//返回链表长度
}

获取单链表中元素

int GetElem(LinkList L, int i, elemtype *e)			//用e返回L中第i个元素值
{
	int j = 1;
	LinkList p;
	p = L->next;							//使p指向链表的第一个节点
	while (p && j < i)						//p不为NULL并且j < i 时循环
	{
		p = p->next;
		++j;
	}
	if (!p || j > i)
	{
		printf("查询不到该元素!\n");
		return 0;
	}
	*e = p->data;							//将查到的数据用e返回
	return 0;
}

获得链表第i个数据的算法思路:

  1. 声明一个指针p指向链表中第一个节点,初始化j从1开始
  2. 当 j < i 时,就遍历链表,让p的指针向后移动,不断指向下一节点,j累加1
  3. 当到链表尾p为空,则说明第i个节点不存在
  4. 否则查找成功,返回节点p的数据

新元素插入单链表

int InsertList(LinkList *L, int i, elemtype e)			//在L中第i个位置插入元素e
{
	LinkList p, s;
	int j = 1;
	p = *L;									//使p指向头节点
	while (p && j < i)
	{
		p = p->next;
		++j;
	}
	if (!p || j > i)
	{
		printf("插入元素失败!\n");
		return 0;
	}
	s = (LinkList)malloc(sizeof(Node));
	s->data = e;
	s->next = p->next;							//将p的后继节点赋值给s的后继
	p->next = s;								//将s赋值给p的后继
	return 0;
}

单链表第i个数据插入节点的算法思路

  1. 声明一指针p指向链表头节点,初始化j从1开始
  2. 当 j < i 时,就遍历链表,让p的指针向后移动,不断指向下一节点,j 累加1
  3. 若到链表末尾p为空,则说明第i个节点不存在
  4. 否则查找成功,在系统中生成一个空节点s
  5. 将数据元素e赋值给s->data
  6. 单链表的插入标准语句s->next=p->next;p->next = s
  7. 返回0

删除链表中某元素

int DeleteList(LinkList *L, int i, elemtype *e)				//删除L中第i个元素,并用e返回其值
{
	LinkList p, q;
	int j = 1;
	p = *L;
	while (p->next && j < i)						//遍历寻找第i - 1 个节点
	{
		p = p->next;
		++j;
	}
	if (!(p->next) || j > i)
	{
		printf("删除元素失败!\n");
		return 0;
	}
	q = p->next;
	p->next = q->next;								//将q的后继赋值给p的后继
	*e = q->data;									//将q节点中的数据给e*
	free(q);										//释放q节点
	return 0;
}

单链表第i个数据删除节点的算法思路:

  1. 声明一指针p指向链表头节点,初始化j从1开始
  2. 当 j < 1 时,就遍历链表,让p的指针向后移动,不断指向下一个节点,j 累加1
  3. 若到链表末尾p为空,则说明第i个节点不存在
  4. 否则查找成功,将要删除的节点p->next赋值给q
  5. 单链表的删除标准语句p->next = q->next;
  6. 将q节点中的数据赋值给e,作为返回
  7. 释放q节点
  8. 返回0

单链表的整表删除

int ClearList(LinkList *L)					//单链表的整表删除
{
	LinkList p, q;
	p = (*L)->next;
	while (p)		
	{
		q = p->next;					
		free(p);							//循环,逐个释放各个节点
		p = q;
	}
	(*L)->next = NULL;					//将头节点的next置空
	return 0;
}

打印出整个单链表

void ShowList(LinkList *L)					//打印整个链表
{
	LinkList p;
	p = (*L)->next;
	if (p == NULL)
	{
		printf("这是一个空链表!\n");
	}
	printf("单链表");
	while (p)
	{
		printf(" -> %d", p->data);
		p = p->next;
	}
	printf("\n");
}

到此,单链表的基本操作已经完成,下面附上源码

源码:

#include<stdio.h>
#include<stdlib.h>
typedef int elemtype;
typedef struct Node								//定义一个结构体
{
	elemtype data;
	struct Node *next;
}Node;
typedef struct Node *LinkList;

int InitList(LinkList *L)							//带有头节点的单链表的初始化
{
	(*L) = (LinkList)malloc(sizeof(Node));
	if (!L)
	{
		printf("分配内存失败!\n");
		exit(0);
	}
	(*L)->next = NULL;
	return 0;
}

void CreateListHead(LinkList *L)			//头插法创建一个单链表,n为要插入的元素个数
{
	int i, n;
	LinkList p;
	(*L) = (LinkList)malloc(sizeof(Node));
	(*L)->next = NULL;
	printf("请输入您要插入元素的个数:");
	scanf("%d", &n);
	printf("请输入你要插入的元素值(用空格隔开):");
	for (i = 0; i < n; i++)
	{
		p = (LinkList)malloc(sizeof(Node));
		scanf("%d", &p->data);
		p->next = (*L)->next;
		(*L)->next = p;
	}
}

void CreateListTail(LinkList *L)			//尾插法创建一个单链表,n为要插入的元素个数
{
	int i, n;
	LinkList p,r;
	(*L) = (LinkList)malloc(sizeof(Node));
	r = *L;
	printf("请输入您要插入元素的个数:");
	scanf("%d", &n);
	printf("请输入你要插入的元素值(用空格隔开):");
	for (i = 0; i < n; i++)
	{
		p = (LinkList)malloc(sizeof(Node));
		scanf("%d", &p->data);
		r->next = p;
		r = p;
	}
	r->next = NULL;
}

int LengthList(LinkList *L)					//计算链表长度
{
	int length = 0;
	LinkList p;
	p = (*L)->next;
	while (p)
	{
		length++;
		p = p->next;
	}
	return length;
}

int GetElem(LinkList L, int i, elemtype *e)			//用e返回L中第i个元素值
{
	int j = 1;
	LinkList p;
	p = L->next;
	while (p && j < i)
	{
		p = p->next;
		++j;
	}
	if (!p || j > i)
	{
		printf("查询不到该元素!\n");
		return 0;
	}
	*e = p->data;
	return 0;
}

int InsertList(LinkList *L, int i, elemtype e)			//在L中第i个位置插入元素e
{
	LinkList p, s;
	int j = 1;
	p = *L;
	while (p && j < i)
	{
		p = p->next;
		++j;
	}
	if (!p || j > i)
	{
		printf("插入元素失败!\n");
		return 0;
	}
	s = (LinkList)malloc(sizeof(Node));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return 0;
}

int DeleteList(LinkList *L, int i, elemtype *e)				//删除L中第i个元素,并用e返回其值
{
	LinkList p, q;
	int j = 1;
	p = *L;
	while (p->next && j < i)
	{
		p = p->next;
		++j;
	}
	if (!(p->next) || j > i)
	{
		printf("删除元素失败!\n");
		return 0;
	}
	q = p->next;
	p->next = q->next;
	*e = q->data;
	free(q);
	return 0;
}

int ClearList(LinkList *L)					//单链表的整表删除
{
	LinkList p, q;
	p = (*L)->next;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	(*L)->next = NULL;
	return 0;
}

void ShowList(LinkList *L)					//打印整个链表
{
	LinkList p;
	p = (*L)->next;
	if (p == NULL)
	{
		printf("这是一个空链表!\n");
	}
	printf("单链表");
	while (p)
	{
		printf(" -> %d", p->data);
		p = p->next;
	}
	printf("\n");
}

int main()
{
	LinkList L;
	InitList(&L);
	int k,i;
	elemtype m ;
	CreateListHead(&L);
	ShowList(&L);
	printf("单链表的长度为%d\n", LengthList(&L));
	CreateListTail(&L);
	ShowList(&L);
	printf("单链表的长度为%d\n",LengthList(&L));
	GetElem(L, 5, &m);
	printf("得到的元素值为:%d\n", m);
	InsertList(&L, 4, 25);
	printf("插入元素后的");
	ShowList(&L);
	DeleteList(&L, 3, &m);
	printf("删除元素后的");
	ShowList(&L);
	printf("删除的元素值为:%d\n", m);
	ClearList(&L);
	system("pause");
	return 0;
}
以下是单链表C语言代码实现,包括建立线性表、删除、查找、插入元素等操作: ```c #include<stdio.h> #include<stdlib.h> // 单链表结点的定义 typedef struct LNode{ int data; // 数据域 struct LNode *next; // 指针域,指向下一个结点 }LNode, *LinkList; // 单链表的建立 void CreateList(LinkList *L, int a[], int n){ *L = (LinkList)malloc(sizeof(LNode)); // 创建头结点 (*L)->next = NULL; // 头结点的指针域为空 LNode *p = *L; // p指向当前结点 for(int i=0; i<n; i++){ LNode *s = (LinkList)malloc(sizeof(LNode)); // 创建新结点 s->data = a[i]; // 数据域赋值 s->next = NULL; // 指针域为空 p->next = s; // p的指针域指向新结点s p = s; // p指向新的结点s } } // 单链表的删除 bool DeleteList(LinkList L, int i, int *e){ if(i<1) return false; // i的值不合法 LNode *p = L; int j = 0; while(p->next!=NULL && j<i-1){ p = p->next; j++; } if(p->next==NULL) return false; // i的值超过了链表长度 LNode *q = p->next; *e = q->data; p->next = q->next; free(q); return true; } // 单链表的查找 int LocateList(LinkList L, int e){ LNode *p = L->next; int i = 1; while(p!=NULL && p->data!=e){ p = p->next; i++; } if(p==NULL) return 0; // 没找到 else return i; // 返回e所在位置 } // 单链表的插入 bool InsertList(LinkList L, int i, int e){ if(i<1) return false; // i的值不合法 LNode *p = L; int j = 0; while(p!=NULL && j<i-1){ p = p->next; j++; } if(p==NULL) return false; // i的值超过了链表长度 LNode *s = (LinkList)malloc(sizeof(LNode)); s->data = e; s->next = p->next; p->next = s; return true; } // 单链表的输出 void PrintList(LinkList L){ LNode *p = L->next; while(p!=NULL){ printf("%d ", p->data); p = p->next; } printf("\n"); } int main(){ LinkList L; int a[] = {1,2,3,4,5}; int n = 5; CreateList(&L, a, n); PrintList(L); int e; DeleteList(L, 3, &e); printf("%d\n", e); PrintList(L); int pos = LocateList(L, 4); if(pos==0) printf("4不存在\n"); else printf("4在链表中的位置为%d\n", pos); InsertList(L, 3, 6); PrintList(L); return 0; } ``` 运行结果: ``` 1 2 3 4 5 3 1 2 4 5 4在链表中的位置为3 1 2 6 4 5 ```
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值