C语言数据结构——单链表

0.引言

链表是一种相对简单的数据结构,但衍生种类繁多,并且在某些方面举足轻重。

关于链表的内容回分多篇文章简要介绍,此文仅介绍单链表。

和所有数据结构一样,最基础的部分无非是建立、增、删、改、查、遍历。

(本文以带头结点的链表为例)

1.建立

01.定义链表的结点

typedef int ElemType;
typedef struct LNode
{
	ElemType data;
	struct LNode* next;//指向下一个节点
}LNode,*LinkList;

02.建立链表

(1)头插法建立链表

不妨设输入9999为结束

LinkList CreateList1(LinkList &L)//头插法新建链表 
{
	LNode* s;
	int x;
	L = (LinkList)malloc(sizeof(LNode));//带头结点的链表
	L->next = NULL;//L->data里面没放东西
	scanf("%d", &x);//从标准输入读取数据
	//3 4 5 6 7 9999
	while (x != 9999)
	{
		s = (LNode*)malloc(sizeof(LNode));//申请一个空间,强制类型转换
		s->data = x;//把读取到的值,给新空间中的data成员
		s->next = L->next;//让新结点的next指针指向链表的第一个元素
		L->next = s;//让s作为第一个元素
		scanf("%d", &x);//读取标准输入
	}
	return L;
}

(2)尾插法建立链表

