在数据结构中,链表的相关操作尤为重要,链表有单向链表和双向链表。 此篇博客主要向大家介绍单链表的相关操作,
其中包括链表的增删改查,头删尾删,头插尾插。 在链表中由于需要不断的扩充或者减小结构,因此将链表定义为动态内存,
使用malloc来满足这一操作。
#include <stdio.h>
#include <windows.h>
#include <assert.h>
// 值类型
typedef int DataType;
typedef struct SListNode {
DataType data; // 值
struct SListNode *pNext; // 指向下一个结点
} SListNode;
// 初始化
void SListInit(SListNode **ppFirst)
{
*ppFirst = NULL;
}
// 尾部插入
void SListPushBack(SListNode** ppFirst, DataType data)
{
assert(ppFirst != NULL);
SListNode *pNewNode = (SListNode *)malloc(sizeof(SListNode));
assert(pNewNode);
pNewNode->data = data;
pNewNode->pNext = NULL;
if (*ppFirst == NULL){
*ppFirst = pNewNode;
return 0;
}
SListNode *pNode;
pNode = *ppFirst;
while (pNode->pNext != NULL)
{
pNode = pNode->pNext;
}
pNode->pNext = pNewNode;
}
// 头部插入
void SListPushFront(SListNode **ppFirst, DataType data)
{
assert(ppFirst != NULL);
SListNode *pFirst = (SListNode*)malloc(sizeof(SListNode));
pFirst->data=data;
pFirst->pNext = *(ppFirst);
}
// 尾部删除
void SListPopBack(SListNode **ppFirst)
{
if ((*ppFirst)->pNext == NULL)
{
free(*ppFirst);
(*ppFirst) = NULL;
}
SListNode *Back = *ppFirst;
while (Back->pNext->pNext != NULL)
{
Back=Back->pNext;
}
free(Back->pNext);
Back->pNext = NULL;
}
// 头部删除
void SListPopFront(SListNode **ppFirst)
{
assert(*ppFirst != NULL);
SListNode *oldFirst = *ppFirst;
*ppFirst = (*ppFirst)->pNext;
free(oldFirst);
}
// 给定结点插入,插入到结点前
void SListInsert(SListNode **ppFirst, SListNode *pPos, DataType data)
{
assert(ppFirst != NULL);
SListNode *pNode;
pNode = *ppFirst;
while( pNode->pNext != pPos)
{
pNode = pNode->pNext;
}
//两个位置交换
pNode->pNext = pPos;
pPos->pNext = pNode->pNext;
}
// 给定结点删除
void SListErase(SListNode **ppFirst, SListNode *pPos)
{
assert(ppFirst);
/*SListNode *NewFirst = *ppFirst;
while (NewFirst != pPos)
{
NewFirst = NewFirst->pNext;
}
free(ppFirst);
pPos->pNext = NewFirst->pNext;
pPos = NewFirst;*/
if (*ppFirst == pPos)
{
SListPopFront(ppFirst);
}
SListNode *NewFirst = *ppFirst;
for (NewFirst; NewFirst->pNext != pPos; NewFirst = NewFirst->pNext)
{
;
}
NewFirst->pNext = pPos->pNext;
free(pPos);
}
// 按值查找,返回第一个找到的结点指针,如果没找到,返回 NULL
SListNode* SListFind(SListNode *pFirst, DataType data)
{
SListNode *Node = pFirst;
while (Node)
{
if (Node->data == data)
{
return Node;
}
Node = Node->pNext;
}
return NULL;
}
// 按值删除,只删遇到的第一个
void SListRemove(SListNode **ppFirst, DataType data)
{
SListNode *Find = SListFind(*ppFirst, data);
if (Find != NULL)
{
SListErase(ppFirst, Find);
}
}
// 按值删除,删除所有的
void SListRemoveAll(SListNode **ppFirst, DataType data)
{
SListNode *Node = *ppFirst;
while (Node)
{
if (Node->pNext->data== data)
{
Node->pNext = Node->pNext->pNext;
free(Node->pNext);
}
if (Node->data = data)
{
Node = Node->pNext;
free(Node);
}
else
{
Node = Node->pNext;
}
}
}
// 销毁
void SListDestroy(SListNode **ppFirst)
{
SListNode *Node, *Next;
Node = *ppFirst;
while (Node!=NULL)
{
Next = Node->pNext;
free(Node);
Node = Next;
}
*ppFirst = NULL;
}
void show(SListNode *Sln)
{
while (Sln)
{
printf("%d->", Sln->data);
Sln = Sln->pNext;
}
printf("NULL");
}
int main()
{
SListNode *Sln;
SListInit(&Sln);
SListPushBack(&Sln, 5);
show(Sln);
system("pause");
return 0;
}
至此,单链表的相关操作就在代码中体现出来了。 链表的概念有些抽象,博主给大家一个小方法,在写链表的操作时可以用画图的形式来理解,这样写代码时就更容易实现链表的相关操作了。