数据结构之单链表

单链表的基本操作

这里所创建的单链表都为带头结点的单链表

关于Node结构体

在这里插入图片描述
这就可以理解为一个结点类型
data为数据域
*next为指针域,next为指向一个结点的指针

头结点

在这里插入图片描述
上图就为头结点
数据域不存放任何东西!
由图知头结点初始化要令其指针域指向NULL

单链表

在这里插入图片描述
上图就为一个带头结点的单链表

我们可以清楚的知道一些内容,最后一个结点(尾结点)指向空

头结点的指针域指向首结点,首结点的指针域指向下一个结点……

最终形成一个链,即为单链表。

方向:从头结点开始,往下串起来,单向

故:我们无法从下一个结点找到上一个结点

例子:假设我们已知3,我们想找到2,是无法利用3来找到2的。

但我们可以利用头结点找到2

头结点的重要性就体现出来了,我们可以利用头结点找到整个单链表!(这便是带头结点的优势所在,只要头结点不丢失,就可以找到整个链表,故以下的函数我多数使用返回值为void的函数)

List.h文件

#ifndef  __LIST_H__
#define  __LIST_H__

typedef int Elempyte;	//注:将typedef int Elempyte写在Node上面!!!
//结点类型声明
typedef struct Node
{
	Elempyte data;
	struct Node* next;
}Node, * List;//Node为Node类型,List为Node*类型


List Init_Node();				//结点初始化
void Build_List(List, int);		//创建单链表(头插法)
void Insert_Node(List, int);	//插入结点
void Delete_Node(List, int);	//删除结点
void Printf_List(List );		//打印单链表
List Reserve_List(List );		//逆置单链表

#endif // !__LIST_H__

List.c文件

初始化头结点

/*
@初始化结点
@List Build_List()
@返回值为:struct Node * 类型
@这里是初始化头结点,相当于单链表初始化
@使用例子:List head = List Init_Node();
*/
List Init_Node()
{
	List head;
	head = (List)malloc(sizeof(Node));
	head->next = NULL;//一定要令其指向NULL!!!
	return head;
}

创建单链表

/*
@创建单链表(头插法)
@void Build_List(List,int)
@第一个参数:struct Node * 类型,这里使用的是头结点
@第二个参数:int 类型,这里是指创建一个长度为n的单链表
@返回值:无
*/
void Build_List(List head, int n)
{
	List q;
	for (int i = 0; i < n; i++)
	{
		q = (List)malloc(sizeof(Node));
		scanf_s("%d", &(q->data));
		q->next = head->next;
		head->next = q;
	}
}

在这里插入图片描述

头插法,会令存储的数据逆向,故需使用逆置函数将其倒回来

例如输入:1 2 3 4 5

单链表存储形式:

head -> 5 -> 4 -> 3 -> 2 -> 1 -> NULL

故打印后输出:5 4 3 2 1

插入结点

/*
@插入结点
@void Insert_Node(List,int)
@第一个参数:struct Node * 类型,这里使用的是头结点
@第二个参数:int 类型,这里是指插入第n个结点前面,取值范围 n >= 1 (n == 0 时 与 n == 1 等效)
@返回值:无
*/
void Insert_Node(List head, int n)
{
	List q=head;//定义一个变量指针q指向head,作用:找到第n个结点的前一位(0与1等效)
	for (int i = 0; i < n-1; i++)
	{
		q = q->next;
	}
	//若q==NULL则插入失败!(这里就是指q超出单链表长度)
	/*
	* 例如一个长度为5个结点的单链表,它可插入的位置为1~6
	* 一个长度为0的结点的单链表,它可插入的位置为1
	* 这里只要超出范围都为报插入失败(该代码插入位置0与1等效)
	*/
	if (!q)
	{
		printf("插入失败!\n");
		return;
	}
	List p = (List)malloc(sizeof(Node));	//创建一个结点p,这里为插入结点
	scanf_s("%d", &(p->data));
	p->next = q->next;
	q->next = p;
}

