单链表初学笔记

没什么好说的,添加头文件和创建单链表的形式
申明定义一个结构体,结构体类型名叫做 struct Node,为了便于理解,这个结构体里面的数据段只用来存储一个最简单的整形数据(data),然后定义一个(struct Node)类型的指针,用于指向后面一个链表元素的地址.
由于我们使用dypedef定义这个结构体类型为Nodelb,后面需要使用(struct Node)类型时就可以直接使用Nodelb

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

typedef struct Node
{
	int data;
	struct Node* next;
}Nodelb;

定义一个函数,createList(),这个函数的目的是创建链表的第一个元素,这个元素中的数据不使用,然后把这个创建的链表元素指针域指向空.然后返回这个新结构体变量的地址.

Nodelb* createList()
{
	Nodelb* headNode = (Nodelb*)malloc(sizeof(Nodelb));
	headNode->next = NULL;
	return headNode;
}

定义一个函数,createNode(int data) 这个函数的目的是创建一个新的结点.
这个结点的数据,由我们传入的参数决定.然后将这个新结点的指针域指向空,最后返回这个新结点(此时动态申请了内存空间,所以有了一个新的结构体)的地址(以指针形式).
(注意:这个函数是为了接下来的插入结点时使用的函数所服务的)

Nodelb* createNode(int data)
{
	Nodelb* newNode =(Nodelb*)malloc(sizeof(Nodelb));
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}

定义一个函数insertNodeByHead(Nodelb* headNode, int data),
这个函数的目的是在链表中插入一个结点,插入结点的数据是data
所以我们这个函数需要两个参数,一个是原始链表(需要在哪个链表里面插入?),一个是插入的具体数据先创建一个(newNode)新结点使用的是上面的 (createNode)函数
(注意:这下重点来了,为什么称之为链表,链即是链接,我们为了使前后元素之间产生确实的联系.所以需要使用下列步骤)
让新结点的next指向原来链表指向的next,紧接着让原来链表的next指向这个我们创建的结点.

void insertNodeByHead(Nodelb* headNode, int data)
{
	Nodelb* newNode = createNode(data);
	newNode->next = headNode->next;
	headNode->next = newNode;
}

定义一个函数,deleteNodeByAppoin(Nodelb* headNode, int posData)
这个函数的目的是删除一个结点,同样的,我们需要在哪一个链表里面去删除,然后删除的具体数据是谁?所以我们需要两个参数,参数1(Nodelb* headNode)需要删除链表的起始地址 参数2(int posData)需要删除元素的数据
然后我们进入函数内部看具体步骤:首先创建两个结构体指针(posNode)(posNodeFront),分别赋值:posNode赋值成原链表头结点的next,posNodeFront赋值成为原链表头结点的内容(因为后面要用到循环结构,所以这里才要用到本来非法值得headNode)

添加判断(如果posNode为空指针的情况),这里没什么好说的.

添加循环条件(posData != posNode->data)这个循环条件我理解了很久,也没有怎么搞懂,应该是我不怎么聪明的原因,如果传入的参数不等于现在现在创建的这个临时结构体内的数据(也就是原链表当中的头结点(这个地方的头结点要理解成一直向后变化的才行)中的data)

将posNode的值赋给posNodeFront,将posNodeFront->next赋给posNode,这样做的目的在于迭代,让posNode的值转走,转向原本位于posNodeFront的值,然后自己走向下一个结点.
(可以理解成a = a+1的复杂形势)

如果(posNode == NULL),这个时候就说明遍历整个链表都没有找到永远传入数据的结点.所以找不到,直接返回就好.

跳出这个循环只有两种可能,一个是找到了传入数据的结点(posData == posdata),还有一种就是直接被函数返回了.

前面的都是限制条件:作为思考找不到的情况,传入的链表是空链表的情况.接下来就是实际的删除结点部分:在找到了传入数据的结点情况时,跳出循环,走向下一段代码:
(找到了,然后将posNode->next赋给posNodeFront->next,如下图所示:)
(这里的红色框中描述可能有问题,如果有错误还请指出,)在这里插入图片描述

