1. 什么是单链表
单链表是逻辑上连续,但是在物理存储结构上非连续、非顺序的存储结构。单链表实际上是用他们内部的的指针链接起来的。
- 顺序表只需要一个指针指向一个大空间,其数据和空间都是连续的。
- 单链表则是一个指针指向头部,其他的数据依次在头部后面用指针进行链接。其空间并不是连续的。
2. 单链表的模拟实现
2.1 slink.h 头文件的包含和函数声明
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLTDataType;
#define STLp (STLNode*)
typedef struct SlistNode
{
SLTDataType data;
struct SlistNode* next;
}STLNode;
//打印链表
void SlistPrint(STLNode* phead);
//列表判空
STLNode* CheckNull(SLTDataType x);
//尾插
void SlistPushBack(STLNode** pphead, SLTDataType x);
//头插
void SlistPushFront(STLNode** pphead, SLTDataType x);
//头删
void SlistPopFront(STLNode** pphead);
//尾删
void SlistPopBack(STLNode** pphead);
//查找
STLNode* SlistFind(STLNode* phead,SLTDataType x);
//插入
void SlistInsert(STLNode** phead, STLNode* pos, SLTDataType x);
void SlistAfterInsert(STLNode* pos, SLTDataType x);
//删除
void SlistErase(STLNode** pphead, STLNode* pos);
void SListEraseAfter(STLNode* pos);
2.2 slink.c 函数功能声明
#define _CRT_SECURE_NO_WARNINGS 1
#include"slink.h"
//打印链表
void SlistPrint(STLNode* phead)
{
//assert(phead);
STLNode* cur = phead;
while (cur != NULL)
{
printf("%d-->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
//判空处理
STLNode* CheckNull(SLTDataType x)
{
STLNode* newnode = STLp malloc(sizeof(STLNode));
assert(newnode);
newnode->data = x;
newnode->next = NULL;
return newnode;
}
//尾插
void SlistPushBack(STLNode** pphead, SLTDataType x)
{
assert(pphead);
STLNode* newnode = CheckNull(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
STLNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
//头插
void SlistPushFront(STLNode** pphead, SLTDataType x)
{
//关于为什么是二级指针,因为要更新成新的头结点,只要调整头结点,就必须传头结点的地址。
//**pphead是二级指针,二级指针存的是(STLNode *n1)的地址,*pphead就是n1。n1也是一个指针,它的值是一个地址,他的初始值是NULL。
//当头插成功后,会将newnode中的值(地址)赋给n1,此时n1由指向NULL变成指向新的内存空间地址。
assert(pphead);
STLNode* newnode = CheckNull(x);
newnode->next = *pphead;
*pphead = newnode; //*pphead = n1
}
//头删
void SlistPopFront(STLNode** pphead)
{
assert(pphead);
STLNode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
//尾删
void SlistPopBack(STLNode** pphead)
{
assert(pphead);
assert(*pphead);
//只有一个结点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
STLNode* tail = *pphead;
while (tail->next->next != NULL)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
//STLNode* tail = *pphead;
//STLNode* oldtail = NULL;
//while (tail->next != NULL)
//{
// oldtail = tail;
// tail = tail->next;
//}
//free(tail);
//tail = NULL;
//oldtail->next = NULL;
}
}
//查找和修改
STLNode* SlistFind(STLNode* phead, SLTDataType x)
{
STLNode* cur = phead;
while (cur != NULL)
{
if (cur->data == x)
return cur;
cur = cur->next;
}
}
//前置插入
void SlistInsert(STLNode** pphead, STLNode* pos, SLTDataType x)
{
assert(pos);
assert(pphead);
if (pos == *pphead)
{
SlistPushFront(pphead, x);
}
else
{
STLNode* newnode = CheckNull(x);
STLNode* prve = *pphead;
while (prve->next != pos)
{
prve = prve->next;
}
prve->next = newnode;
newnode->next = pos;
}
}
//前置删除
void SlistErase(STLNode** pphead, STLNode* pos)
{
assert(pphead);
assert(pos);
if (*pphead == pos)
{
SlistPopFront(pphead);
}
else
{
STLNode* prve = *pphead;
while (prve->next != pos)
{
prve = prve->next;
}
prve->next = pos->next;
free(pos);
}
}
//后置插入
void SlistAfterInsert(STLNode* pos, SLTDataType x)
{
assert(pos);
STLNode* newnode = CheckNull(x);
newnode->next = pos->next;
pos->next = newnode;
}
//后置删除
void SListEraseAfter(STLNode* pos)
{
assert(pos);
if (pos == NULL)
return;
STLNode* del = pos->next;
//pos->next = pos->next->next;
pos->next = del->next;
free(del);
del = NULL;
}
2.3 test.c 函数功能测试
#define _CRT_SECURE_NO_WARNINGS 1
#include"slink.h"
void TestList1()
{
int a = 5;
STLNode* n1 = STLp malloc(sizeof(STLNode));
assert(n1);
STLNode* n2 = STLp malloc(sizeof(STLNode));
assert(n2);
STLNode* n3 = STLp malloc(sizeof(STLNode));
assert(n3);
STLNode* n4 = STLp malloc(sizeof(STLNode));
assert(n4);
n1->data = 1;
n2->data = 2;
n3->data = 3;
n4->data = 4;
n1->next = n2;
n2->next = n3;
n3->next = n4;
n4->next = NULL;
SlistPushBack(n1, 6);
SlistPrint(n1);
}
void TestList2()
{
STLNode* n1 = NULL;
//SlitsPushBack(STLNode* phead, 1);传n1过去就只是把n1的值NULL传了过去,phead的接受的就是
// NULL这个值,值传递,phead的改变并不会改变n1的值
//这里是值传递,因为n1 和 phead都是STLNode* 类型,同类型传递就是传值操作,如果要改变 n1的值,必须n1的地址。
//要对类型对象的改变,必须传递类型和对象的地址过来进行改变。
SlistPushFront(&n1, 1);
SlistPushFront(&n1, 2);
SlistPushFront(&n1, 3);
SlistPushFront(&n1, 4);
STLNode* ret = SlistFind(n1, 4);
if (ret)
{
SlistInsert(&n1, ret, 40);
SlistPrint(n1);
//SlistErase(&n1, ret);
SListEraseAfter(ret);
SlistAfterInsert(ret, 66);
}
SlistPrint(n1);
//SlistPrint(n1);
}
int main()
{
TestList2();
return 0;
}