数据结构----链表快速入门(链表的简单操作)

链表

什么是链表?

那么接下来呢,小编就用自己“清新超俗”的话来谈谈小编对链表的理解。

链表就是逻辑上连续,物理存储上不连续的一种数据结构,其以结点为单位存储数据。

为了简单快速的了解什么是链表,可以将链表与数组进行对比,数组是内存上的一段连续的存储空间,而链表,只要将它想成是数组的每个元素都被打散即可(当然这只是简单地指出了数组与链表的最大的区别而已)。

其中,结构体中包含两个元素:其一是存放的数据,其二是一个结构体指针变量,存放的是下一个节点的地址。

 了解了链表的结构以后,接下来就是对链表进行操作了,常见的操作有增、删、改、查。接下来我们就用代码实现这些操作。

链表的基本操作(接口):

1.初始化:让其中结点的数目为空,即让头节点指向空。

头节点都指向空了,什么都没有!!!

2.插入

(1)头插

无论链表是不是空,操作均是四步走:

①先申请新空间(要插入当然得有空间了,不然我住哪?对吧。)

②赋值:数据域进行赋值

③连接链表

有两种情况:

a).链表为空时。

未插入前head指向NULL。

b).链表不为空时。

(2)尾插:道理一样

①分配内存

②遍历找到尾结点

③连接链表

同样分链表为空和不为空

1)链表为空时

2)链表不为空时

以下的以此类推:

3.删除

(1)头删

①先记录下头结点的位置 

②再将头结点指向它的下一个结点(此时头节点就是原来链表的第二个节点)

③再释放原来头节点的内存

(2)尾删

①先遍历找到尾结点的前一个结点 

②再利用一个变量将尾结点记录下来

③再释放尾结点的空间

④再将尾节点的前一个结点的next指向NULL(即更新了尾结点)

4.查找

遍历整个链表即可

5.销毁

遍历整个链表

两个遍历指针,第一个指向头节点,第二个指向头节点的下一个节点,将前一个结点的内存再释放即可。

最后,要让原来的头节点指向空。

话不多说,上代码!!!

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

//链表:
typedef struct Node
{
	int data;
	struct Node *next;
}Node;

//1.链表的初始化:没有结点。
void NodeInit(Node **head)
{
	*head = NULL;
}

//插入操作:头插与尾插

//(1).头插
void NodeInsertFront(Node **head,int data)
{
	//首先分配内存
	//进行数据赋值
	//链表的连接:1.将该节点的next指向原来的头节点
	//			  2.再将原来的头节点指向该节点
	Node *node = (Node*)malloc(sizeof(Node));	//首先进行内存的分配
	assert(node != NULL);	//判断内存是否分配成功

	node->data = data;
	node->next = *head;
	*head = node;
	//printf("%p\n", *head);
}

//(2).尾插
void NodeInsertTail(Node **head, int data)
{
	//首先分配内存
	//在进行数据的赋值
	//将链表连接起来:1.将原来的头节点指向该节点
	//				  2.再将该节点的next指向NULL
	Node *node = (Node*)malloc(sizeof(Node));
	assert(node != NULL);
	//如果链表为空
	if (*head == NULL)
	{
		*head = node;
		node->data = data;
		node->next = NULL;
		return;
	}
	//链表不为空:
	//先遍历,找到尾结点,再进行链表的连接
	else {
		Node *cur = *head;
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		node->data = data;
		cur->next = node;
		node->next = NULL;
		return;
	}	
}

//(3).在值为pos的结点后插入
void NodeInsertPos(Node** head, int pos, int data)
{
	//先判空
	Node *node = *head;
	//if (node == NULL)
	//{
	//	//进行尾插
	//	NodeInsertTail(*head, data);
	//	return;
	//}
	//链表非空,先遍历,在进行插入
	while (node != NULL)
	{
		if (node->data == pos)
		{
			Node *tem = (Node *)malloc(sizeof(Node));
			assert(tem != NULL);
			tem->data = data;
			tem->next = node->next;
			node->next = tem;
			return;
		}
		else node = node->next;
	}
}

//2.删除操作:头删、尾删
//(1).头删:
void NodeDeleteFront(Node **head)
{
	//先将head指向下一个
	//再将第一个结点的内存进行释放
	//判空
	if (*head == NULL)
	{
		return;
	}
	Node* node = *head;
	*head = (*head)->next;
	free(node);
	return;
}

//(2).尾删
void NodeDeleteTail(Node **head)
{
	//先进行遍历找到倒数第二个结点
	//再将倒数第二个结点的next指向空即可
	
	//先进行判空
	Node *node = *head;
	if (*head == NULL)
	{
		printf("链表为空,无法删除!!!\n");
		return;
	}
	//遍历找到倒数第二个节点
	while (node->next->next != NULL)
	{
		node = node->next;
	}
	Node *temp = node->next;
	free(temp);
	node->next = NULL;
}

//(3).删除值为data的结点
void NodeDeleteData(Node** head, int data)
{
	//先进行判空
	if (*head == NULL)
	{
		printf("链表为空,无法删除!!!\n");
		return;
	}
	//再遍历查找值为data的结点的前驱结点
	Node *node = *head;
	while (node != NULL)
	{
		//找到了,进行删除:
		//创建临时变量记录该节点
		//连接链表
		//再将该节点的内存释放
		//目标结点是第一个结点
		if (node->data == data)
		{
			//进行头删操作
			Node* tem = *head;
			*head = (*head)->next;
			free(tem);
			return;
			//NodeDeleteFront(*head);
		}
		 if (node->next->data == data)
		{
			Node *temp = node->next;
			node->next = node->next->next;
			free(temp);
			return;
		}
		else node = node->next;
	}
}

//3.查找操作:
//查找值为data的结点
Node * NodeFind(Node **head, int data)
{
	//先进行判空
	if (*head == NULL)
	{
		return NULL;
	}
	//链表非空
	Node *node = *head;
	while (node != NULL)
	{
		if (node->data == data)
		{
			printf("找到该数!!!\n");
			return node;
		}
		else node = node->next;
	}
	if (node == NULL)
	{
		printf("查无此数!!!\n");
		return NULL;
	}
}

//4.链表的销毁
void NodeDestroy(Node** head)
{
	//先进行判空

	Node *node = *head;
	*head = NULL;
	head = NULL;
	if (node == NULL)
	{
		printf("链表为空!!!\n");
		return;
	}
	while (node != NULL)
	{
		//先将结点指到下一个位置,再释放当前位置的内存
		Node *temp = node;
		if (node->next != NULL) {
			node = node->next;
		}
		else {
			node = NULL;
		}
		free(temp);	
	}
	printf("链表已销毁!!!\n");
	return;
}



//5.打印链表
void NodePrint(Node *head)
{
	Node *node = head;
	if (node == NULL)
	{
		printf("链表为空!!!\n");
	}
	while (node != NULL)
	{
		printf("%-3d ", node->data);
		node = node->next;
	}
}



int main()
{
	Node *head ;
	NodeInit(&head);
	NodeInsertFront(&head, 10);
	NodeInsertFront(&head, 20);
	NodeInsertFront(&head, 30);
	NodeInsertFront(&head, 40);
	NodeInsertTail(&head, 15);
	//NodeDeleteFront(&head);
	//NodeDeleteTail(&head);
	//NodeDeleteData(&head, 40);
	//NodeInsertPos(&head, 20, 25);
	Node *pos = NodeFind(&head,20);
	//NodeDestroy(&head);
	NodePrint(head);
	system("pause");
	return 0;
}

注意:无论进行什么操作,对链表判空是一件很重要的事!

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值