然后释放(posNode),并且赋值成空指针.以免内存泄漏.

void deleteNodeByAppoin(Nodelb* headNode, int posData)
{
	Nodelb* posNode = headNode->next;
	Nodelb* posNodeFront = headNode;
	if(posNode == NULL)
	{
		printf("无法删除空链表");
		return;
	}
	else
    {
    	while(posData != posNode->data)
    	{
    		posNodeFront = posNode;
    		posNode = posNodeFront->next;
    		if(posNode == NULL)
    		{
    			printf("没有找到相关信息,无法删除\n");
    			return;
			}
		}
		posNodeFront->next = posNode->next;
		free(posNode);
		posNode = NULL;
	}
}

定义函数printList(Nodelb* headNode)
(这个函数的目的是:打印整个链表,因此,我们需要传入打印的链表,所以参数是Nodelb* headNode)
进入函数内部:定义一个结构体指针pMove = headNode->next
(因为传入的链表实际上是最开始的结点,这个结点内的数据时什么我们不知道,指向的是一个随机数据.所以我们要从头结点的下一个结点开始打印)
当pMove不为空指针时:打印此时pMove的数据,然后向后移动.

void printList(Nodelb* headNode)
{
	Nodelb* pMove = headNode->next;
	while(pMove)
	{
		printf("%d\t",pMove->data);
		pMove = pMove->next;
	}
	printf("\n");
}

主函数,创建四个结点,实际上有五个结点,只是我们没有使用头结点的数据域,所以最后打印结果应该是:
(4 3 2 1)
(4 3 1)

int main (void)
{
	Nodelb* list = createList();
	
	insertNodeByHead(list, 1);
	insertNodeByHead(list, 2);
	insertNodeByHead(list, 3);
	insertNodeByHead(list, 4);
	
	printList(list);
	deleteNodeByAppoin(list, 2);
	printList(list);

	return 0;
}

–至此结束–


完整代码如下:

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

typedef struct Node
{
	int data;
	struct Node* next;
}Nodelb;

Nodelb* createList()
{
	Nodelb* headNode = (Nodelb*)malloc(sizeof(Nodelb));
	headNode->next = NULL;
	return headNode;
}

Nodelb* createNode(int data)
{
	Nodelb* newNode =(Nodelb*)malloc(sizeof(Nodelb));
	newNode->data = data;
	newNode->next = NULL;
	return newNode;
}

void printList(Nodelb* headNode)
{
	Nodelb* pMove = headNode->next;
	while(pMove)
	{
		printf("%d\t",pMove->data);
		pMove = pMove->next;
	}
	printf("\n");
}

void insertNodeByHead(Nodelb* headNode, int data)
{
	Nodelb* newNode = createNode(data);
	newNode->next = headNode->next;
	headNode->next = newNode;
}

void deleteNodeByAppoin(Nodelb* headNode, int posData)
{
	Nodelb* posNode = headNode->next;
	Nodelb* posNodeFront = headNode;
	if(posNode == NULL)
	{
		printf("无法删除空链表");
		return;
	}
	else
    {
    	while(posData != posNode->data)
    	{
    		posNodeFront = posNode;
    		posNode = posNodeFront->next;
    		if(posNode == NULL)
    		{
    			printf("没有找到相关信息,无法删除\n");
    			return;
			}
		}
		posNodeFront->next = posNode->next;
		free(posNode);
		posNode = NULL;
	}
}

int main (void)
{
	Nodelb* list = createList();
	
	insertNodeByHead(list, 1);
	insertNodeByHead(list, 2);
	insertNodeByHead(list, 3);
	insertNodeByHead(list, 4);
	
	printList(list);
	deleteNodeByAppoin(list, 2);
	printList(list);

	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值