数据结构---链表功能全实现(单向+不带头+不循环)

在这里我创建的是单向+不循环+不带头的链表。

首先对数据类型进行重命名:

typdef int SLDatatype;

对链表结点的定义:在链表结点中存放数据,与指向下一个有效空间的指针,如果当前的结点是链表的最后一个结点,则结点中的指针指向NULL,表示链表的结束。

typedef struct SListNode {
	SLDataType	data;
	struct SListNode *next;
}	SListNode;

对链表的创建:在链表的结构体重只存放了指向链表第一个结点的指针,如果没有链表,链表指向NULL。

typedef struct SList {
	struct SListNode *first;
}	SList;

接口实现

初始化
链表的初始化就是对链表中的first进行制空即可。

//初始化
void SListInit(SList *list)
{
	assert(list);
	list->first = NULL;
	return;
}

销毁
链表的销毁就是将在堆上申请到的空间进行释放,然后将链表的first置为空。

//销毁
void SListDestroy(SList *list)
{
	assert(list);
	SListNode *next;
	for (SListNode *cur = list->first; cur != NULL; cur=next)
	{
		next = cur->next;
		free(cur);
	}
	list->first = NULL;
}

构造结点
在进行插入操作时需要动态地从堆上申请一个结点,所以这个接口应该为内部接口。
:在此处动态申请内存失败时,应该对其进行相应的处理,为了方便起见,直接使用断言不允许申请失败,因为这个程序不存在内存申请不到的情况,所以这种方法是可行的。

//构造节点
SListNode *BuySListNode(SLDataType data)
{
	SListNode* node = (SListNode*)malloc(sizeof(SListNode));
	assert(node != NULL);
	node->data = data;
	node->next = NULL;
	return node;
}

基本功能:
增:
头插:
将一个结点插入到第一个位置,就是将first的初始指向当做新结点的next,node的位置就是first的新指向,这样新结点就在头部插入到整个链表中的第一个位置。

//头插
void SListPushFront(SList *list, SLDataType data)
{
	assert(list != NULL);
	SListNode *node = BuySListNode(data);
	node->next = list->first;
	list->first = node;
	return;
}

尾插 :
将一个新结点在最后一个位置插入链表中。需要找到最后一个结点,将最后一个结点的next更改为新结点的位置,新结点的next默认为NULL,所以在尾插操作中不需要在意新结点的next。如果链表中无结点,进行尾插时,可以直接调用头插接口。

//尾插
void SListPushBack(SList *list,SLDataType data)
{
	assert(list != NULL);
	if (list->first == NULL)
	{
		SListPushFront(list,data);
		return;
	}
	//找最后一个节点
	SListNode* cur = list->first;
	for ( ; cur->next != NULL ;cur = cur->next ){}
	SListNode* node = BuySListNode(data);
	cur->next = node;
	return;
}

在pos结点后插入:
在pos结点后插入需要将pos结点的next进行更改,也需要对新结点的next进行更改。
:在进行next的赋值是,先对新结点的next进行更改,然后对pos结点进行更改,这样可以避免将原来的地址丢失。

//在pos节点后插入新节点
void SListInsertAfter(SListNode *pos, SLDataType data)
{
	assert(pos);
	SListNode *node = BuySListNode(data);
	node->next = pos->next;
	pos->next = node;
	return;
}

删:
头删:
删除在链表中的第一个结点。就是将链表的first的指向更改为first->next,然后将原来的第一个结点进行释放。
:在进行释放时必须先记录下,需要释放的地址,一旦进行更改后,原来的地址就不能找到了,所以必须牢记。

//头删
void SListPopFront(SList *list)
{
	assert(list != NULL);
	assert(list->first != NULL);
	SListNode *oldFirst = list->first;
	list->first = list->first->next;
	free(oldFirst);
	return;
}

尾删:
删除链表中最后一个结点。需要找到倒数第二个结点,然后对倒数第二个结点的next进行释放和制空,可以删除最后一个结点。如果在链表中只有一个结点,则尾删就可以调用头删接口。

