单链表的定义:
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针
(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
单链表分为:1,有头单链表 2,无头单链表
本次主要针对无头单链表
链表的声明
#include <stdio.h>
#include <assert.h>
#include <malloc.h>
typedef int DataType;
//带头单链表
typedef struct Node
{
DataType _data;
struct Node* _pNext;
}Node, *PNode;
链表的基本操作
注意:
在传入参数时,当需要修改pHead的指向时,需要传入二级指针PNode *pHead
当不需要改变pHead的指向时,只需传入一级指针PNode pHead即可。
// 初始化单链表
void InitList(PNode* pHead);
//销毁链表
void DestroyList(PNode *pHead);
// 在单链表的尾部插入一个节点
void PushBack(PNode* pHead, DataType data);
// 删除单链表的最后一个节点
void PopBack(PNode* pHead);
// 在单链表的头部插入值为data的结点
void PushFront(PNode* pHead, DataType data);
// 删除单链表的第一个结点
void PopFront(PNode* pHead);
// 在单链表中查找值为data的结点,找到了返回该结点的地址,否则返回NULL
Node* Find(PNode pHead, DataType data);
// 在单链表pos位置后插入值为data的结点
void Insert(PNode pos, DataType data);
// 在单链表中删除位置为pos的结点
void Erase(PNode* pHead, PNode pos);
// 移除单链表中第一个值为data的结点
void Remove(PNode* pHead, DataType data);
// 移除单链表中所有值为data的结点
void RemoveAll(PNode* pHead, DataType data);
// 获取单链表总结点的总个数
size_t Size(PNode pHead);
// 判断结点是否为空
int Empty(PNode pHead);
// 返回单链表的最后一个结点的位置
PNode Back(PNode pHead);
// 返回单链表的第一个结点的位置
PNode Front(PNode pHead);
// 构建一个新节点
Node* BuyNode(DataType data);
// 正向打印单链表
void PrintList(PNode pHead);
链表基本功能实现
///只要改变了单链表的内容(指针指向内容),应使用PNode*二级指针。
///不然的话,在函数中改变了pHead的内容,函数外pHead还是指向原来的地址//
// 构建一个新节点
Node* BuyNode(DataType data)
{
PNode pTemp = (PNode)malloc(sizeof(Node));
if (NULL != pTemp)
{
pTemp->_data = data;
pTemp->_pNext = NULL;
}
return pTemp;
}
// 初始化单链表
void InitList(PNode* pHead)
{
assert(NULL != pHead);
*pHead = NULL; //初始化为空
}
// 在单链表的尾部插入一个节点
void PushBack(PNode* pHead, DataType data)
{
PNode pNewNode = NULL;
assert(NULL != pHead);
if (!(pNewNode = BuyNode(data))) //创建节点失败
return ;
if (NULL == *pHead) //链表为空时
*pHead = pNewNode;
else //链表不为空
{
PNode pTailNode = Back(*pHead);
pTailNode->_pNext = pNewNode;
}
}
// 在单链表的头部插入值为data的结点
void PushFront(PNode* pHead, DataType data)
{
PNode pNewNode = NULL;
assert(NULL != pHead);
if (!(pNewNode = BuyNode(data)))//创建节点失败
return ;
if (NULL == *pHead) //链表为空时
*pHead = pNewNode;
else //链表不为空
{
pNewNode->_pNext = *pHead;
*pHead = pNewNode;
}
}
// 删除单链表的最后一个节点
void PopBack(PNode* pHead)
{
assert(NULL != pHead);
if (NULL == *pHead) //链表为空
return ;
if (NULL == (*pHead)->_pNext) //链表只有一个节点
{
free(*pHead); //删除节点
*pHead = NULL; //链表为空
}
else //链表节点大于等于2
{
PNode pDelNode = *pHead; //倒数第二个节点指针
while (NULL != pDelNode->_pNext->_pNext) //指向倒数第二个节点
pDelNode = pDelNode->_pNext;
free(pDelNode->_pNext); //删除最后一个节点
pDelNode->_pNext = NULL; //倒数第二个节点指向空。
}
}
// 删除单链表的第一个结点
void PopFront(PNode* pHead)
{
assert(NULL != pHead);
if (NULL == *pHead)
return ;
else
{
PNode pFirstNode = *pHead;
*pHead = (*pHead)->_pNext;
free(pFirstNode);
pFirstNode = NULL;
}
}
// 在单链表pos位置后插入值为data的结点
void Insert(PNode pos, DataType data)
{
PNode pNewNode = NULL;
assert(NULL != pos);
if (!(pNewNode = BuyNode(data)))
return ;
pNewNode->_pNext = pos->_pNext;
pos->_pNext = pNewNode;
}
// 在单链表中删除位置为pos的结点
void Erase(PNode* pHead, PNode pos)
{
PNode pPreNode = NULL;
assert(NULL != pHead); //看看是该用if(pos == NULL)好,还是assert好。
assert(NULL != pos);
pPreNode = *pHead; //pPreNode指向pos前一节点
if (NULL == *pHead) //当是空链表时
return ;
if (pos == *pHead) //pos为第一个节点时
PopFront(pHead);
else //pos为别的位置,并且链表不为空
{ //考虑pos不为链表内容情况
while (pPreNode && pPreNode->_pNext != pos) //pCurNode指向不为空且pCurNode->_pNext不等于pos
pPreNode = pPreNode->_pNext; //pCurNode指向下一节点
if (NULL != pPreNode) //pCurNode下一节点是pos
{
pPreNode->_pNext = pos->_pNext;
free(pos);
pos = NULL;
}
}
}
// 移除单链表中第一个值为data的结点
void Remove(PNode* pHead, DataType data)
{
PNode pDelNode = NULL;
assert(NULL != pHead);
if (pDelNode = Find(*pHead, data))
Erase(pHead, pDelNode);
}
// 移除单链表中所有值为data的结点
void RemoveAll(PNode* pHead, DataType data)
{
PNode pDelNode = NULL;
assert(NULL != pHead);
pDelNode = *pHead;
if (NULL == *pHead) //链表为空
return ;
if (NULL == (*pHead)->_pNext) //链表只有一个节点
{
if ((*pHead)->_data == data)
PopFront(pHead);
}
else
{ //思路:将本该删除的节点pDelNode替换为它的下一节点pTemp,然后释放pTemp。
while (pDelNode->_pNext)
if (pDelNode->_data == data)
{
PNode pTemp = pDelNode->_pNext;
pDelNode->_data = pTemp->_data;
pDelNode->_pNext = pTemp->_pNext;
free(pTemp);
pTemp = NULL;
}
else
pDelNode = pDelNode->_pNext;
}
}
//销毁链表
void DestroyList(PNode *pHead)
{
PNode pCurNode = NULL;
assert(NULL == pHead);
while (NULL != *pHead)
{
PNode pTemp = *pHead;
*pHead = (*pHead)->_pNext;
free(pTemp);
pTemp = NULL;
}
}
///
// 在单链表中查找值为data的结点,找到了返回该结点的地址,否则返回NULL
Node* Find(PNode pHead, DataType data)
{
assert(NULL != pHead);
while (pHead)
if (pHead->_data == data)
break;
else
pHead = pHead->_pNext;
return pHead;
}
// 获取单链表总结点的总个数
size_t Size(PNode pHead)
{
size_t n = 0;
while (pHead) //当pHead不为空时
{
++n;
pHead = pHead->_pNext;
}
return n;
}
// 判断结点是否为空
int Empty(PNode pHead)
{
if (pHead) //pHead不是空链表
return 1;
return 0;
}
// 返回单链表的最后一个结点的位置
PNode Back(PNode pHead)
{
if (NULL != pHead) //pHead不是空链表
while (pHead->_pNext)
pHead = pHead->_pNext;
return pHead;
}
// 返回单链表的第一个结点的位置
PNode Front(PNode pHead)
{
return pHead;
}
// 正向打印单链表
void PrintList(PNode pHead)
{
PNode pCurNode = NULL;
assert(NULL != pHead);
pCurNode = pHead;
while (pCurNode)
{
printf("%d->", pCurNode->_data);
pCurNode = pCurNode->_pNext;
}
printf("<null>\n");
}