目录
SLT.h
SLT.c
SLTtest.c
测试示例
单链表优劣分析
SLT.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int SLTDataType;
typedef struct SListNode
{
SLTDataType data;
struct SListNode* next;
}SLTNode;
//打印单链表
void SLTPrint(SLTNode* phead);
//创建节点
SLTNode* BuySLTNode(SLTDataType x);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//尾删
void SLTPopBack(SLTNode** pphead);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//头删
void SLTPopFront(SLTNode** pphead);
//单链表查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在pos之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos);
//单链表在pos位置之后插入x
void SListInsertAfter(SLTNode* pos, SLTDataType x);
//单链表删除pos位置之后的值
void SListEraseAfter(SLTNode* pos);
//销毁单链表
void SLTDestroy(SLTNode** pphead);
SLT.c
#include "SLT.h"
//打印单链表
void SLTPrint(SLTNode* phead)
{
SLTNode* cur = phead;
while (cur)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
//创建节点
SLTNode* BuySLTNode(SLTDataType x)
{
SLTNode* node = (SLTNode*)malloc(sizeof(SLTNode));
if (node == NULL)
{
perror("SLTBuysNode");
exit(-1);
}
node->data = x;
node->next = NULL;
return node;
}
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
if (*pphead == NULL)
{
*pphead = BuySLTNode(x);
}
else
{
SLTNode* tail = *pphead;
while (tail->next)
{
tail = tail->next;
}
tail->next = BuySLTNode(x);
}
}
//尾删
void SLTPopBack(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* tail = *pphead;
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next->next);
tail->next = NULL;
}
}
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
assert(pphead);
SLTNode* newnode = BuySLTNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
//头删
void SLTPopFront(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
SLTNode* newhead = (*pphead)->next;
free(*pphead);
*pphead = newhead;
}
// 单链表查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{
SLTNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
//找到了
return cur;
}
cur = cur->next;
}
//找不到
return NULL;
}
//在pos之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
assert(pphead);
if (*pphead == pos)
{
SLTNode* newnode = BuySLTNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
else
{
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
SLTNode* newnode = BuySLTNode(x);
cur->next = newnode;
newnode->next = pos;
}
}
// 删除pos位置
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(*pphead && pos);
if (*pphead == pos)
{
SLTNode* newhead = (*pphead)->next;
free(*pphead);
*pphead = newhead;
}
else
{
SLTNode* cur = *pphead;
while (cur->next != pos)
{
cur = cur->next;
}
SLTNode* pos_next = pos->next;
free(pos);
cur->next = pos_next;
}
}
// 单链表在pos位置之后插入x
void SListInsertAfter(SLTNode* pos, SLTDataType x)
{
assert(pos);
SLTNode* newnode = BuySLTNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
// 单链表删除pos位置之后的值
void SListEraseAfter(SLTNode* pos)
{
assert(pos && pos->next);
SLTNode* pos_next_next = pos->next->next;
free(pos->next);
pos->next = pos_next_next;
}
//销毁单链表
void SLTDestroy(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
while (*pphead)
{
SLTNode* newhead = (*pphead)->next;
free(*pphead);
*pphead = newhead;
}
}
SLTtest.c
#include "SLT.h"
void SLTtest1()
{
SLTNode* phead = NULL;
SLTPrint(phead);
SLTPushBack(&phead, 1);
SLTPushBack(&phead, 2);
SLTPushBack(&phead, 3);
SLTPushBack(&phead, 4);
SLTPushBack(&phead, 5);
SLTPrint(phead);
SLTPopBack(&phead);
SLTPrint(phead);
SLTPopBack(&phead);
SLTPrint(phead);
SLTPopBack(&phead);
SLTPrint(phead);
SLTPopBack(&phead);
SLTPrint(phead);
SLTPopBack(&phead);
SLTPrint(phead);
/*SLTPopBack(&phead);
SLTPrint(phead);*/
}
void SLTtest2()
{
SLTNode* phead = NULL;
SLTPrint(phead);
SLTPushFront(&phead, 1);
SLTPushFront(&phead, 2);
SLTPushFront(&phead, 3);
SLTPushFront(&phead, 4);
SLTPushFront(&phead, 5);
SLTPrint(phead);
/*SLTDestroy(&phead);
SLTPrint(phead);*/
/*SLTPopFront(&phead);
SLTPrint(phead);
SLTPopFront(&phead);
SLTPrint(phead);
SLTPopFront(&phead);
SLTPrint(phead);
SLTPopFront(&phead);
SLTPrint(phead);
SLTPopFront(&phead);
SLTPrint(phead);*/
/*SLTPopFront(&phead);
SLTPrint(phead);*/
}
void SLTtest3()
{
SLTNode* phead = NULL;
SLTPrint(phead);
SLTPushFront(&phead, 1);
SLTPushFront(&phead, 2);
SLTPushFront(&phead, 3);
SLTPushFront(&phead, 4);
SLTPushFront(&phead, 5);
SLTPrint(phead);
//在pos位置之前插入删除
SLTInsert(&phead, phead, 10);
SLTPrint(phead);
SLTInsert(&phead, NULL, 20);
SLTPrint(phead);
SLTNode* pos = SLTFind(phead, 3);
SLTInsert(&phead, pos, 30);
SLTPrint(phead);
//删除pos位置的值
SLTErase(&phead, phead);
SLTPrint(phead);
pos = SLTFind(phead, 3);
SLTErase(&phead, pos);
SLTPrint(phead);
pos = SLTFind(phead, 20);
SLTErase(&phead, pos);
SLTPrint(phead);
}
void SLTtest4()
{
SLTNode* phead = NULL;
SLTPrint(phead);
SLTPushFront(&phead, 1);
SLTPushFront(&phead, 2);
SLTPushFront(&phead, 3);
SLTPushFront(&phead, 4);
SLTPushFront(&phead, 5);
SLTPrint(phead);
//在pos位置之后插入
SListInsertAfter(phead, 10);
SLTPrint(phead);
SLTNode* pos = SLTFind(phead, 3);
SListInsertAfter(pos, 30);
SLTPrint(phead);
pos = SLTFind(phead, 1);
SListInsertAfter(pos, 10);
SLTPrint(phead);
//删除pos位置之后的值
SListEraseAfter(phead);
SLTPrint(phead);
pos = SLTFind(phead, 4);
SListEraseAfter(pos);
SLTPrint(phead);
}
int main()
{
//测试尾插尾删
//SLTtest1();
//测试头插头删
//SLTtest2();
//在pos位置之前插入删除
//SLTtest3();
//在pos位置之后插入删除
//SLTtest4();
return 0;
}
测试示例
尾插尾删:
头插头删:
在pos位置之前插入:
删除pos位置的值:
在pos位置之后插入删除:
单链表优劣分析
单链表在逻辑上连续,在物理上不一定连续,用多少申请多少空间,因此不存在空间浪费且申请空间开销小;插入删除元素时无需挪动元素,只需要改变指向即可,但除头插头删,在pos位置之后插入删除外需要先遍历链表,效率低下;不支持随机访问;缓存利用率低。
总结:单链表具有较大的缺陷,相较于顺序表而言没有明显的优势,因此在实践中几乎没有应用场景。