文章目录
编者前言
链表的题多用双指针,三指针,快慢指针,头指针等解决。画图,写一项调试一项。
单链表的创建,申请,销毁,打印
创建,申请
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int DaT;
typedef struct SListNode
{
struct SListNode* next;
DaT data;
}SL;
申请
SL* BuyNode(DaT x)
{
SL* node = (SL*)malloc(sizeof(SL));
if (node == NULL)
{
printf("malloc failed\n");
exit(-1);
}
node->data = x;
node->next = NULL;
return node;
}
打印,销毁
void SLPrint(SL* phead)
{
SL* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
void DestorySL(SL** phead)
{
assert(phead);
SL* cur = *phead;
while (cur)
{
SL* next = cur->next;
free(cur);
cur = next;
}
*phead = NULL;
}
单边表的尾插,头插,尾删,头删
尾部插入,头部插入
void SLPushBcak(SL** phead, DaT x)
{
assert(phead);
if (*phead == NULL) 如果为空,则申请开辟一个结点
{
SL* newnode = BuyNode(x);
*phead = newnode;
}
else 不为空,则找尾
{
SL* cur = *phead;
while (cur->next!=NULL)
{
cur = cur->next;
}
SL* newn = BuyNode(x);
cur->next = newn;
}
}
头插
void SLPushFront(SL** phead, DaT x)
{
assert(phead);
SL* newnode = BuyNode(x);
newnode->next = *phead;
*phead = newnode; 始终指向第一个结点
}
尾删,头删
void SLPopBcak(SL** phead)
{
assert(phead);
assert(*phead); 为空调用尾删->向标准错误设备写入一条消息并调用abort,终止程序的执行。
一个结点时,
if ((*phead)->next == NULL)
{
free(*phead);
*phead = NULL;
}
else
{
SL* cur = *phead;
SL* prev = NULL;
while (cur->next != NULL)
{
prev = cur;
cur = cur->next;
}
free(cur);
prev->next = NULL;
}
}
头删
void SLPopFront(SL** phead)
{
assert(phead);
一个结点时,
if ((*phead)->next == NULL)
{
free(*phead);
*phead = NULL;
}
else
{
SL* cur = *phead;
*phead = cur->next;
free(cur);
}
}
单链表的查找,pos之后的插入,删除,之前的插入
查找
SL* SLFind(SL* phead, DaT x)
{
assert(phead);
SL* cur = phead;
while (cur->data != x && cur)
{
cur = cur->next;
}
return cur;
}
pos之后的插入,删除
void SLInsertAft(SL* pos, DaT x)
{
assert(pos);
SL* newn = BuyNode(x);
newn->next = pos->next;
pos->next = newn;
}
删除
void SLEarse(SL** phead, SL* pos)
{
assert(phead);
assert(pos);
如果pos是指向第一个节点,就调头删
if (pos == *phead)
{
SLPopFront(phead);
}
else
{
SL* del = *phead;
while (del->next != pos)
{
del = del->next;
}
del->next = pos->next;
free(pos);
pos = NULL;
}
}
pos之前的插入
void SLInsert(SL** phead, SL* pos, DaT x)
{
assert(phead);
assert(pos);
if (pos == *phead)
{
SLPushFront(phead,x); 如果pos是指向第一个节点,则调用头插
}
else
{
SL* cur = *phead;
while (cur->next != pos)
{
cur = cur->next;
}
SL* newnode = BuyNode(x);
newnode->next = pos;
cur->next = newnode;
}
}
是否空链表,链表元素个数
外部调用
SL* pl = NULL;
printf("几个元素:%d\n", SLsize(pl));
printf("是否为空:%d", SLEmpty(pl));
空链表,链表元素个数
个数
int SLsize(SL* phead)
{
int count = 0;
SL* cur = phead;
while (cur)
{
count++;
cur = cur->next;
}
return count;
}
空判定
bool SLEmpty(SL* phead)
{
return phead == NULL ? true : false;
}
双向链表的申请,空否,销毁,打印
双向链表头节点不存储数据。
申请
typedef struct DListN
{
struct DListN* prev;
struct DListN* next;
DaT data;
}DL;
DL* DListCreat()
{
DL* phead = (DL*)malloc(sizeof(DL));
phead->next = phead->prev = phead;
return phead;
}
空否
bool DListEmpty(DL* pdl)
{
assert(pdl);
return pdl->next == pdl ? true : false;
}
销毁
void DListDestory(DL* pdl)
{
DL* del = pdl->next;
while (del != pdl)
{
DL* next = del->next;
free(del);
del = next;
}
free(pdl);
}
打印
void DListPrint(DL* pdl)
{
assert(pdl);
DL* cur = pdl->next;
while (cur != pdl)
{
printf("%d<->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
双向链表的尾插,头插,尾删,头删
尾插,头插
void DListPushBack(DL* pdl, DaT x)
{
assert(pdl);
DL* newn = DListBuy(x);
一个节点都没有
if (pdl->next == NULL)
{
pdl->next = pdl->prev = newn;
newn->next = newn->prev = pdl;
}
else
{
(pdl)->prev->next = newn;
newn->prev = (pdl)->prev;
(pdl)->prev = newn;
newn->next = (pdl);
}
}
尾删,头删
void DListPopBack(DL* pdl)
{
assert(pdl);
assert(!DListEmpty(pdl));
DL* del = pdl->prev;
del->prev->next = pdl;
pdl->prev = del->prev;
free(del);
}
头删
void DListPopFront(DL* pdl)
{
assert(pdl);
assert(!DListEmpty(pdl));
DL* cur = pdl->next;
pdl->next = cur->next;
cur->next->prev = pdl;
free(cur);
}
pos前的插入,删除pos节点
pos之前插入
void DListInterpos(DL* pos, DaT x)
{
assert(pos);
DL* posprev = pos->prev;
DL* newn = DListBuy(x);
posprev->next = newn;
newn->prev = posprev;
newn->next = pos;
pos->prev = newn;
}
删除pos位置的节点
void DListOmit(DL* pos)
{
assert(pos);
/记住它的前指针后指针
DL* posprev = pos->prev;
DL* posnext = pos->next;
free(pos);
posprev->next = posnext;
posnext->prev = posprev;
}
编者寄语
奶奶常说,学无止境,总有你没见过的错误…Don’t panic !