单向链表和双向链表基本操作的实现(数据结构 C语言实现版)

大家吼我又来了,今天我给大家带来的是单向链表和双向链表的基本操作(基本上挺全的。。。)
数据结构这门课程是学计算机的学生们感觉很重要很困难的学科。而链表也基本上算是数据结构刚入门时所写的了吧。
我把自己学习数据结构的历程分享到自己的博客里,供大家学习也供我自己查阅自己的学习历程。若是感觉还不错或者有任何问题的话,欢迎加我的qq:790567648来跟我进一步的交流。hhh
话不多说,我先上代码为敬,(基本上操作内我都写上注释了,再有什么看不懂的地方可以私信我聊)

单向链表的基本操作实现

-------老规矩,头文件,宏定义以及ADT和基本数据操作的声明
#include<stdio.h>
#include <stdlib.h>

typedef int ElemType;

typedef struct Node
{
	ElemType data;
	struct Node *next;
}Node, *List;

List InitList();//带头结点的链表的建立
int Listlength(List L);//求链表的长度
void ListInsert(List L, int i, ElemType e);//在L中第i个位置之后插入一个结点的数值为e
void ListDelete(List L, int i);//链表第i个结点的删除
int GetElemtype(List L, int i);// 返回L中第i个位置的数据元素的值
void GetElem(List L, ElemType e);//查找在链表中是否有e这个元素,有的话返回它在链表中的位置,没有的话显示无
void ListCleaner(List L);//链表的清除
void print(List L);//链表的输出

List InitList()//带头结点的链表的建立(需要参数和不需要参数同理)
{
	Node *last;//p为插入结点,last始终指向末节点;
	List L;
	L = (Node *)malloc(sizeof(Node));
	L->next == NULL;
	last = L;
	ElemType elem;
	printf("已为您创建链表,请输入每个元素的值(以空格隔开并且以-1为结尾且不计入链表之中)\n");
	while (scanf("%d", &elem) && elem != -1)
	{
		Node *p;
		p = (Node *)malloc(sizeof(Node));
		p->data = elem;
		last->next = p;
		last = p;
	}
	last->next = NULL;
	printf("链表以创建成功!\n");
	return L;
}
int Listlength(L)//求链表的长度
{
	Node *p;
	p = L;
	int temp = 0;
	while (p->next != NULL)
	{
		temp++;
		p = p->next;
	}
	return temp;
}
void ListInsert(List L, int i, ElemType e)//在L中第i个位置之后插入一个结点的数值为e
{
	int j = 0;
	Node *p, *temp;
	p = L;
	while (j<i)
	{
		p = p->next;
		j++;
	}
	temp = (Node *)malloc(sizeof(Node));//新建一个结点
	temp->data = e;
	temp->next = p->next;
	p->next = temp;
}
void print(List L)//链表的输出
{
	List tempList;
	tempList = L->next;
	while (tempList)
	{
		printf("%d ", tempList->data);
		tempList = tempList->next;
	}
}
void ListDelete(List L, int i)//链表第i个结点的删除
{
	if (i<1 || i>Listlength(L) + 1)
	{
		exit(0);
	}
	int j = 0;
	Node *p;
	p = L;
	while (p&&j < i - 1)//找到第i个位置前的结点
	{
		p = p->next;
		j++;
	}
	p->next = p->next->next;
}
int GetElemtype(List L, int Position)// 返回L中第i个数据元素的值
{
	Node *p;
	p = L;
	for (int j = 0; j < Position; j++)
	{
		p = p->next;
	}
	return p->data;
}

void ListCleaner(List L)//链表的清除
{
	List p = NULL, q = NULL;//让p指向当前要删除的结点,q指向p之后的结点,等p释放空间后再重复上述操作
	p = L->next;
	while (p)
	{
		q = p->next;
		free(p);
		p = q;
	}
	L->next = NULL;
	printf("链表已经清除!\n");
}
void GetElem(List L, ElemType e)//查找在链表中是否有e这个元素,有的话返回它在链表中的位置
{
	Node *p;
	int temp = 0;
	p = L->next;
	while (p)
	{
		temp++;
		if (p->data == e)
		{
			printf("结果:该元素在第%d个位置\n", temp);
			exit(0);
		}
		p = p->next;
	}
	printf("结果:未找到相关元素!\n");
}

自己写的main函数,大家看看就好,,,,不必当真(QAQ我知道看到这里大佬要开始吐槽我了,手下留情)