LinkList CreateList2(LinkList& L)//尾插法新建链表
{
	int x;
	L = (LinkList)malloc(sizeof(LNode));//带头节点的链表
	LNode* s, * r = L;//LinkList s,r=L;也可以,r代表链表表尾结点,指向链表尾部
	//3 4 5 6 7 9999
	scanf("%d", &x);
	while (x!=9999)
	{
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;//让尾部指向新节点
		r = s;//r指向新的表尾结点
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}

03.初始化链表

(1)带头结点

bool InitList(LinkList& L)
{
	L = (LNode*)malloc(sizeof(LNode));//分配一个头结点
	if (L == NULL)	//内存不足,分配失败
	{
		return false;
	}
	L->next = NULL; //头结点之后暂时还没有结点
	return true;
}

(2)不带头结点

//不带头结点
bool InitList(LinkList& L)
{
	L = NULL;//空表,暂时还没有任何结点
	return true;
}

2.增:插入元素

01.按位序插入

(1)带头结点

//按位序插入
bool ListFrontInsert(LinkList L, int i, ElemType e)//往第i个位置插入元素
{
	if (i < 1)
	{
		return false;
	}
	LinkList p = GetElem(L, i - 1);//拿到要插入位置的前一个位置的地址值
	if (NULL == p)
	{
		return false;//i不对
	}
	LinkList s = (LNode*)malloc(sizeof(LNode));//为新插入的结点申请空间
	s->data = e;//要插入的值放入空间
	s->next = p->next;//插入的步骤
	p->next = s;
	return true;
}

(2)不带头结点

//按位序插入
bool ListInsert(LinkList& L, int i, ElemType e)
{
	if (i < 1)
	{
		return false;
	}
	if (i == 1)//插入第一个结点的操作与其它结点操作不同
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L = s;//头指针指向新结点
		return true;
	}
	LNode* p;//指针p指向当前扫描到的结点
	int j = 1;//当前p指向的是第几个结点
	p = L;//p指向第一个结点(注意:不是头结点)
	while (p != NULL && j < i - 1)//循环找到第i-1个结点
	{
		p = p->next;
		j++;
	}
	if (p == NULL)//i值不合法
	{
		return false;
	}
	LNode* s = (LNode*)malloc(sizeof(LNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;//插入成功
}

02.后插操作

//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode* p, ElemType e)
{
	if (p == NULL)
	{
		return false;
	}
	LNode* s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL)//内存分配失败
	{
		return false;
	}
	s->data = e;//用结点s保存数据元素e
	s->next = p->next;
	p->next = s;//将结点s连到p之后
	return true;
}

03.前插操作

//前插操作:在p结点之前插入元素e
bool InsertPriorNode(LNode* p, ElemType e)
{
	if (p == NULL)
	{
		return false;
	}
	LNode* s = (LNode*)malloc(sizeof(LNode));
	if (s == NULL)//内存分配失败
	{
		return false;
	}
	s->next = p->next;
	p->next = s;//新结点s连到p之后
	s->data = p->data;//将p中元素复制到s中
	p->data = e;//p中元素覆盖为e
	return true;
}

3.删:删除元素

01.按位序删除

bool ListDelete(LinkList L, int i)//删除第i个元素的位置
{
	LinkList p = GetElem(L, i - 1);//查找删除位置的前驱结点
	if (NULL==p)
	{
		return false;
	}
	LinkList q = p->next;
	if (NULL==q)
	{
		return false;
	}
	p->next = q->next;
	free(q);
	q = NULL;
	return true;
}

02.按结点删除

//删除指定结点p
bool DeleteNode(LNode* p)
{
	if (p == NULL)
	{
		return false;
	}
	LNode* q = p->next;//令q指向*p的后继节点
	p->data = p->next->data;//和后继节点交换数据域
	p->next = q->next;//将*q结点从链中“断开”
	free(q);//释放后继结点的存储空间
	return true;
}

4.查:查找元素

01.按位序查找

LinkList GetElem(LinkList L, int i)//按序查找元素
{
	int j = 1;
	LNode* p = L->next;//让p指向第一个结点
	if (0==i)
	{
		return L;//i是零就返回头节点
	}
	if (i < 1)
	{
		return NULL;//i是负值就返回空
	}
	while (p && j < i)
	{
		p = p->next;//让p指向下一个结点
		j++;
	}
	return p;
}

02.按元素查找

LinkList LocateElem(LinkList L, int e)//按值查找元素
{
	LinkList p = L->next;
	while (p && p->data != e)
	{
		p = p->next;
	}
	return p;
}

5.检查是否为空

(1)带头结点

bool Empty(LinkList L)
{
	if (L->next == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

(2)不带头结点

//不带头结点
bool Empty(LinkList L)
{
	if (L == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

6.遍历链表并打印

void PrintList(LinkList L)//打印链表
{
	L = L->next;
	while (L!=NULL)
	{
		printf("%3d", L->data);//打印当前结点数据
		L = L->next;//指向下一个结点
	}
	printf("\n");
}

7.链表长度

int Length(LinkList L)
{
	int len = 0;
	LNode* p = L;
	while (p->next != NULL)
	{
		p = p->next;
		len++;
	}
	return len;
}

附:

1.关于销毁和改

销毁只需遍历链表并free一下即可

关于改,直接访问修改即可。

2.此文代码中语法问题


以上因为书写方便,故使用到布尔类型、引用等C++语法,所以使用以上代码文件名后缀要改为cpp,其余书写与C++几乎无关。

相关推荐

  1. C语言数据结构——

    2024-01-30 12:42:01       73 阅读
  2. C语言 数据结构之循环

    2024-01-30 12:42:01       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-30 12:42:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-30 12:42:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-01-30 12:42:01       82 阅读
  4. Python语言-面向对象

    2024-01-30 12:42:01       91 阅读

热门阅读

  1. Redis -- 背景知识

    2024-01-30 12:42:01       62 阅读
  2. 【C++】构造函数

    2024-01-30 12:42:01       55 阅读
  3. 如何系统地自学 Python?

    2024-01-30 12:42:01       74 阅读
  4. 【Vue3】状态管理工具——pinia的使用

    2024-01-30 12:42:01       71 阅读
  5. 四:C语言-条件分支语句

    2024-01-30 12:42:01       59 阅读
  6. 【前端】防抖和节流

    2024-01-30 12:42:01       66 阅读