//尾删
void SListPopBack(SList *list)
{
	assert(list != NULL);
	assert(list->first != NULL);
	if (list->first->next == NULL)
	{
		SListPopFront(list);
	}
	SListNode *cur = list->first;
	//cur找到的是倒数第二个节点,用来删除倒数第一个节点
	for (; cur->next->next != NULL; cur = cur->next)
	{ }
	free(cur->next);
	cur->next = NULL;
	return;
}

删除pos结点的后一个结点:
:不允许链表中只有一个元素进行此操作。
记录pos的next用于释放内存,将pos的next指向pos的next的next,即可删除pos结点的后一个结点。

//删除pos节点后的节点
void SListEraseAfter(SListNode *pos)
{
	assert(pos);
	assert(pos->next != NULL);	//不允许链表中的节点数只有一个进行此操作
	SListNode *old_node = pos->next;
	pos->next = pos->next->next;
	free(old_node);
}

删除第一个遇到的data结点:
如果第一个结点的data值即为需要删除的data,调用头删接口删除即可。否则,就遍历整个链表进行比较,如果遇到相同的data,删除,退出即可。如果一直到NULL仍然没有找到,则没有与data相等的结点,直接返回。

// 删除第一个遇到的 data 结点
void SListRemove(SList *list, SLDataType data)
{
	assert(list);
	SListNode* cur;
	if (list->first->data == data)
	{
		SListPopFront(list);
		return;
	}
	for (cur = list->first; cur != NULL; cur = cur->next)
	{
		if (cur->next->data == data)
		{
			SListNode* old = cur->next;
			cur->next = cur->next->next;
			free(old);
			return;
		}
	}
	return;
}


查找第一个的与data相等的位置。遍历整个链表,找第一个与data值相等的位置,如果找到了返回地址,找不到返回NULL。

//查找第一个找到的数据
SListNode* SListFind(SList* list, SLDataType data)
{
	SListNode* cur = list->first;
	for (cur = list->first; cur != NULL; cur = cur->next)
	{
		if (cur->data == data)
		{
			return cur;
		}
	}
	return NULL;
}

打印
遍历链表打印每个结点的值。

//打印
void SListPrint(SList *list)
{
	assert(list != NULL);
	SListNode *cur = list->first;
	for (cur = list->first; cur != NULL; cur = cur->next)
	{
		printf("%d-->",cur->data);
	}
	printf("NULL\n");
	return;
}

源代码如下
SList.h:

#pragma once
// 单向 + 不循环 + 不带头
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLDataType;

typedef struct SListNode {
	SLDataType	data;
	struct SListNode *next;
}	SListNode;

typedef struct SList {
	struct SListNode *first;
}	SList;

// 初始化/销毁
void SListInit(SList *list);
void SListDestroy(SList *list);

// 增 删 查 改
// 头插
void SListPushFront(SList *list, SLDataType data);

// 头删
void SListPopFront(SList *list);

// 尾插
void SListPushBack(SList *list, SLDataType data);

// 尾删
void SListPopBack(SList *list);

// 查找
// NULL 表示没找到
SListNode * SListFind(SList *list, SLDataType data);

// 在 pos 这个结点后面插入新结点
void SListInsertAfter(SListNode *pos, SLDataType data);

// pos 不是最后一个结点
// 删除 pos 这个结点后面的结点
void SListEraseAfter(SListNode *pos);

// 删除第一个遇到的 data 结点
void SListRemove(SList *list, SLDataType data);

// 打印
void SListPrint(SList *list);

SList.c:

#include "SList.h"

//初始化
void SListInit(SList *list)
{
	assert(list);
	list->first = NULL;
	return;
}

//销毁
void SListDestroy(SList *list)
{
	assert(list);
	SListNode *next;
	for (SListNode *cur = list->first; cur != NULL; cur=next)
	{
		next = cur->next;
		free(cur);
	}
	list->first = NULL;
}

//构造节点
SListNode *BuySListNode(SLDataType data)
{
	SListNode* node = (SListNode*)malloc(sizeof(SListNode));
	assert(node != NULL);
	node->data = data;
	node->next = NULL;
	return node;
}