int main(void)
{
	int n, i, e;
	List L;
	L = InitList();
	printf("链表的长度为:%d\n", Listlength(L));
	printf("此时,链表的元素为:");
	print(L);
	printf("\n");

	printf("请输入需要插入的位置以及元素:");
	scanf("%d %d", &i, &e);
	ListInsert(L, i, e);
	printf("此时,链表的元素为:");
	print(L);
	printf("\n");
	printf("此时链表的长度为:%d\n", Listlength(L));

	int deletenum;
	printf("请输入要删除的元素的位置为:");
	scanf("%d", &deletenum);
	ListDelete(L, deletenum);
	printf("此时,链表的元素为:");
	print(L);
	printf("\n");
	printf("此时,链表的长度为:%d\n", Listlength(L));

	int test;
	printf("请输入要查询第几个位置的元素:");
	scanf("%d", &test);
	printf("该位置的元素为:%d\n", GetElemtype(L, test));

	int temp;
	printf("请输入此元素来查询该链表中是否有该元素:");
	scanf("%d", &temp);
	GetElem(L, temp);

	printf("正在进行清空操作,请稍候。。。\n");
	ListCleaner(L);
	printf("此时,链表的长度为:%d\n", Listlength(L));
	
	printf("恭喜您以完成全部操作!\n");
	return 0;
}

双向链表的基本操作实现

#include<stdio.h>
#include <stdlib.h>
typedef int ElemType;

typedef struct DuLNode {
	ElemType data;
	struct DuLNode *prior;
	struct DuLNode *next;
}DuLNode,*DuLinkList;

DuLinkList InitList();//带头结点的链表的建立
int Listlength(DuLinkList L);//求链表的长度
void ListInsert(DuLinkList L, int i, ElemType e);//在L中第i个位置之后插入一个结点的数值为e
void ListDelete(DuLinkList L, int i);//链表第i个结点的删除
int GetElemtype(DuLinkList L, int i);// 返回L中第i个位置的数据元素的值
void GetElem(DuLinkList L, ElemType e);//查找在链表中是否有e这个元素,有的话返回它在链表中的位置,没有的话显示无
void ListCleaner(DuLinkList L);//链表的清除
void print(DuLinkList L);//链表的输出

DuLinkList InitList()
{
	DuLinkList L,Last;
	L = (DuLinkList)malloc(sizeof(DuLinkList));
	L->prior = NULL;
	L->next = NULL;
	Last = L;//last一直指向链表的最后一个元素,便于循环内部的初始化链表的值
	int data;
	printf("请输入双向链表的值:(以空格为间隔,结尾为-1且不算在链表中)");
	while (scanf("%d",&data)&&data!=-1)//出现-1则跳出循环,-1不在链表之内
	{
		DuLNode *p = (DuLNode *)malloc(sizeof(DuLNode));
		p->data = data;
		Last->next=p;
		p->prior = Last;
		p->next = NULL;
		Last = p;
	}
	Last->next = NULL;//最后last指向最后一个有效的结点p,使其的next指向NULL
	return L;
}


int Listlength(DuLinkList L)
{
	DuLinkList p;
	p = L;
	int length = 0;
	while (p->next)//若p->next不空,则temp++,temp即为链表的长度
	{
		p = p->next;
		length++;
	}
	return length;
}

int GetElemtype(DuLinkList L, int i)
{
	DuLinkList p = L;
	int j = 0;
	if (L=NULL)
	{
		return;
	}
	else {
		while (p->next&&j < i)//找到第i个元素所在的位置
		{
			p = p->next;
			j++;
		}//跳出循环时p当前的位置即为第i个元素所在的位置(判断并输出的条件是j==i)
		if (j==i)
		{
			return p->data;
		}
	}
}

void GetElem(DuLinkList L, ElemType e)
{
	DuLinkList p = L;
	int temp = 0;
	while (p->next)//p->next若不空,则继续进行遍历,知道找到p
	{
		p = p->next;
		temp++;
		if (p->data==e)
		{
			printf("存在该元素,且它的位置在链表的第%d个位置上\n", temp);
			temp = -1;//若元素在最后一个位置上,则下面的话也会输出,所以改变temp的值,使其跳出循环时不会被下面的判断句所接收
		}
	}
	if (temp>0)
	{
		printf("该链表中不存在该元素!\n");
	}
}

void ListCleaner(DuLinkList L)
{
	DuLinkList p;
	p = L->next;//L为头结点,所以p要指向链表中第一个有效的结点即头结点的next
	while (p)
	{
		L->next = p->next;//将L->next指向p->next,便于删除p时影响链表的结构
		free(p);
		p = L->next;
	}
	printf("链表已清除完毕!\n");
}

