C语言--单链表

一、单链表结构

这里我们可以看到数据存储在结构体内,结构体一部分用来存储数据,一部分用指针来存储需要链接的地址。通过这些地址,我们能灵活地查找到其数据位置,从而完成增删查改等功能。

二、完成简单单链表,实现其功能

1、定义结构体

这里我们简单为主,先构建一个结构体,一部分储存整形数据,一部分用来存地址——

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

typedef int SLTDataTyp;

typedef struct SListNode
{
	SLTDataTyp data;
	struct SListNode* next;
}SLTNode;

这里我们用到重命名法将数据类型进行重命名,进而使其更为灵活 。

2、进行数据存储测试

void SListTest1()
{
	SLTNode* n1 = (SLTNode*)malloc(sizeof(SLTNode));
	assert(n1);
	SLTNode* n2 = (SLTNode*)malloc(sizeof(SLTNode));
	assert(n2);
	SLTNode* n3 = (SLTNode*)malloc(sizeof(SLTNode));
	assert(n3);
	SLTNode* n4 = (SLTNode*)malloc(sizeof(SLTNode));
	assert(n4);
	SLTNode* n5 = (SLTNode*)malloc(sizeof(SLTNode));
	assert(n5);


	n1->data = 1;
	n2->data = 2;
	n3->data = 3;
	n4->data = 4;
	n5->data = 5;

这里可以随便用malloc函数开辟几个空间进行测试,存储数据后,将其链接起来。 

    n1->next = n2;
	n2->next = n3;
	n3->next = n4;
	n4->next = n5;
	n5->next = NULL;

此时我们可以通过调试的方法进行查看——

3、打印储存数据

为了方便查看,我们可以先进行打印,后期也需要用到此函数——

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

4、增加数据

增加数据可以分为头增和尾增,也可随机增加,数据增加必定要创建新的结构体,此时我们可用malloc新创建一个结构体,在三个函数(头增和尾增还有随机增加都需要用到这个函数)所以我们可以分装出一个函数。(注意,在更改链表的时候需要进行结构体传参,改变整个结构体需要传入指针变量,因为读取结构体数据本就是指针,所以这里找到数据并进行更改,形参需要传入指针变量,即这里传入二级指针)这部分可以举个简单的例子——

SLTNode* BuySLTNode(SLTDataTyp x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	assert(newnode);
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

这里开辟一个结构体类的函数用来开辟新的结构体,进而进行数据的增加。

然后将其与单链表链接起来——

1.头插

void SLTPushFront(SLTNode** pphead, SLTDataTyp x)
{
	SLTNode* newnode = BuySLTNode(x);

	newnode->next = *pphead;
	*pphead = newnode;
	
}

2.尾插 

void SLTPushBack(SLTNode** pphead, SLTDataTyp x)
{
	SLTNode* newnode = BuySLTNode(x);

	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* cur = *pphead;
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}
}

头插的话可以直接调用此函数进行增加位置,尾插的话需要分情况而定,将其分为是否为空链表和是否存在数据。

3.随机插入

void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pos);
	assert(pphead);

	// 头插
	if (pos == *pphead)
	{
		SListPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		SLTNode* newnode = BuySListNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}

5、删除数据

删除数据也分为头删和尾删,删除之前需要检查链表是否为空,进而进行下一步的更改——

1.尾删

我们先来看下大多数人容易错的——野指针问题

void SLTPopBack(SLTNode** pphead)
{
	assert(*pphead);
	while ((*pphead)->next != NULL)
	{
		*pphead = (*pphead)->next;
	}
	free(*pphead);
 //释放时将*pphead前面的next指针变为了野指针,进而程序崩溃
	(*pphead)->next = NULL;
}

这个思路显然很简单,但造成了野指针的问题,可进行调试查看。 


void SLTPopBack(SLTNode** pphead)
{
	assert(*pphead);
	//一个节点
	if ((*pphead) == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* cur = *pphead;
		SLTNode* tail = *pphead;

		while (cur->next != NULL)
		{
			tail = cur;
			cur = cur->next;
		}
		free(cur);
		tail->next = NULL;
	}
}


2.头删

void SLTPopFront(SLTNode** pphead)
{
	assert(*pphead);
	*pphead = (*pphead)->next;
	free(*pphead);
	//*pphead = (*pphead)->next;//野指针问题
}

//也可以创建结构体指针指向节点
//void SLTPopFront(SLTNode** pphead)
//{
//	assert(*pphead);
//	SLTNode* next = (*pphead)->next;
//	free(*pphead);
//	*pphead = next;
//}

3.随机删除

void SListErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		prev->next = pos->next;

		free(pos);
		pos = NULL;
	}
}

6、查找

这个较为简单,遍历即可,找到级返回结构体指针,找不到返回空——

SLTNode* SLTFind(SLTNode* phead, SLTDataTyp x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
			return cur;

		cur = cur->next;
	}

	return NULL;
}

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单链表是一种常见的数据结构,它由一个或多个节点组成,每个节点包含一个数据域和一个指针域,指针域指向下一个节点。 实现单链表的查找位序算法函数需要以下步骤: 1. 定义一个指针p指向链表的头节点,并定义一个变量count,用于计数。 2. 从头节点开始,遍历链表,当p指向某个节点时,计数器count加1。 3. 如果p指向的节点的数据与目标数据相等,则返回当前的计数器count,即为目标数据的位序。 4. 如果p指向的节点不是目标数据,则将p指向下一个节点,重复步骤3。 5. 如果遍历完链表后仍未找到目标数据,则返回-1,表示未找到。 下面是C语言实现单链表查找位序算法函数的代码示例: ```c #include <stdio.h> #include <stdlib.h> // 定义单链表节点结构 typedef struct Node { int data; // 数据域 struct Node* next; // 指针域 } Node; // 查找位序的算法函数 int findPosition(Node* head, int target) { Node* p = head; // 指向头节点 int count = 0; // 计数器初始化为0 while (p != NULL) { count++; // 计数器加1 if (p->data == target) { return count; // 找到目标数据,返回当前计数器的值 } p = p->next; // 指向下一个节点 } return -1; // 遍历完链表未找到目标数据,返回-1 } int main() { // 创建链表 Node* head = (Node*)malloc(sizeof(Node)); head->data = 1; // 头节点数据为1 Node* node1 = (Node*)malloc(sizeof(Node)); node1->data = 2; Node* node2 = (Node*)malloc(sizeof(Node)); node2->data = 3; head->next = node1; node1->next = node2; node2->next = NULL; // 查找位序示例 int target = 3; // 目标数据为3 int position = findPosition(head, target); if (position != -1) { printf("目标数据 %d 的位序为 %d\n", target, position); } else { printf("未找到目标数据 %d\n", target); } // 释放链表内存 free(node2); free(node1); free(head); return 0; } ``` 在上述代码中,我们首先定义了一个指向头节点的指针p和一个计数器count,然后使用while循环遍历链表。当p指向某个节点时,计数器加1,并判断该节点的数据是否与目标数据相等。如果找到了目标数据,则返回当前计数器的值,即为目标数据的位序。如果遍历完链表仍未找到目标数据,则返回-1表示未找到。最后在主函数中演示了调用该算法函数的示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值