//增删查改

//头插
void SListPushFront(SList *list, SLDataType data)
{
	assert(list != NULL);
	SListNode *node = BuySListNode(data);
	node->next = list->first;
	list->first = node;
	return;
}

//头删
void SListPopFront(SList *list)
{
	assert(list != NULL);
	assert(list->first != NULL);
	SListNode *oldFirst = list->first;
	list->first = list->first->next;
	free(oldFirst);
	return;
}

//尾插
void SListPushBack(SList *list,SLDataType data)
{
	assert(list != NULL);
	if (list->first == NULL)
	{
		SListPushFront(list,data);
		return;
	}
	//找最后一个节点
	SListNode* cur = list->first;
	for ( ; cur->next != NULL ;cur = cur->next ){}
	SListNode* node = BuySListNode(data);
	cur->next = node;
	return;
}

//尾删
void SListPopBack(SList *list)
{
	assert(list != NULL);
	assert(list->first != NULL);
	if (list->first->next == NULL)
	{
		SListPopFront(list);
	}
	SListNode *cur = list->first;
	//cur找到的是倒数第二个节点,用来删除倒数第一个节点
	for (; cur->next->next != NULL; cur = cur->next)
	{ }
	free(cur->next);
	cur->next = NULL;
	return;
}

//在pos节点后插入新节点
void SListInsertAfter(SListNode *pos, SLDataType data)
{
	assert(pos);
	SListNode *node = BuySListNode(data);
	node->next = pos->next;
	pos->next = node;
	return;
}

//删除pos节点后的节点
void SListEraseAfter(SListNode *pos)
{
	assert(pos);
	assert(pos->next != NULL);	//不允许链表中的节点数只有一个进行此操作
	SListNode *old_node = pos->next;
	pos->next = pos->next->next;
	free(old_node);
}

//查找第一个找到的数据
SListNode* SListFind(SList* list, SLDataType data)
{
	SListNode* cur = list->first;
	for (cur = list->first; cur != NULL; cur = cur->next)
	{
		if (cur->data == data)
		{
			return cur;
		}
	}
	return NULL;
}

// 删除第一个遇到的 data 结点
void SListRemove(SList *list, SLDataType data)
{
	assert(list);
	SListNode* cur;
	if (list->first->data == data)
	{
		SListPopFront(list);
		return;
	}
	for (cur = list->first; cur != NULL; cur = cur->next)
	{
		if (cur->next->data == data)
		{
			SListNode* old = cur->next;
			cur->next = cur->next->next;
			free(old);
			return;
		}
	}
	return;
}

//打印
void SListPrint(SList *list)
{
	assert(list != NULL);
	SListNode *cur = list->first;
	for (cur = list->first; cur != NULL; cur = cur->next)
	{
		printf("%d-->",cur->data);
	}
	printf("NULL\n");
	return;
}

测试用例:main.c
该测试用例只供参考

#include "SList.h"

void test()
{
	SList slist;
	SListInit(&slist);
	SListPushFront(&slist, 0);
	SListPushFront(&slist, 1);
	SListPushFront(&slist, 2);
	SListPushFront(&slist, 3);
	SListPrint(&slist);

	SListPushBack(&slist, 1);
	SListPushBack(&slist, 2);
	SListPushBack(&slist, 3);
	SListPrint(&slist);
#if 0 
	SListPopFront(&slist);
	SListPopFront(&slist);
	SListPrint(&slist);

	SListPopBack(&slist);
	SListPopBack(&slist);
	SListPrint(&slist);

	SListNode* node1 = SListFind(&slist,0);
	SListInsertAfter(node1, 5);
	SListPrint(&slist);

	SListEraseAfter(node1);
	SListPrint(&slist);

	SListNode* node2 = SListFind(&slist, 1);
	SListInsertAfter(node2, 5);
	SListInsertAfter(node2, 5);
	SListPrint(&slist);
#endif
	SListRemove(&slist, 3);
	SListPrint(&slist);
	SListDestroy(&slist);
}

int main()
{
	test();
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值