【数据结构】—— 无头单向不循环链表相关接口实现

一、链表基本概念

1、链表的分类(8种)
  • 单向 | 双向
  • 有头 | 没有头
  • 有循环 | 无循环
  • 可随机组合
2、顺序表与链表的区别

链表与顺序表的区别

3、相关接口介绍
接口功能
void SListInit(SList* plist)初始化链表
void SListDstory(SList* plist)销毁链表
SListNode* BuySListNode(SLTDataType x)创建一个链表节点
void SListPushFront(SList* plist, SLTDataType x)头插
void SListPushBack(SList* plist,SLTDataType x)尾插
void SListPopFront(SList* plist)头删
void SListPopBack(SList* plist)尾删
SListNode* SListFind(SList* plist, SLTDataType x)在链表中查找一个节点
void SListInsertAfter(SListNode* pos, SLTDataType x)在链表pos位置后进行插入
void SListEraseAfter(SListNode* pos)删除链表pos位置之后的节点
void SListRemove(SList* plist, SLTDataType x)根据x的值删除链表中的节点
void SListPrint(SList* plist)打印链表元素
void Listtest1()特殊链表相关接口
4、相关接口的具体实现

1.【创建链表结构体】

  • 定义一个链表结构体,一共存放两个成员
  • 一个存放数据域
  • 一个存放指针域(即指向下一个节点的指针)
	typedef int SLTDataType;
    typedef struct SListNode
    {
    	SLTDataType _data;
    	struct SListNode* _next;
    	
    }SListNode;
    

2.【初始化链表】

  • 初始化链表的思想很简单,只需要让链表中的头结点指向空即可,以防成为野指针
	void SListInit(SList* plist)
    {
    	assert(plist);
    	plist->_head = NULL;
    }

3.【销毁链表】

  • 销毁链表的思想是,遍历整个链表,将节点逐个释放,再将头结点置空
	void SListDstory(SList* plist)
    {
    	assert(plist);
    	SListNode* cur = plist->_head;
    	while (cur != NULL)
    	{
    		SListNode* next = cur->_next;
    		free(cur);//释放节点动态开辟的空间
    		cur = next;
    	}
    	plist->_head = NULL;
    }

4.【打印链表元素】

  • 思路很简单,遍历链表将每个节点中的数据逐个打印即可
    void SListPrint(SList* plist)
    {
    	assert(plist);
    	SListNode* cur = plist->_head;
    	while (cur != NULL)
    	{
    		printf("%d->", cur->_data);
    		cur = cur->_next;
    	}
    	printf("NULL");
    }

5.【创建链表节点】

  • 我们知道链表和顺序表不一样,链表不需要考虑增容的问题,需要插入元素只要开辟一个节点进行插入即可,因此我们需要单独写一个函数进行节点的创建
  • 我们这里的节点是动态开辟的,开辟节点之后,将值赋为x,并让节点的下一个节点指针置空,最后返回这个节点。
  SListNode* BuySListNode(SLTDataType x)
    {
    	SListNode* pnode;
    	pnode = (SListNode*)malloc(sizeof(SListNode));
    	pnode->_data = x;
    	pnode->_next = NULL;
    	return pnode;
    }

6、【头插】

  • 头插思想比较简单,因为我们创建了一个头结点,这里我们只需要申请一个新的节点,让它指向_head节点,再让它成为_head就完成了头插
    头插
   void SListPushFront(SList* plist, SLTDataType x)
    {
    	assert(plist);
    	SListNode* newnode = BuySListNode(x);
    	newnode->_next = plist->_head;
    	plist->_head = newnode;
    }

7、【尾插】
尾插

   void SListPushBack(SList* plist, SLTDataType x)
    {
    	assert(plist);
    	if (plist->_head == NULL)
    	{
    		SListNode* newnode = BuySListNode(x);
    	}
    	else
    	{
    		SListNode* tail = plist->_head;
    		while (tail->_next != NULL)
    		{
    			tail = tail->_next;
    		}
    		SListNode* newtail = BuySListNode(x);
    		tail->_next = newtail;
    	}
    	
    }

