链表:
就是用一组任意的存储单元来存放线性表的元素,这组存储单元可以是连续的,也可以是不连续的,甚至可以是分布在任何位置。
首先定义一个结构体:
typedef int DataType;
typedef struct ListNode
{
DataType data;
struct ListNode* next;
}ListNode,*pNode;
结点包括两个域:
- 数据域:用来存储节点的值
- 指针域:用来存储数据元素的直接后继的地址信息
单链表的基本操作:
LinkList.h
#include<stdio.h>
#include<stdlib.h>
typedef int DataType;
typedef struct Node
{
int _data;
struct Node* _next;
}Node,*PNode;
//创建新结点
PNode BuyNewNode(DataType data);
// 尾插
void SListPushBack(PNode* pHead, DataType data);
// 尾删
void SListPopBack(PNode* pHead);
// 头插
void SListPushFront(PNode* pHead, DataType data);
// 头删
void SListPopFront(PNode* pHead);
// 在链表中查找值为data的元素,找到后返回值为data的结点
PNode SListFind(PNode pHead, DataType data);
// 在pos位置插入值为data的结点
void SListInsert(PNode* pHead, PNode pos, DataType data);
// 删除pos位置的结点
void SListErase(PNode* pHead, PNode pos);
// 判断链表是否为空
int SListEmpty(PNode pHead);
// 销毁链表
void SListDestroy(PNode* pHead);
// 链表遍历
void PrintNode(PNode pHead);
LinkList.c
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<assert.h>
#include"LinkList.h"
PNode BuyNewNode(DataType data)
{
PNode _new = (PNode)malloc(sizeof(Node));
if (NULL == _new)
{
printf("内存申请失败\n");
return NULL;
}
_new->_data = data;
_new->_next = NULL;
return _new;
}
// 尾插操作函数
void SListPushBack(PNode* pHead, DataType data)
{
PNode _new = NULL;
// 参数检验
assert(pHead);
_new = BuyNewNode(data);
if (NULL == _new)
{
return;
}
else
{
// 申请到了新节点
if (NULL == (*pHead))
{
// 如果单链表是空的话,让头指针直接指向新节点
*pHead = _new;
}
else
{
// 链表非空
PNode pCur = NULL;
pCur = (*pHead);
// 找链表的尾
while (!(pCur->_next == NULL))
{
pCur = pCur->_next;
}
// 链接起来
pCur->_next = _new;
}
}
}
// 尾删操作函数
void SListPopBack(PNode* pHead)
{
PNode pCur = NULL; //
PNode pPre = NULL; // 用来保存当前节点前一个节点
// 参数检验
assert(pHead);
pCur = *pHead;
pPre = pCur;
// 找单链表的尾,并用pPre保存前一个节点
while (!(pCur->_next == NULL))
{
pPre = pCur;
pCur = pCur->_next;
}
pPre->_next = NULL; // 找到尾之后直接让pPre->_next赋空
free(pCur); // 释放掉从单链表摘下的节点
pCur = NULL; // 避免野指针
}
// 头插操作函数
void SListPushFront(PNode* pHead, DataType data)
{
PNode _new = NULL;
// 参数检验
assert(pHead);
_new = BuyNewNode(data);
if (NULL == _new)
{
return;
}
else
{
// 成功申请到新节点
if (*pHead == NULL)
{
// 空链表 直接让头指针指向新节点
*pHead = BuyNewNode(data);
return;
}
// 链表非空 进行头插
_new = BuyNewNode(data);
_new->_next = *pHead;
*pHead = _new;// 修改头指针
}
}
// 头删操作函数
void SListPopFront(PNode* pHead)
{
PNode pCur = NULL;
// 参数检验
assert(pHead);
pCur = *pHead;
if (NULL == pCur)
{
printf("链表为空\n");
return;
}
// 单链表非空
*pHead = pCur->_next; // 让头指针指向头的_next域
free(pCur); // 释放pCur
pCur = NULL; // 避免野指针
}
// 在链表中查找值为data的元素,找到后返回值为data的结点
PNode SListFind(PNode pHead, DataType data)
{
PNode pCur = NULL;
// 参数检验
assert(pHead);
pCur = pHead;
// 遍历单链表 查找值为data的元素
while (pCur != NULL)
{
if (pCur->_data == data)
{
return pCur; // 找到了返回
}
pCur = pCur->_next; // pCur后移
}
return NULL; // 找不到返回NULL
}
// 在pos位置插入值为data的结点
void SListInsert(PNode* pHead, PNode pos, DataType data)
{
PNode pPre = NULL;
PNode pCur = NULL;
PNode _new = NULL;
// 参数检验
assert(pHead);
pCur = *pHead;
pPre = pCur;
if (pCur->_next == NULL)
{
// 链表为空
if (pCur == pos)
{
// 头插
_new = BuyNewNode(data);
if (_new == NULL)
{
return;
}
else
{
pHead = &_new;
}
}
else
{
// 链表位置不合法
printf("pos位置不合法\n");
return;
}
}
// 链表不为空
while (pCur != NULL)
{
if (pos == pCur)
{
_new = BuyNewNode(data);
if (_new == NULL)
{
return;
}
else
{
_new->_next = pPre->_next;
pPre->_next = _new;
}
return;
}
else
{
pPre = pCur;
pCur = pCur->_next;
}
}
// 已经遍历完了单链表 仍没找到pos位置
printf("pos位置不合法\n");
return;
}
// 删除pos位置的结点
void SListErase(PNode* pHead, PNode pos)
{
PNode pCur = NULL;
PNode pPre = NULL;
// 参数检验
assert(pHead);
pCur = *pHead;
pPre = pCur;
if (pCur == NULL)
{
printf("链表为空!!!\n");
return;
}
while (pCur != NULL)
{
if (pos == pCur)
{
pPre->_next = pCur->_next;
free(pCur);
pCur = NULL;
return;
}
else
{
pPre = pCur;
pCur = pCur->_next;
}
}
// 已遍历单链表
printf("pos位置不合法\n");
return;
}
// 判断链表是否为空 为空返回1 不为空返回0
int SListEmpty(PNode pHead)
{
if (pHead == NULL)
{
return 1;
}
return 0;
}
// 销毁链表
void SListDestroy(PNode* pHead)
{
PNode p = NULL;
PNode q = NULL;
// 参数检验
assert(pHead);
p = *pHead;
while (p != 0)
{
// 不是链尾时
q = p->_next; // 让q指向头节点的后继节点
free(p);
p = q; // 让p和q都指向后继节点
}
*pHead = NULL; // 将头指针赋空
}
// 链表遍历
void PrintNode(PNode pHead)
{
PNode pCur = NULL;
// 参数检验
assert(pHead);
pCur = pHead;
printf("单链表中所有元素:");
while (pCur != NULL)
{
printf("%d->", pCur->_data);
pCur = pCur->_next;
}
printf("NULL\n");
}
1、测试单链表尾插、尾删操作
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include"LinkList.h"
void TestNodePushBack_PopBack()
{
PNode pHead = NULL; // 头指针,并初始化
SListPushBack(&pHead, 1); // 尾插元素
SListPushBack(&pHead, 2);
SListPushBack(&pHead, 3);
SListPushBack(&pHead, 4);
PrintNode(pHead); // 遍历打印单链表
SListPopBack(&pHead); // 尾删一个元素
PrintNode(pHead); // 遍历打印单链表
SListDestroy(&pHead); // 销毁单链表
}
int main()
{
TestNodePushBack_PopBack();
system("pause");
}
2、测试单链表头插、头删操作
//测试头插头删
void TestNodePushFront_PopFront()
{
PNode pHead = NULL; // 头指针,并初始化
SListPushFront(&pHead, 4); // 头插元素
SListPushFront(&pHead, 3);
SListPushFront(&pHead, 2);
SListPushFront(&pHead, 1);
PrintNode(pHead); // 遍历打印单链表
SListPopFront(&pHead); // 头删一个元素
PrintNode(pHead); // 遍历打印单链表
SListDestroy(&pHead); // 销毁单链表
}
int main()
{
//TestNodePushBack_PopBack();
TestNodePushFront_PopFront();
system("pause");
}
3、测试单链表查找、指定位置插入、指定位置删除操作
void TestNodeFind_Insert_Erase()
{
PNode pHead = NULL;
PNode ret_Find = NULL;
SListPushBack(&pHead, 1);
SListPushBack(&pHead, 2);
SListPushBack(&pHead, 4);
PrintNode(pHead);
ret_Find = SListFind(pHead, 4);
SListInsert(&pHead, ret_Find, 3);
PrintNode(pHead);
SListErase(&pHead, ret_Find);
PrintNode(pHead);
SListDestroy(&pHead); // 销毁单链表
}
int main()
{
//TestNodePushBack_PopBack();
//TestNodePushFront_PopFront();
TestNodeFind_Insert_Erase();
system("pause");
}
为了避免内存泄漏,在使用完单链表之后一点要销毁。