链表的增删改查(规范化的)

链表的增删改查

#define _CRT_SECURE_NO_WARNINGS
#include
#include

/*1.创建指针结构体*/
typedef int ElemType;
typedef struct LNode {
	ElemType data;//数据域
	struct LNode* next;//指针域
}LNode, * LinkList;

/*
	2.头插法创建新链表{
		2.1 产生一个头节点L
		2.2 将头节点的指针域变为空
		2.3 循环读取新的数据(3,4,5,6,7,9999 读取的数据){
			2.3.1 申请一个新空间,给s(结构体类型的)
			2.3.2 将读取的新数据赋值给s的数据域
			2.3.3 修改s的指针域,让新节点的next指针指向链表的第一个元素(头节点之后的元素)
			2.3.4 修改L的指针域
			2.3.5 进行下一次的数据的读取
		}
		返回头节点
	}
*/
LinkList CreateList1(LinkList &L)
{
	LNode* s; int x;//创建指向接结构体的指针,以及存放数据的变量
	L = (LinkList)malloc(sizeof(sizeof(LNode)));//产生一个头节点L
	L->next = NULL; //将头节点的指针域变为空

	//循环读取新的数据(3,4,5,6,7,9999 读取的数据)
	scanf("%d", &x);
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode));//申请一个新空间,给s(结构体类型的)
		s->data = x;//将读取的新数据赋值给s的数据域
		s->next = L->next;//修改s的指针域,让新节点的next指针指向链表的第一个元素(头节点之后的元素)
		L->next = s;//修改L的指针域
		scanf("%d", &x);
	}
	return L;
}

/*
	3.打印链表中的每一个节点的值
*/
void PrintList(LinkList L)
{
	//为什么这里可以用L,不会改变L的值,因为函数是值传递,并没有用引用

	L = L->next;
	while (L != NULL)
	{
		printf("%3d", L->data);//打印当前节点数据
		L = L->next;//指向下一个节点
	}

}

/*
	4.尾插法创建链表
	LinkList CreateList2(LinkList &L){
		//4.0 创建变量x用于数据的读取
		//4.1 申请带头结点的链表
		//4.2 创建LNode *s,*r=L;进行插入操作,其中r代表的是链表的表尾的节点,指向链表的尾部
		//4.3 循环读取数据(3 4 5 6 7 9999){
			//4.3.1 新申请一个新节点,让s指向
			//4.3.2 s(新节点)的数据域 = 读取的数据x
			//4.3.3 r(尾节点)的指针域指向s(新节点)
			//4.3.4 r(尾节点)指向s(本质:就是让r尾节点始终指向最后一个节点)
			//4.3.5 进行下一次的数据的读取
		}
		//4.4 循环结束后,将尾节点的指针域变为NULL;
		//4.5 返回链表的头指针
	}
*/
LinkList CreateList2(LinkList &L) {
	int x; //创建变量x用于数据的读取
	L = (LinkList)malloc(sizeof(LNode)); //申请带头结点的链表
	LNode* s, * r = L; //创建LNode *s,*r=L;进行插入操作,其中r代表的是链表的表尾的节点,指向链表的尾部
	//L->next = NULL;

	scanf("%d", &x);
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode)); //新申请一个新节点 ,让s指向
		//s->next = r->next;
		s->data = x; //s(新节点)的数据域 = 读取的数据x
		r->next = s; //r(尾节点)的指针域指向s(新节点)
		r = s; //r(尾节点)指向s(本质:就是让r尾节点始终指向最后一个节点)
		scanf("%d", &x); //进行下一次的数据的读取

	}
	r->next = NULL; //循环结束后,将尾节点的指针域变为NULL;
	return L;

}