8.【头删】

  • 思路很简单,其实链表最大的优势就在于它的头插头删,不仅思路简单而且时间复杂度为O(1)
  • 记录_head的下一个节点,释放_head节点,让next成为_head节点

头删

    void SListPopFront(SList* plist)
    {
    	assert(plist);
    	SListNode* next = plist->_head->_next;
    	free(plist->_head);
    	plist->_head = next;
    }

9.【尾删】
尾删

	void SListPopBack(SList* plist)
    {
    	if (plist->_head->_next == NULL)
    	{
    		free(plist->_head);
    		plist->_head = NULL;
    	}
    	else
    	{
    		SListNode* prev = NULL;
    		SListNode* tail = plist->_head;
    		while (tail->_next != NULL)
    		{
    			prev = tail;
    			tail = tail->_next;
    		}
    		free(tail);
    		prev->_next = NULL;
    	}
    }

10.【查找链表中的元素】

  • 遍历链表查找值为x的节点,找到返回该节点指针
  • 没找到返回空
    SListNode* SListFind(SList* plist, SLTDataType x)
    {
    	assert(plist);
    	SListNode* cur = plist->_head;
    	while (cur->_next != NULL)
    	{
    		if (cur->_data == x)
    			return cur;
    		else
    			cur = cur->_next;
    	}
    	return cur;
    }

11、【在pos后插入元素】

  • 利用Find找到对应的位置,在pos之后插入元素

插入元素

   // 在pos的后面进行插入 
    void SListInsertAfter(SListNode* pos, SLTDataType x)
    {
    	assert(pos);
    	SListNode* newnode = BuySListNode(x);
    	assert(newnode);
    	newnode->_next = pos->_next;
    	pos->_next = newnode;
    }

12.【删除pos之后的元素】

  • 思路很简单,记录pos的下一个节点和pos的下下一个节点,让pos的_next指向nextnext,再释放next节点即可。
    删除pos之后元素
    void SListEraseAfter(SListNode* pos)
    {
    	assert(pos && pos->_next);
    	SListNode* next = pos->_next;
    	SListNode* nextnext = next->_next;
    	
    	pos->_next = nextnext;
    	free(next);
    }

无头单向不循环链表完整代码

单链表相关接口介绍List.h

#define _CRT_SECURE_NO_WARNINGS
#ifndef __LIST_H__
#define __LIST_H__
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType _data;
	struct SListNode* _next;
	
}SListNode;

typedef struct SList
{
	SListNode* _head;
}SList;



void SListInit(SList* plist);
void SListDstory(SList* plist);

SListNode* BuySListNode(SLTDataType x);
void SListPushFront(SList* plist, SLTDataType x);
void SListPushBack(SList* plist,SLTDataType x);
void SListPopFront(SList* plist);
void SListPopBack(SList* plist);

SListNode* SListFind(SList* plist, SLTDataType x);
// 在pos的后面进行插入 
void SListInsertAfter(SListNode* pos, SLTDataType x);
// 在pos的前面进行插入 
void SListEraseAfter(SListNode* pos);
void SListRemove(SList* plist, SLTDataType x);

void SListPrint(SList* plist);
void TestSList();
void SListPopFront(SList* plist);
SListNode* SListFind(SList* plist, SLTDataType x);
// 在pos的后面进行插入 
void SListInsertAfter(SListNode* pos, SLTDataType x);
void SListEraseAfter(SListNode* pos);
void SListRemove(SList* plist, SLTDataType x);

void SListPrint(SList* plist);
void Listtest1();

#endif //__LIST_H__

单链表相关接口的实现List.c

#include"List.h"

void SListInit(SList* plist)
{
	assert(plist);
	plist->_head = NULL;
}

