在这里我创建的是单向+不循环+不带头的链表。
首先对数据类型进行重命名:
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;
}