/*
5.查找第几个节点的值
LNode* GetElem(LinkList L,int i){
	1.创建变量j=1,用于保存当前是第几个节点
	2.创建结构体指针p,指向第一个节点
	3.判断查找位置是否是头结点以及是否合法
	4.循环遍历{
		4.1指针指向下一个节点
		4.2j++保存下一个节点
	}
	5.循环遍历后返回p
}
*/
LNode* GetElem(LinkList L, int i) 
{
	int j = 1;//创建变量j=1,用于保存当前是第几个节点
	LNode *p = L->next;//创建结构体指针p,指向第一个节点
	
	if (i == 0)//判断查找位置是否是头结点
		return L;
	
	if (i < 1)//判断查找位置是否合法,i是负值就返回空
		return NULL;
	
	while (p && j < i)
	{
		p = p->next;//指针指向下一个节点
		j++;//j++保存下一个节点
	}
	return p;
}

/*
6.按值查询
	LinkList LocateElem(LinkList L, ElemType e)
	{
		1.定义结构体指针变量,让p指向第一个节点
		2.循环遍历,直到p非空或者p的数据域等于e循环结束
		3.返回结构体指针p
	}
*/
LinkList LocateElem(LinkList L, ElemType e) 
{
	LinkList p = L->next;
	while (p != NULL && p->data != e) 
	{
		p = p->next;
	}
	return p;
}

/*
7.往第i个位置插入元素
bool ListFrontInsert(LinkList L,int i,ElemType e)
{
	1.通过GetElem函数,得到插入的i位置的前驱节点,返回值用p接收
	2.判断前驱节点是否为空(即判断插入的i的位置是否合法)
	3.申请一个新的空间,用变量s结构体指针变量指向
	4.给s指向的节点的指针域赋值
	5.进项相关的插入步骤
	6.返回true(代表插入成功)
}

这里为什么没有使用LinkList &L(引用),而是用的是LinkList L?
原因:
因为子函数ListFrontInsert并没有改变主函数L的指针的指向,以及其中的值,
但是头插法和尾插法的相关函数(子函数)通过相关的函数(子函数)中的此语句 L = (LinkList)malloc(sizeof(LNode));
从而使得主函数中的L的值发生了改变,所以需要用到引用
*/
bool ListFrontInsert(LinkList L, int i, ElemType e)
{
	LinkList p = GetElem(L, i - 1);//通过GetElem函数,得到插入的i位置的前驱节点,返回值用p接收
	
	//判断前驱节点是否为空(即判断插入的i的位置是否合法)
	if (p == NULL)
	{
		return false;
	}

	LinkList s = (LinkList)malloc(sizeof(LNode));//申请一个新的空间,用变量s结构体指针变量指向
	s->data = e;//给s指向的节点的指针域赋值
	s->next = p->next;//进项相关的插入步骤
	p->next = s;
	return true;
}

/*
	8.删除第i个位置的元素
	bool ListDelete(LinkList L,int i){
		9.1 获取删除位置的前驱节点
		9.2 判断删除的位置是否合法
		9.3 删除操作
	}
*/
bool ListDelete(LinkList L, int i)
{
	LinkList p = GetElem(L, i - 1);//获取删除位置的前驱节点
	if (p == NULL)
	{
		return false;//判断删除的位置是否合法,即前驱节点是否为空
	}
	// 删除操作
	LinkList q = p->next;
	p->next = q->next;
	free(q);
	q = NULL;//为了避免野指针
	return true;
}


int main()
{
	LinkList L;//定义链表头,是结构体指针类型
	LinkList search;//用来存储拿到的某一个节点

	//头插法创建链表
	//CreateList1(L);//输入的数据是3 4 5 6 7 9999

	//尾插法创建链表
	CreateList2(L);//输入的数据是3 4 5 6 7 9999

	//链表打印
	PrintList(L);

	//查找第2个元素
	search = GetElem(L,2);
	if (search!=NULL)
	{
		printf("\n按序号查找成功\n");
		printf("%d\n",search->data);
	}

	//按值查找值为6的节点
	search = LocateElem(L, 6);
	if (search!=NULL)
	{
		printf("按值查找成功\n");
		printf("%d\n",search->data);
	}

	//新节点插入第i个位置
	ListFrontInsert(L, 2, 99);
	PrintList(L);

	printf("\n");
	//删除第4个节点
	ListDelete(L, 4);
	PrintList(L);
	return 0;
}

你可能感兴趣的:(数据结构各种常见的实验,链表,数据结构,c++)