void SListDstory(SList* plist)
{
	assert(plist);
	SListNode* cur = plist->_head;
	while (cur != NULL)
	{
		SListNode* next = cur->_next;
		free(cur);
		cur = next;
	}
	plist->_head = NULL;
}

void SListPrint(SList* plist)
{
	assert(plist);
	SListNode* cur = plist->_head;
	while (cur != NULL)
	{
		printf("%d->", cur->_data);
		cur = cur->_next;
	}
	printf("NULL");
}

SListNode* BuySListNode(SLTDataType x)
{
	SListNode* pnode;
	pnode = (SListNode*)malloc(sizeof(SListNode));
	pnode->_data = x;
	pnode->_next = NULL;
	return pnode;
}

void SListPushFront(SList* plist, SLTDataType x)
{
	assert(plist);
	SListNode* newnode = BuySListNode(x);
	newnode->_next = plist->_head;
	plist->_head = newnode;
}

void SListPushBack(SList* plist, SLTDataType x)
{
	assert(plist);
	if (plist->_head == NULL)
	{
		SListNode* newnode = BuySListNode(x);
	}
	else
	{
		SListNode* tail = plist->_head;
		while (tail->_next != NULL)
		{
			tail = tail->_next;
		}
		SListNode* newtail = BuySListNode(x);
		tail->_next = newtail;
	}
	
}

void SListPopFront(SList* plist)
{
	assert(plist);
	SListNode* next = plist->_head->_next;
	free(plist->_head);
	plist->_head = next;
}
void SListPopBack(SList* plist)
{
	if (plist->_head->_next == NULL)
	{
		free(plist->_head);
		plist->_head = NULL;
	}
	else
	{
		SListNode* prev = NULL;
		SListNode* tail = plist->_head;
		while (tail->_next != NULL)
		{
			prev = tail;
			tail = tail->_next;
		}
		free(tail);
		prev->_next = NULL;
	}
}

SListNode* SListFind(SList* plist, SLTDataType x)
{
	assert(plist);
	SListNode* cur = plist->_head;
	while (cur->_next != NULL)
	{
		if (cur->_data == x)
			return cur;
		else
			cur = cur->_next;
	}
	return cur;
}
// 在pos的后面进行插入 
void SListInsertAfter(SListNode* pos, SLTDataType x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	assert(newnode);
	newnode->_next = pos->_next;
	pos->_next = newnode;
}
// 在pos的前面进行插入 
void SListEraseAfter(SListNode* pos)
{
	assert(pos && pos->_next);
	SListNode* next = pos->_next;
	SListNode* nextnext = next->_next;
	
	pos->_next = nextnext;
	free(next);
}
void SListRemove(SList* plist, SLTDataType x)
{
	assert(plist);
	if (plist->_head->_next==NULL)
	{
		if (plist->_head->_data == x)
			SListPopFront(plist);
		else
			printf("所删除的数不存在!\n");
	}
	else
	{
		SListNode* cur = plist->_head;
		SListNode* prev = plist->_head;
		while (cur->_next != NULL)
		{
			if (cur->_data == x)
			{
				prev->_next = cur->_next;
			}
			else
			{
				cur = cur->_next;
				prev = prev->_next;
			}
				
		}
	}
}

void Listtest1()
{
	SList list;
	SListInit(&list);
	//SListPrint(&list);
	SListPushFront(&list, 1);
	SListPushFront(&list, 2);
	SListPushFront(&list, 3);
	SListPushFront(&list, 4);
	//SListPushBack(&list, 0);
	//SListPopFront(&list);
	//SListPopBack(&list);
	/*SListNode* pos = SListFind(&list, 3);
	printf("%d\n", pos->_data);
	SListInsertAfter(pos, 6);
	SListEraseAfter(pos);*/
	SListRemove(&list, 2);
	SListPrint(&list);
	SListDstory(&list);

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值