Ta 给我留了地址——链表的基础实现

目录

一、起始设置 

二、函数实现

1. 创造节点

2. 打印链表

3. 尾插尾删

4. 头插头删

5. 查找

6. 插入(前插)和删除

7. 后插和后删

8. 销毁链表

三、代码汇总

1. SList.c

2. SList.c

3. test.c


链表的本质:通过一个个的节点来记录数据,并且通过下一个节点的地址来找到下一个节点

一、起始设置 

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLT;

二、函数实现

这里对于指针的应用非常灵活,需要补充一部分【指针知识】

1) 因为在传参的时候,我们传的都是第一个节点的指针,所以形参是一级指针的时候就只是一份临时拷贝,函数内的操作不改变原来的链表

2) 而如果是头插头删、尾插尾删等需要改变实参的函数,就需要传二级指针,二级指针就是指针的指针,也就是用来存放指针的地址的玩意

void SListPrint(SLT* plist);
SLT* SListFind(SLT* plist, SLTDataType x);
void SListDestroy(SLT** pphead);

void SListPushBack(SLT** plist, SLTDataType x);
void SListPushFront(SLT** plist, SLTDataType x);
void SListPopBack(SLT** plist);
void SListPopFront(SLT** plist);

void SListInsert(SLT** pphead, SLT* pos, SLTDataType x);
void SLTErase(SLT** pphead, SLT* pos);
void SLTInsertAfter(SLT* pos, SLTDataType x);
void SLTEraseAfter(SLT* pos);

以上函数都是放在头文件中的,还有一个只在源文件中,就是创造节点的函数,因为它只在同一文件的函数使用

1. 创造节点

