链表以及基本操作
1. 链表是一种链式存储的线性表,每个存储单元称为结点
链表是相互连接起来的存储单元,一个存储单元包含两部分
一部分表示的是指向下一个存储单元的指针,另一部分表示的是的存储单元中的数据元素。
2. 接下来就进行一些基本的链表操作
(1)链表的建立
//链表类型在头文件中的定义
typedef int DataType;
typedef struct SListNode
{
DataType _data;
struct SListNode* _pNext; // 指向下一个结点的指针
}Node, *PNode;
//开辟空间,并初始化
PNode BuySListNode(DataType data)
{
PNode node = (Node*)malloc(sizeof(Node));//开辟一个Node类型的结点的空间
node->_data = data;
node->_pNext = NULL;
return node;
}
// 尾插
void SListPushBack(PNode*ppHead, DataType data)
{
assert(ppHead);
if (NULL == *ppHead)
{
*ppHead = BuySListNode(data);
}
else
{
PNode pTail = *ppHead;
while (pTail->_pNext)
{
pTail = pTail->_pNext;
}
pTail->_pNext = BuySListNode(data);
}
}
// 头插
void SListPushFront(PNode* ppHead, DataType data)
{
assert(ppHead);
PNode pnewnode = BuySListNode(data);//创建一个新的头结点
pnewnode->_pNext = *ppHead;//更新头结点
*ppHead = pnewnode;
}
(2) 链表的特殊位置以及指定位置的插入和删除
// 尾删
void SListPopBack(PNode* ppHead)
{
assert(ppHead);
PNode pTail = *ppHead;
PNode pre = NULL;
while (pTail == NULL)//为空时,直接返回
{
printf("链表为空");
return;
}
if (pTail->_pNext == NULL)//有一个结点时,释放掉一个结点
{
free(pTail);
pTail = NULL;
}
else if (pTail->_pNext)//为多个时,借用pre来更新链表
{
pre = pTail;
pTail->_pNext = pTail;
}
free(pTail);
pre->_pNext = NULL;
}
// 头删
void SListPopFront(PNode* ppHead)
{
assert(ppHead);
while (*ppHead == NULL)
{
printf("链表为空");
return;
}
PNode pdel = *ppHead;//pdel指向头结点
*ppHead = pdel->_pNext;//改变头结点的位置
free(pdel);
}
// data插入在pos之前
void SListInsert(PNode* ppHead, PNode pos, DataType data)// 1 2 3(5) 4-------》pos为4,data为5
{
assert(ppHead);
PNode pcur = *ppHead;
PNode pnewnode = BuySListNode(data);
if (pcur== pos)//当pos为头结点时
{
SListPushFront(ppHead, data);//头插
}
if (pcur->_pNext != pos)//后移
{
pcur = pcur->_pNext;
}
else
{
pcur->_pNext = pnewnode;//3指向5
pnewnode->_pNext = pos;//5指向4
}
}
// 删除链表中pos位置的结点
void SListErase(PNode* ppHead, PNode pos)// 1 2 3 4---->删除pos为3的结点
{
assert(ppHead);
PNode pcur = *ppHead;
PNode pre = *ppHead;
if(pcur==NULL||pos==NULL)
{
printf("无法删除");
}
if (pcur == pos)//当pos为头结点时
{
SListPopFront(ppHead);//头删
}
else
{
PNode pre = *ppHead;
while (pre&&pre->_pNext != pos)
{
pre = pre->_pNext;
}
if (pre)
{
pre->_pNext = pos->_pNext;//更新链表
}
free(pos);
}
(3)其余的操作
// 在链表中查找元素data,返回该结点在链表中的位置
PNode Find(PNode pHead, DataType data)
{
assert(pHead);
PNode pcur = pHead;
while (pcur)
{
if (pcur->_data == data)
{
return pcur;
}
pcur = pcur->_pNext;
}
return NULL;
}
// 获取链表中结点的个数
int Size(PNode pHead)
{
PNode pcur = pHead;
assert(pHead);
int count;
while (pcur)
{
count++;
pcur = pcur->p_Next;
}
return count;
}
// 判断链表是否为空,若为空,返回true,否则返回false
size_t Empty(PNode pHead)
{
assert(pHead);
if (pHead == NULL)
{
return 1;
}
else
return 0;
}
// 销毁单链表
void SListDestroy(PNode * ppHead)
{
assert(ppHead);
PNode pre = NULL;//用于更新链表
PNode pcur = *ppHead;
while (pcur)
{
pre = pcur;
pcur->_pNext = pcur;
}
free(pcur);
free(pre);
}
// 打印单链表
void SListPrint(PNode pHead)
{
assert(pHead);
PNode pcur = pHead;
while (pcur)
{
printf("->%d", pcur->_data);
}
printf("\n");
}
3. 测试函数
#include "linklist.h"
int main()
{
Node* L=NULL;//L为指向链表的指针
Node *pos = L;//pos为二级指针
pos = pos->_pNext;
BuySListNode(0);
SListPushBack(&L, 1);//需要传指针的地址,因为需要对链表会有内容的改变
SListPushBack(&L, 2);
SListPushBack(&L, 3);
SListPushBack(&L, 4);
SListPushBack(&L, 5);
SListPrint(&L);
SListPopBack(&L);
SListPrint(&L);
SListPushFront(&L, 0);
SListPrint(&L);
SListPopFront(&L);
// 在链表中查找元素data,返回该结点在链表中的位置
Find(&L, 3);
// data插入在pos之前
SListInsert(&L, pos, 8);
SListPrint(&L);
SListErase(&L, pos);
SListPrint(L);
// 获取链表中结点的个数
Size(L);
// 判断链表是否为空,若为空,返回true,否则返回false
Empty(L);
// 销毁单链表
SListDestroy(&L);
system("pause");
return 0;
}
4.头文件
#include"stdio.h"
#include"assert.h"
#include"windows.h"
#ifndef _LINKLIST_H__
#define _LINKLIST_H__
//链表类型在头文件中的定义
typedef int DataType;
typedef struct SListNode
{
DataType _data;
struct SListNode* _pNext; // 指向下一个结点的指针
}Node, *PNode;
// 尾插
void SListPushBack(PNode*ppHead, DataType data);
// 尾删
void SListPopBack(PNode* ppHead);
// 头插
void SListPushFront(PNode*ppHead, DataType data);
// 头删
void SListPopFront(PNode* ppHead);
// 在链表中查找元素data,返回该结点在链表中的位置
PNode Find(PNode pHead, DataType data);
// data插入在pos之前
void SListInsert(PNode* ppHead, PNode pos, DataType data);
// 删除链表中pos位置的结点
void SListErase(PNode* ppHead, PNode pos);
// 获取链表中结点的个数
size_t Size(PNode pHead);
// 判断链表是否为空,若为空,返回true,否则返回false
size_t Empty(PNode pHead);
// 销毁单链表
void SListDestroy(PNode* ppHead);
// 创建结点,并初始化
PNode BuySListNode(DataType data);
// 打印单链表
void SListPrint(PNode pHead);
#endif _LINKLIST_H__