目录
单链表
链式结构是一种重要的存储结构,学习单链表的实现可以帮助我们理解链式结构的意义。
特别注意,节点的本质是一块指针指向的空间,因此想要改变节点,必须使用双指针形参,这样才可以在函数中改变节点。
SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
// Single List
typedef struct SListNode
{
SLNDataType val;
struct SListNode* next;
}SLNode;
void SLTPrint(SLNode* phead);
void SLTPushBack(SLNode** pphead, SLNDataType x);
void SLTPushFront(SLNode** pphead, SLNDataType x);
void SLTPopBack(SLNode** pphead);
void SLTPopFront(SLNode** pphead);
SLNode* SLTFind(SLNode* phead, SLNDataType x);
// posǰ
SLNode* SLTInsert(SLNode** pphead, SLNode* pos, SLNDataType x);
// ɾposλ
void SLTErase(SLNode** pphead, SLNode* pos);
void SLTDestroy(SLNode** pphead);
SList.c
1.打印链表(SLTPrint)
void SLTPrint(SLNode* phead)
{
SLNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->val);
cur = cur->next;
}
printf("NULL\n");
}
2.创建节点(SLTCreatNode)
SLTNode* SLTCreatNode(SLTDataType x)
{
SLNode* newnode = (SLNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail!");
exit(1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
3.链表尾插 (SLTPushBack)
void SLTPushBack(SLNode** pphead, SLNDataType x)
{
SLNode* newnode = SLTCreateNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
// 找尾
SLNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
4.链表头插 (SLTPushFront)
void SLTPushFront(SLNode** pphead, SLNDataType x)
{
SLNode* newnode = SLTCreateNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
5.链表尾删 (SLTPopBack)
void SLTPopBack(SLNode** pphead)
{
assert(*pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLNode* tail = *pphead;
while (tail->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
}
6.链表头删 (SLTPopFront)
void SLTPopFront(SLNode** pphead)
{
assert(*pphead);
SLNode* tmp = *pphead;
free(tmp);
*pphead = (*pphead)->next;
}
7.查找结点 (SLTFind)
SLTNode* SLTFind(SLNode* phead, SLTDataType x)
{
SLNode* pcur = phead;
while (pcur)//等价于pcur != NULL
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
//pcur == NULL
return NULL;
}
8.指定插入节点 (SLTInsert)
//在指定位置之前插入数据
void SLTInsert(SLNode** pphead, SLNode* pos, SLTDataType x)
{
assert(pphead && *pphead);
assert(pos);
SLNode* newnode = SLTCreatNode(x);
//若pos == *pphead;说明是头插
if (pos == *pphead)
{
SLTPushFront(pphead, x);
}
else {
SLNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;//这里相当于需要找到pos之前的指针
}
//prev -> newnode -> pos
newnode->next = pos;
prev->next = newnode;
}
}
9.指定删除节点 (SLTErase)
void SLTErase(SLNode** pphead, SLNode* pos)
{
assert(pphead && *pphead);
assert(pos);
//pos是头结点/pos不是头结点
if (pos == *pphead)
{
//头删
SLTPopFront(pphead);
}
else {
SLNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//prev pos pos->next
prev->next = pos->next;
free(pos);
pos = NULL;
}
}
10.链表销毁 (SLTDestroy)
//销毁链表
void SListDesTroy(SLNode** pphead)
{
assert(pphead && *pphead);
SLNode* pcur = *pphead;
while (pcur)
{
SLNode* next = pcur->next;
free(pcur);
pcur = next;
}
//pcur
*pphead = NULL;
}