SLT* CreateSListNode(SLTDataType x)
{
	SLT* newNode = (SLT*)malloc(sizeof(SLTDataType));
	if (newNode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}

2. 打印链表

void SListPrint(SLT* plist)
{
	assert(plist);
	while (plist)
	{
		printf("%d ", plist->data);
		plist = plist->next;
	}
}

尾插尾删、头插头删这类的函数最好画图进行分析,其实本质上思路很简单

3. 尾插尾删

这部分了解即可,因为效率太低(需要找到尾),一般不用

void SListPushBack(SLT** plist, SLTDataType x)
{
	SLT* newNode = CreateSListNode(x);

	if (*plist == NULL)
	{
		*plist = newNode;
		(*plist)->next = NULL;
	}
	else
	{
		SLT* tail = *plist;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newNode;
	}
}


void SListPopBack(SLT** plist)
{
	assert(*plist);

	if ((*plist)->next == NULL)
	{
		free(*plist);
		*plist = NULL;
	}
	else
	{
		SLT* tail = *plist;
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

4. 头插头删

相比之下,头插头删是相对高效的,也是我们常用的

void SListPushFront(SLT** plist, SLTDataType x)
{
	SLT* newNode = CreateSListNode(x);
	newNode->next = *plist;
	*plist = newNode;
}

void SListPopFront(SLT** plist)
{
	assert(*plist);
	SLT* tmp = *plist;
	*plist = (*plist)->next;
	free(tmp);//此处是否将tmp置空都可以,因为出了此函数就会被销毁
}

5. 查找

SLT* SListFind(SLT* plist, SLTDataType x)
{
	assert(plist);

	SLT* cur = plist;
	while (cur)
	{
		if (cur->data == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

6. 插入(前插)和删除

注意:插入的是pos的前一个位置

void SListInsert(SLT** pphead, SLT* pos, SLTDataType x)
{
	assert(pos);
	assert((*pphead && pos) || (!(*pphead) && !pos));

	if (*pphead == pos)
	{
		SListPushFront(pphead, x);
	}
	else
	{
		SLT* newNode = CreateSListNode(x);
		SLT* cur = *pphead;
		while (cur->next != pos)
		{
			cur = cur->next;
		}
		newNode->next = pos;
		cur->next = newNode;
	}

}

void SLTErase(SLT** pphead, SLT* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);

	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	else
	{
		SLT* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;

		free(pos);
		pos = NULL;
	}
}

7. 后插和后删

void SLTInsertAfter(SLT* pos, SLTDataType x)
{
	assert(pos);
	SLT* newNode = CreateSListNode(x);

	newNode->next = pos->next;
	pos->next = newNode;

}

void SLTEraseAfter(SLT* pos)
{
	assert(pos);
	assert(pos->next);

	SLT* tmp = pos->next;
	pos->next = tmp->next;
	free(tmp);
	tmp = NULL;
}

8. 销毁链表

void SListDestroy(SLT** pphead)
{
	assert(pphead);
	assert(*pphead);

	SLT* tmp = *pphead;
	SLT* next = NULL;
	while (tmp != NULL)
	{
		next = tmp->next;
		free(tmp);
		tmp = next;
	}
	*pphead = NULL;
}

三、代码汇总

总共有三个文件SList.c/SList.h/test.c,test.c可以随意调试

1. SList.c

#pragma once
#include 
#include 
#include 

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLT;


void SListPrint(SLT* plist);

void SListPushBack(SLT** plist, SLTDataType x);

void SListPushFront(SLT** plist, SLTDataType x);

void SListPopBack(SLT** plist);

void SListPopFront(SLT** plist);

SLT* SListFind(SLT* plist, SLTDataType x);

void SListInsert(SLT** pphead, SLT* pos, SLTDataType x);

void SLTErase(SLT** pphead, SLT* pos);

void SLTInsertAfter(SLT* pos, SLTDataType x);

void SLTEraseAfter(SLT* pos);

void SListDestroy(SLT** pphead);

2. SList.c

#include "SList.h"

SLT* CreateSListNode(SLTDataType x)
{
	SLT* newNode = (SLT*)malloc(sizeof(SLTDataType));
	if (newNode == NULL)
	{
		perror("malloc");
		exit(-1);
	}
	newNode->data = x;
	newNode->next = NULL;
	return newNode;
}


void SListPrint(SLT* plist)
{
	assert(plist);
	while (plist)
	{
		printf("%d ", plist->data);
		plist = plist->next;
	}
}

void SListPushBack(SLT** plist, SLTDataType x)
{
	SLT* newNode = CreateSListNode(x);

	if (*plist == NULL)
	{
		*plist = newNode;
		(*plist)->next = NULL;
	}
	else
	{
		SLT* tail = *plist;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newNode;
	}
}

void SListPushFront(SLT** plist, SLTDataType x)
{
	SLT* newNode = CreateSListNode(x);
	newNode->next = *plist;
	*plist = newNode;
}


void SListPopBack(SLT** plist)
{
	assert(*plist);

	if ((*plist)->next == NULL)
	{
		free(*plist);
		*plist = NULL;
	}
	else
	{
		SLT* tail = *plist;
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

void SListPopFront(SLT** plist)
{
	assert(*plist);
	SLT* tmp = *plist;
	*plist = (*plist)->next;
	free(tmp);
}

SLT* SListFind(SLT* plist, SLTDataType x)
{
	assert(plist);

	SLT* cur = plist;
	while (cur)
	{
		if (cur->data == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

void SListInsert(SLT** pphead, SLT* pos, SLTDataType x)
{
	assert(pos);
	assert((*pphead && pos) || (!(*pphead) && !pos));

	if (*pphead == pos)
	{
		SListPushFront(pphead, x);
	}
	else
	{
		SLT* newNode = CreateSListNode(x);
		SLT* cur = *pphead;
		while (cur->next != pos)
		{
			cur = cur->next;
		}
		newNode->next = pos;
		cur->next = newNode;
	}

}

void SLTErase(SLT** pphead, SLT* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);

	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	else
	{
		SLT* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;

		free(pos);
		pos = NULL;
	}
}

void SLTInsertAfter(SLT* pos, SLTDataType x)
{
	assert(pos);
	SLT* newNode = CreateSListNode(x);

	newNode->next = pos->next;
	pos->next = newNode;

}

void SLTEraseAfter(SLT* pos)
{
	assert(pos);
	assert(pos->next);

	SLT* tmp = pos->next;
	pos->next = tmp->next;
	free(tmp);
	tmp = NULL;
}

void SListDestroy(SLT** pphead)
{
	assert(pphead);
	assert(*pphead);

	SLT* tmp = *pphead;
	SLT* next = NULL;
	while (tmp != NULL)
	{
		next = tmp->next;
		free(tmp);
		tmp = next;
	}
	*pphead = NULL;
}

3. test.c(不具备参考价值,可自行调试)

#include "SList.h"

void Test()
{
	SLT* psl = NULL;

	SListPushBack(&psl, 1);
	SListPushBack(&psl, 2);
	SListPushBack(&psl, 3);
	

	SLT* pos = SListFind(psl, 2);
	SLT* pos2 = SListFind(psl, 3);

	SListInsert(&psl, pos, 99);
	SListPrint(psl);
	printf("\n");
	SLTErase(&psl, pos);
	SLTInsertAfter(pos2, 666);
	SListPrint(psl);
	printf("\n");

	SLTEraseAfter(pos2);

	SListPrint(psl);
	SListDestroy(&psl);
}

int main()
{
	Test();
	return 0;
}

你可能感兴趣的:(链表,数据结构,c语言,c++)