void print(DuLinkList L)
{
	int i = 1;
	DuLinkList p = L->next;
	while (p)
	{
		printf("链表的第%d个元素为:%d\n", i, p->data);
		i++;
		p = p->next;
	}
}

void ListInsert(DuLinkList L, int i, ElemType e)
{
	DuLinkList p = L->next;
	int j = 0;
	if (i<0||i>Listlength(L))
	{
		printf("所插入的位置不存在!\n");
	}
	else {
		while (p&&j < i - 1)//找到p为所要插入的位置(即i之后的位置)
		{
			p = p->next;
			j++;
		}
		if (i==0)//想在头结点之后插入元素时
		{
			DuLinkList inserted;
			inserted = (DuLinkList)malloc(sizeof(DuLinkList));
			//四步走,把四个线连起来
			inserted->data = e;
			L->next = inserted;
			inserted->prior = L;
			inserted->next = p;
			p->prior = inserted;
		}
		else if (p->next)//i>0&&p之后还有结点时
		{
			DuLinkList inserted;
			inserted = (DuLinkList)malloc(sizeof(DuLinkList));
			inserted->data = e;
			//四步走,把四个线连起来
			inserted->next = p->next;
			p->next->prior = inserted;
			p->next = inserted;
			inserted->prior = p;
			printf("插入成功!\n");
		}
		else {//i>0&&p为链表最后一个结点时
			DuLinkList inserted;
			inserted = (DuLinkList)malloc(sizeof(DuLinkList));
			inserted->data = e;
			//三步走
			p->next = inserted;
			inserted->prior = p;
			inserted->next = NULL;
		}
	}
}

void ListDelete(DuLinkList L, int i)
{
	if (i<0||i>Listlength(L))
	{
		printf("位置不存在!\n");
	}
	else {
		int j = 0;
		DuLinkList p = L->next;//L为头结点,所以p要指向链表中第一个有效的结点即头结点的next
		//先找到被删除结点的位置
		while (p&&j < i - 1)
		{
			p = p->next;
			j++;
		}

		if (p->next)//p的next后还有结点时
		{//两步走
			p->next->prior = p->prior;
			p->prior->next = p->next;
		}
		else {//p为链表最后一个元素
			p->prior->next = NULL;
		}
	}
}

int main(void)
{
	//双向链表的定义及初始化
	DuLinkList L;
	L = InitList();


	//求链表的长度
	printf("该链表的长度为;%d\n", Listlength(L));


	求链表的第i个位置上的元素
	int temp;
	printf("请输入想要知道的第几个位置:");
	scanf("%d", &temp);
	printf("该位置上的数为:%d\n", GetElemtype(L, temp));


	//求链表是否存在元素的某个值
	printf("请输入想知道链表中是否存在该元素的值:");
	scanf("%d", &temp);
	GetElem(L, temp);
	//遍历输出链表的元素
	print(L);


	//在链表中指定位置后插入元素
	printf("输入你想在第几个位置之后插入元素:");
	int yuansu, weizhi;
	scanf("%d", &weizhi);
	printf("输入你想插入元素的值:");
	scanf("%d", &yuansu);
	ListInsert(L, weizhi, yuansu);
	//遍历
	print(L);


	//在链表中指定位置删除元素
	printf("输入你想删除的结点在链表中的位置:");
	scanf("%d", &weizhi);
	ListDelete(L, weizhi);
	//遍历
	print(L);


	//选择是否进行摧毁链表操作
	printf("是否选择进行摧毁链表操作,1是确定,2是不进行:");
	int boolean;
	scanf("%d", &boolean);	
	if (boolean==1)
	{
		printf("链表正在删除当中。。。\n");
		ListCleaner(L);
		printf("该链表的长度为:%d\n", Listlength(L));
	}
	else{
		printf("恭喜你完成双向链表的全部基本操作!\n");
	}


	return 0;
}

双向链表代码里面的基本内容也都是参照单向链表里面写的,只不过更进一步而已。而循环链表我没再写是因为只要把最后last-next从指向NULL改为指向头结点即可。具体操作跟单向链表几乎一模一样(当然你也可以从双向链表的基础上做也就是双向循环链表hhh)

*PS:*emmmm…我写的两个基本操作集里面的链表都是带头结点的,而且Ctrl A+Crtl C+Ctrl V是可以直接使用C语言编译器通过的。。。刚想起来补充上,还有一些可能想不起来了想起来的时候会更新哦!

大家也要加油鸭!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值