C语言单向链表的创建,增加,删除和打印,以及模块化设计

链表:一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次 序实现的。链表由一系列结点(链表中每一个元素称为 结点)组成,结点可以在运行时动态生成。每个结点包 括两个部分:一个是存储数据元素的数据域,另一个是 存储下一个结点地址的指针域。 

涉及链表的操作有很多,今天简单讲解一下单向链表的创建 增加 删除 打印。

首先声明一个结构体要有数据域和指针域,因为链表是非连续、非顺序的存储结构,需要用指针来找到下一个结点的位置。声明常用有两种方法:

/*第一种*/
struct Node
{
	int date;          //数据域
	struct Node * next;	 //指针域
};


/*第二种*/
typedef struct Node
{
	int date;          //数据域
	struct Node * next;	 //指针域
}Node;
  • 创建链表与结点
//创建链表 
struct Node * createList()    
{
	struct Node * headNode = (struct Node *)malloc(sizeof(struct Node));
	//headNode变成一个变量
	//变量使用前初始化
	headNode->next = NULL;
	tail=headNode;  //后面尾插会用到
	return headNode;
}; 
//创建结点 
struct Node * createNode(int date)
{
	struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
	newNode->date = date;
	newNode->next = NULL;
	return newNode;
}
  • 增加结点(头插法和尾插法)(ps:不要将头插和尾插混合使用)
  1. 头插法

思路:

插入的结点永远在头结点的后面,同时要保证让新结点先指向原来的头结点后一位,再让头结点记录新结点的位置,因为如果是先让头结点记录新结点的位置,那么,原来结点的位置信息就丢失了,这个链表就会中断,连不起来,结合图理解。

 代码:

//插入结点(头插法)
void insertNodebyHead(struct Node * headNode, int date)
{
	//创建新结点 
	struct Node * newNode = createNode(date); 
	
    /*位置不能交换*/
	newNode->next = headNode->next;
	headNode->next= newNode;
	 
} 

        2.尾插法

思路:

将新的结点加在链表的尾端,我们知道结点的位置只能通过上一个结点来找到它,所以我们就要用一个tail指针来确定最后一个结点的位置。所以我们需要一开始声明一个tail指针。

代码:

//插入结点(尾插法) 
void insertNodebyTail(struct Node * headNode, int date)
{
	//创建新结点
	struct Node * newNode = createNode(date);
	
	tail->next = newNode;
	tail = newNode;
}
  • 删除结点

思路:

删除的话涉及查找,我们肯定是先找到,在删除,所以我们需要两个指针来遍历链表,一个在前,一个在后,后一位的指针负责查找,前一位的指针负责将删除后的链表仍然串起来。

代码:

//删除结点
void deleteNode(struct Node * headNode, int posDate)
{
	struct Node * posNode = headNode->next;
	struct Node * posNodefront = headNode;
	
	if (posNode == NULL)
	{
		printf("无法删除链表\n");
	}
	
	else
	{
		/*查找*/
        while (posNode->date != posDate)
		{
			posNodefront = posNode;
			posNode = posNodefront->next;
			
			if (posNode == NULL)
			{
				printf("未找到指定结点,无法删除\n");	
				return;
			} 
		}
		posNodefront->next = posNode->next;
		free(posNode);    //删除
	}
} 
  • 打印链表

思路:

另外声明一个指针从头结点下一位开始,检查每一个结点的情况,如果不为NULL,打印出数据,如果为NULL,则退出。

代码:

//打印链表
void printList(struct Node * headNode)
{
	struct Node * pMove = headNode->next;  
	
	while (pMove != NULL)
	{
		printf("%d ", pMove->date);
		pMove = pMove->next;   
	} 
	printf("\n");
} 

完整的代码:

/*动态创建一个链表 */
//创建链表
//创建结点
//插入结点(头插法和尾插法) 
//删除结点
//打印遍历链表 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node * tail = NULL;
struct Node
{
	int date;
	struct Node * next;	
};

//创建链表 
struct Node * createList()    
{
	struct Node * headNode = (struct Node *)malloc(sizeof(struct Node));
	//headNode变成一个变量
	//变量使用前初始化
	headNode->next = NULL;
	tail=headNode;
	return headNode;
}; 

//创建结点 
struct Node * createNode(int date)
{
	struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
	newNode->date = date;
	newNode->next = NULL;
	return newNode;
}

//插入结点(头插法)
void insertNodebyHead(struct Node * headNode, int date)
{
	//创建新结点 
	struct Node * newNode = createNode(date); 
	
	newNode->next = headNode->next;
	headNode->next= newNode;
	 
} 
//插入结点(尾插法) 
void insertNodebyTail(struct Node * headNode, int date)
{
	//创建新结点
	struct Node * newNode = createNode(date);
	
	tail->next = newNode;
	tail = newNode;
}



//删除结点
void deleteNode(struct Node * headNode, int posDate)
{
	struct Node * posNode = headNode->next;
	struct Node * posNodefront = headNode;
	
	if (posNode == NULL)
	{
		printf("无法删除链表\n");
	}
	
	else
	{
		while (posNode->date != posDate)
		{
			posNodefront = posNode;
			posNode = posNodefront->next;
			
			if (posNode == NULL)
			{
				printf("未找到指定结点,无法删除\n");	
				return;
			} 
		}
		posNodefront->next = posNode->next;
		free(posNode);
	}
} 


//打印链表
void printList(struct Node * headNode)
{
	struct Node * pMove = headNode->next;  
	
	while (pMove != NULL)
	{
		printf("%d ", pMove->date);
		pMove = pMove->next;   
	} 
	printf("\n");
} 

int main(void)
{
	/*自己发挥*/
    
	return 0;
}

我是将链表的各个操作模块化了,这样看起来简洁,如果需要修改数据的话,只用改一下代码中的date就行了,同时单链表的一些其他操作也可以对上面的代码稍加修改即可。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Junbai_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值