在上一次中,讲解了顺序表,但是顺序表也有一些缺陷,针对顺序表的缺陷发明了链表
顺序表的缺陷:
1、空间不够需要增容,增容有代价
2、空间满了要扩二倍,如果没有有效利用会造成大量的空间浪费
3、在头部或者中间插入数据需要依次向后挪动数据,效率低
链表:
物理存储上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针依次链接实现的
特点:
1、链式结构在逻辑上连续,但在物理上不一定连续
2、节点都是在堆上申请出来的
3、两次申请的空间可能连续,也可能不连续
优点:
1、按需申请空间,不用了就释放
2、头部插入数据不需要挪动,不存在空间浪费
缺点:
1、不支持随机访问
代码实现:
test.c: 放置主函数并且测试功能函数
SList.c:放置函数的定义
SList.h: 放置函数的声明及其各种头文件
SList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
void SListPrint(SLTNode* phead);
void SListPushBack(SLTNode** pphead, SLTDataType x);
void SListPushFront(SLTNode** pphead, SLTDataType x);
void SListPopBack(SLTNode** phead);
void SListPopFront(SLTNode** phead);
SLTNode* SListFind(SLTNode* phead, SLTDataType x);
SList.c
#define _CRT_SECURE_NO_WARNINGS
#include "SList.h"
void SListPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
SLTNode* BuyListNode(SLTDataType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->next = NULL;
newnode->data = x;
return newnode;
}
void SListPushBack(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = BuyListNode(x);
if (*pphead == NULL)
{
*pphead = newnode;
}
else
{
SLTNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
void SListPushFront(SLTNode** pphead, SLTDataType x)
{
SLTNode* newnode = BuyListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SListPopBack(SLTNode** phead)
{
assert(*phead);
// 一个节点的情况
if ((*phead)->next == NULL)
{
free(*phead);
*phead = NULL;
}
else
{
SLTNode* tail = *phead;
SLTNode* prev = NULL;// 保存前一个节点的位置
while (tail->next)
{
prev = tail;// 尾结点的前一个节点
tail = tail->next;// 找到尾结点
}
free(tail);
tail = NULL;
prev->next = NULL;
}
}
void SListPopFront(SLTNode** pphead)
{
// 判断有没有节点
assert(*pphead);
SLTNode* next = (*pphead)->next;
free(*pphead);
*pphead = next;
}
SLTNode* SListFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
// 在pos位置之前插入一个节点
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
SLTNode* newnode = BuyListNode(x);
if (*pphead == pos)// 如果一开始就是pos位置也就是pos==prev,相当于头插
{
newnode->next = *pphead;
*pphead = newnode;
}
else
{
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
newnode->next = pos;
prev->next = newnode;
}
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#include "SList.h"
void Test1()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SListPushFront(&plist, 10);
SListPushFront(&plist, 20);
SListPrint(plist);
SListPopFront(&plist);
SListPrint(plist);
}
void Test2()
{
SLTNode* plist = NULL;
SListPushBack(&plist, 1);
SListPushBack(&plist, 2);
SListPushBack(&plist, 3);
SListPushBack(&plist, 4);
SLTNode* pos = SListFind(plist, 1);
SListInsert(&plist, pos, 0);
SListPrint(plist);
}
int main()
{
//Test1();
Test2();
return 0;
}