链表的实现

发布于:2024-07-05 ⋅ 阅读:(13) ⋅ 点赞:(0)

1.构造结构体,创建结点

这里重命名int是为了适应多种情况,若存的数据类型是char只需要改一个地方就行

结构体内容是数据与下一个结点的地址

SLTNode是结构体重命名后的名字

typedef int SLTDataType;
typedef struct SListNode {
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

2.尾插的实现

尾插先判断链表是否为空,若为空就直接把得到的新节点作为头结点

下面为创建结点的函数,避免重复写创建结点的代码

SLTNode* BuyNode(SLTDataType x)
{
	SLTNode* tmp = (SLTNode*)malloc(sizeof(SLTNode));
	if (tmp == NULL)
	{
		perror("malloc fail:");
		return NULL;
	}
	tmp->data = x;
	tmp->next = NULL;
	return tmp;
}

若链表不为空,就去找尾结点的位置,这里设置cur是避免用*pphead后找不到头的位置,若cur的next不为空就一直往下一个结点走,直到走到最后一个,再把新的结点接上 

//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = BuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* cur = *pphead;
		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}

}

3.头插的实现

先判断链表是否为空,如果不为空就把头指针指向新结点就完成了

//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = BuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		newnode->next = *pphead;
		*pphead = newnode;
	}

}

4.尾删的实现

先判断链表是否为空,为空就直接free头结点,不为空就要去找尾结点,但是不仅要尾结点,还需要尾结点的前一个结点,因为链表的最后一个结点的next是要指向NULL,free了尾结点,倒数第二个结点成为尾结点,但是它的next是指向free的那个结点(因为free只会释放结点的空间,指向还是那个空间,只是没有权限访问),所以需要找倒数第一和第二的结点位置

//尾删
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* next = *pphead;
		SLTNode* cur = *pphead;
		while (cur->next)
		{
			next = cur;
			cur=cur->next;
		}
		free(cur);
		cur = NULL;
		next->next = NULL;
	}
}

5.头删的实现

先判断链表是否为单个,若为单个就直接free,不为单个就先设置一个变量来存储头结点的下一个结点的位置,然后free头结点,在把头指针指向存储的变量

//头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* cur = (*pphead)->next;
		free(*pphead);
		*pphead = cur;
	}
}

6.查找的实现

查找就是对比数据data是否一样,就是遍历链表就完成

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	assert(phead);
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

7.在指定的位置前插入数据

在指定的位置之前插入需要找到指定结点的前一个结点位置,当while循环结束后,cur的下一个结点就是指定的结点,只需要把新结点的next接到pos上(一个结点可以被多个指针指),然后把cur的下一个指向newnode新结点就完成了

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	SLTNode* newnode = BuyNode(x);
	SLTNode* cur = *pphead;
	while (cur->next != pos)
	{
		cur = cur->next;
	}
	newnode->next = pos;
	cur->next = newnode;
}

8.在指定的位置之后插入数据

需要把新结点的下一个接到pos的下一个结点上,然后把pos的下一个接到新结点上

//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = BuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

9.删除pos结点

删除一个结点需要找到删除的结点以及其前一个结点,因为要把删除的结点和删除结点的下一个结点接起来

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);
	SLTNode* cur = *pphead;
	while (cur->next != pos)
	{
		cur = cur->next;
	}
	cur->next = pos->next;
	free(pos);
	pos = NULL;

}

10.删除pos之后的结点

删除pos之后的结点需要把pos的next与删除的next的结点连接起来

//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	SLTNode* cur = pos->next;
	pos->next = cur->next;
	free(cur);
	cur = NULL;
}

11.销毁链表

先设置俩个变量,一个用来free,一个来遍历,直至把链表都删完

//销毁链表
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* cur = *pphead;
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

12.总代码

test.c

#include"SList.h"



int main()
{
	SLTNode* s;
	s = NULL;
	SLTPushBack(&s, 1);
	SLTPushBack(&s, 2);
	SLTPushBack(&s, 3);
	SLTPushBack(&s, 4);
	SLTPushBack(&s, 5);
	SLTPushBack(&s, 6);
	SLTNode* cur=SLTFind(s, 2);
	SLTInsert(&s, cur, 33);
	SLTInsertAfter(cur, 44);
	SLTPushFront(&s, 11);
	//SLTPopFront(&s);
	//SLTPopBack(&s);
	//SLTErase(&s, cur);
	//SLTEraseAfter(cur);


	SLTPrint(s);
	
	return 0;
}

SList.h

#pragma once
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//定义节点的结构
//数据 + 指向下一个节点的指针
typedef int SLTDataType;
typedef struct SListNode {
	SLTDataType data;
	struct SListNode* next;
}SLTNode;
void SLTPrint(SLTNode* phead);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//尾删
void SLTPopBack(SLTNode** pphead);
//头删
void SLTPopFront(SLTNode** pphead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);

SList.c

#include"SList.h"

void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
}
SLTNode* BuyNode(SLTDataType x)
{
	SLTNode* tmp = (SLTNode*)malloc(sizeof(SLTNode));
	if (tmp == NULL)
	{
		perror("malloc fail:");
		return NULL;
	}
	tmp->data = x;
	tmp->next = NULL;
	return tmp;
}
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = BuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* cur = *pphead;
		while (cur->next)
		{
			cur = cur->next;
		}
		cur->next = newnode;
	}

}
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = BuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		newnode->next = *pphead;
		*pphead = newnode;
	}

}
//尾删
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* next = *pphead;
		SLTNode* cur = *pphead;
		while (cur->next)
		{
			next = cur;
			cur=cur->next;
		}
		free(cur);
		cur = NULL;
		next->next = NULL;
	}
}
//头删
void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* cur = (*pphead)->next;
		free(*pphead);
		*pphead = cur;
	}
}

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
	assert(phead);
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	SLTNode* newnode = BuyNode(x);
	SLTNode* cur = *pphead;
	while (cur->next != pos)
	{
		cur = cur->next;
	}
	newnode->next = pos;
	cur->next = newnode;
}
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = BuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);
	SLTNode* cur = *pphead;
	while (cur->next != pos)
	{
		cur = cur->next;
	}
	cur->next = pos->next;
	free(pos);
	pos = NULL;

}
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	SLTNode* cur = pos->next;
	pos->next = cur->next;
	free(cur);
	cur = NULL;
}

//销毁链表
void SListDesTroy(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* cur = *pphead;
	while (cur)
	{
		SLTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}


网站公告

今日签到

点亮在社区的每一天
去签到