例子:有一个单链表:head -> 1 -> 2 -> 3 -> 4 -> NULL

在3前面插入一个结点9(Insert_Node(head, int 3));

插入后为:head -> 1 -> 2 -> 9 -> 3 -> 4 -> NULL

删除结点

/*
@删除结点
@void Dlete_Node(List,int)
@第一个参数:struct Node * 类型,这里使用的是头结点
@第二个参数:int 类型,这里是指删除第n个结点,取值范围 n >= 1 (n == 0 时 与 n == 1 等效)
@返回值:无
*/
void Delete_Node(List head, int n)
{
	List q = head;//定义一个变量指针q指向head,作用:找到第n个结点的前一位(0与-1等效)
	for (int i = 0; i < n - 1; i++)
	{
		q = q->next;
	}
	//若q==NULL则删除失败!(这里就是指q超出单链表长度)
	/*
	* 例如一个长度为5个结点的单链表,它可删除的位置为1~6
	* 一个长度为0的结点的单链表,它可删除的位置为1
	* 这里只要超出范围都为报删除失败(该代码删除位置0与1等效)
	*/
	if (!(q->next))
	{
		printf("删除失败!\n");
		return;
	}
	List p = q->next;	//定义一个变量指针指向q->next指向的结点,作用:用于将改结点指向NULL并释放
	q->next = p->next;
	p->next = NULL;
	free(p);
}

例子:有一个单链表:head -> 1 -> 2 -> 3 -> 4 -> NULL

想要删除结点3(Delete_Node(head, 3))

删除后:head -> 1 -> 2 -> 4 -> NULL

逆置单链表

/*
@逆置单链表
@第一个参数:struct Node* 类型,这里为单链表的首节点
@返回值:Node * 类型,返回的为头结点位置
*/
List Reserve_List(List head)
{
	//若单链表为空返回head;
	if (!(head->next))
		return head;
	List front = head->next;	//定义一个变量指针,指向首结点(不是头结点!!!)
	List behind = head->next->next;	//定义一个变量指针,指向首结点的后一个位
	while (behind)
	{
		//若为首结点,则令其指向空(因为需要逆置,首结点变为尾结点)
		if (front == head->next)
			front->next = NULL;
		//定义临时变量指针temp,令其为behind的后一位(当behind的重新指向后,能找到重新指向之前的下一个结点)
		List temp = behind->next;
		//令behind重新指向到front(即单链表未逆置前,behind所在结点的前一个结点)
		behind->next = front;
		//令front往后移动
		front = behind;
		//令behind往后移动
		behind = temp;
	}
	//最后令头结点指向front(逆置前的尾结点,逆置后的首结点)
	head->next = front;
	return head;
}

在这里插入图片描述
最终temp和behind都指向NULL,上面动图分开写NULL是为了区分temp与behind在没逆置之前的位置,

实际temp与behind和逆置以后的尾结点所指的NULL是一个东西(一样的!)

打印单链表

/*
@打印单链表
@ void Printf_List(List)
@第一个参数:struct Node * 类型,这里使用的是头结点
@返回值:无
*/
void Printf_List(List head)
{
	List q = head;
	if (!head->next)
	{
		printf("单链表为空,打印失败!\n");
	}
	while (q)
	{
		q = q->next;
		printf("%d ", q->data);
	}
	putchar('\n');
}

主函数(main.c)

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

int main()
{
	List head = Init_Node();
	Build_List(head, 5);
	Insert_Node(head, 4);
	Delete_Node(head, 4);
	Reserve_List(head);
	Printf_List(head);
}
//输入
//1 2 3 4 5(Build_List)
//6(Insert_Node)
//此时为5 4 3 6 2 1
//然后为5 4 3 2 1(Delete_Node)
//最后逆置1 2 3 4 5
//输出
//1 2 3 4 5

以上就是单链表的增删改插,逆置操作,希望对大家有所帮助,若当中存在问题,请大家指出,谢谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值