因为顺序表的底层空间是连续的,所以如果对元素进行大量的任意位置添加或删除,在顺序表里就要移动大量的元素,效率很低,因此我们需要让元素存储在不连续的空间中,但如果直接存储,就不知道它的下一个元素是什么,这时就可以利用链表这个结构
链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的链接次序实现(除了存储元素信息外,还要给下一个节点的位置)
找到第一个节点,就可以通过链式结构找到下一个节点
链表:
1.单链表(从前往后)、双链表(循环)
2.带头(链表中第一个节点的不存储有效数据)
不带头(一个节点存储有效数据)
3.循环、非循环
下面来实现下不带头结点的单项非循环链表
SList.h文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
//无头单项非循环
//不带头结点,第一个结点存的是有效元素
typedef int SDataType;
//节点的结构
typedef struct SListNode
{
SDataType _data;//保存数据
struct SListNode* _pNext;//指向下一个 节点的地址
}Node;
//链表的结构
//把链表记录下来,只要知道头节点就行
typedef struct SList
{
Node* _pHead;
}SList,*PSList;
void SListInit(PSList pl);//初始化
void SListDestory(PSList pl);//销毁
Node* BuySListNode(SDataType data);
void SListPushBack(PSList pl, SDataType data);//尾插
void SListPopBack(PSList pl);//尾删
void SListPushFront(PSList pl, SDataType data);//头插
void SListPopFront(PSList pl);//头删
Node* SListFind(PSList pl, SDataType data);//找位置
void SListInsert(PSList pl, Node* pos, SDataType data);//任意位置插入
void SListErase(PSList pl, Node* pos);//任意位置删除
void SListIsFindData(PSList pl, SDataType data);//检测data是否在链表中
void SListRemove(PSList pl, SDataType data);// 移除链表中第一个值为data的元素
//void SListRemoveAll(PSList pl, SDataType data);// 移除链表中所有值为data的元素
void SListSize(PSList pl);//// 获取链表有效元素个数
void SListCapacity(PSList pl);// 获取链表的容量
int SListEmpty(PSList pl);// 检测链表是否为空
SDataType SListFront(PSList pl);// 获取链表中第一个元素
SDataType SListBack(PSList pl);// 获取链表中最后一个元素
///////////////////////////////////////////////////////
void PrintSList(PSList pl);
//////////////////////////////////
void SListTest();
SList.c文件
#include "SList.h"
void SListInit(PSList pl)//初始化
{
assert(pl);
pl->_pHead = NULL;
}
Node* BuySListNode(SDataType data)//获取新结点
{
Node* pNode = (Node*)malloc(sizeof(Node));
if (pNode == NULL)
{
assert(0);
return NULL;
}
pNode->_data = data;
pNode->_pNext = NULL;
return pNode;
}
void SListPushBack(PSList pl, SDataType data)//尾插
{
Node* pNewNode = NULL;//新结点
Node* pCur = NULL;//链表最后一个结点
assert(pl);
pNewNode = BuySListNode(data);
pCur = pl->_pHead;
//检测链表是否为空
if (pl->_pHead == NULL)
pl->_pHead = pNewNode;
else
{
while (pCur->_pNext)
{
pCur = pCur->_pNext;
}
pCur->_pNext = pNewNode;
}
}
void SListPopBack(PSList pl)//尾删
{
//找链表中最后一个结点,保存前一个结点(或倒数第二个结点) 链表至少有两个结点
assert(pl);
if (pl->_pHead == NULL)
{
printf("空链表\n");
return;
}
else if (pl->_pHead->_pNext == NULL)//有一个结点
{
free(pl->_pHead);
pl->_pHead = NULL;
}
else//至少有两个结点
{
Node* pCur = pl->_pHead;
Node* pre = NULL;
while (pCur->_pNext)
{
pre = pCur;//保存pCur的前一个结点
pCur = pCur->_pNext;
}
free(pCur);
pre->_pNext = NULL;
}
}
void SListPushFront(PSList pl, SDataType data)//头插
{
Node* pNewNode = NULL;
assert(pl);
pNewNode = BuySListNode(data);
pNewNode->_pNext = pl->_pHead;;
pl->_pHead = pNewNode;
}
void SListPopFront(PSList pl)//头删
{
assert(pl);
if (pl->_pHead == NULL)//无结点
{
printf("空链表\n");
return;
}
else
{
Node* DeleteNode = pl->_pHead;
pl->_pHead = pl->_pHead->_pNext;
free(DeleteNode);
}
}
Node* SListFind(PSList pl, SDataType data)//找位置
{
assert(pl);
Node* pCur = pl->_pHead;
while (pCur)
{
if (pCur->_data == data)
return pCur;
pCur = pCur->_pNext;
}
return NULL;
}
void SListInsert(PSList pl, Node* pos, SDataType data)//任意位置插入(插在后面)
{
Node* pNewNode = NULL;
assert(pl);
pNewNode = BuySListNode(data);
pNewNode->_pNext = pos->_pNext;
pos->_pNext = pNewNode;
printf("插入成功:");
}
void SListErase(PSList pl, Node* pos)//任意位置删除
{
Node* prePos = NULL;
assert(pl);
if (pl->_pHead == NULL||pos==NULL)
{
printf("链表为空或位置,无法删除\n");
return;
}
if (pos == pl->_pHead)//pos刚好在第一个结点的位置
pl->_pHead = pos->_pNext;
else
{
prePos = pl->_pHead;
while (prePos->_pNext != pos)
{
prePos = prePos->_pNext;
}
prePos->_pNext = pos->_pNext;
}
free(pos);
printf("删除成功:");
}
void SListIsFindData(PSList pl, SDataType data)//检测data是否是链表中
{
assert(pl);
Node* pCur = pl->_pHead;
if (pl->_pHead == NULL)
{
printf("链表为空,无法检测");
return;
}
while (pCur)
{
if (pCur->_data == data)
{
printf("%d在链表中", data);
return;
}
pCur = pCur->_pNext;
}
printf("%d不在链表中",data);
return;
}
void SListRemove(PSList pl, SDataType data)// 移除链表中第一个值为data的元素
{
assert(pl);
if (pl->_pHead == NULL)
{
printf("链表为空,无法移除元素\n");
return;
}
Node* pCur = pl->_pHead;
Node* pPre = NULL;//pCur前一个结点
while (pCur->_pNext!=NULL)
{
while (pCur->_data != data)
{
if (pCur->_pNext == NULL)
{
printf("很遗憾,没有找到:");
return;
}
pPre = pCur;
pCur = pCur->_pNext;
}
if (pCur->_data==data)
{
if (pPre == NULL)
pl->_pHead = pCur->_pNext;
else
pPre->_pNext = pCur->_pNext;
free(pCur);
pCur = NULL;
printf("移除成功: ");
return;
}
}
}
//void SListRemoveAll(PSList pl, SDataType data)// 移除链表中所有值为data的元素
//{
// assert(pl);
// if (pl->_pHead == NULL)
// {
// printf("链表为空,无法移除元素\n");
// return;
// }
// Node* pCur = pl->_pHead;
// Node* pPre = NULL;//pCur的前一个结点
// while (pCur->_pNext!=NULL)
// {
// if (pCur->_data != data)
// {
// pPre = pCur;
// pCur = pCur->_pNext;
// }
// else
// {
// if (pPre == NULL)
// pl->_pHead = pCur->_pNext;
// else
// pPre->_pNext = pCur->_pNext;
// free(pCur);
// pCur = NULL;
// }
// }
//}
void SListSize(PSList pl)//// 获取链表有效元素个数
{
assert(pl);
int count = 1;
Node* pCur = pl->_pHead;
while (pCur->_pNext)
{
if (pCur->_pNext)
pCur = pCur->_pNext;
count++;
}
printf("有效元素个数为:%d :", count);
return;
}
int SListEmpty(PSList pl)// 检测链表是否为空
{
assert(pl);
if (pl->_pHead)
{
printf("链表不为空:");
return 0;
}
printf("链表为空:");
return 0;
}
SDataType SListFront(PSList pl)// 获取链表中第一个元素
{
assert(pl);
printf("链表中第一个元素为:%d: ", pl->_pHead->_data);
return pl->_pHead->_data;
}
SDataType SListBack(PSList pl)// 获取链表中最后一个元素
{
assert(pl);
Node* pCur = pl->_pHead;
while (pCur->_pNext)
{
pCur = pCur->_pNext;
}
printf("链表中最后一个元素为:%d: ", pCur->_data);
return pCur->_data;
}
void SListDestory(PSList pl)//销毁
{
Node* pCur = NULL;
assert(pl);
pCur = pl->_pHead;
while (pCur)
{
pl->_pHead = pCur->_pNext;//下个结点为第一个结点了
free(pCur);
pCur = pl->_pHead;
}
pl->_pHead = NULL;
printf("销毁成功:");
}
//////////////////////////////////////
void PrintSList(PSList pl)
{
Node* pCur = NULL;
assert(pl);
pCur = pl->_pHead;
while (pCur)
{
printf("%d-->", pCur->_data);
pCur = pCur->_pNext;
}
printf("NULL\n");
}
test.c文件
#include "SList.h"
int main()
{
SList s;
SListInit(&s);
SListPushBack(&s, 0);//尾插
SListPushBack(&s, 0);
SListPushBack(&s, 1);
SListPushBack(&s, 1);
SListPushBack(&s, 2);
SListPushBack(&s, 2);
SListPushBack(&s, 4);
SListPushBack(&s, 4);
SListPushBack(&s, 5);
SListPushBack(&s, 5);
SListPushBack(&s, 7);
SListPushBack(&s, 8);
SListPushBack(&s, 9);
SListPushBack(&s, 9);
PrintSList(&s);
SListPopBack(&s);//尾删
PrintSList(&s);
SListPushFront(&s, 0);//头插
PrintSList(&s);
SListPopFront(&s);//头删
PrintSList(&s);
//任意位置插入
Node* ret = SListFind(&s, 2);//找位置
SListInsert(&s, ret, 8);
PrintSList(&s);
//任意位置删除
ret = SListFind(&s, 2);
SListErase(&s, ret);
PrintSList(&s);
//检测data是否是链表中
SListIsFindData(&s, 2);
PrintSList(&s);
// 移除链表中第一个值为data的元素
SListRemove(&s, 0);
PrintSList(&s);
// 移除链表中所有值为data的元素
//SListRemoveAll(&s, 1);
//PrintSList(&s);
// 获取链表有效元素个数
SListSize(&s);//
PrintSList(&s);
// 检测链表是否为空
SListEmpty(&s);
PrintSList(&s);
//获取链表中的第一个元素
SListFront(&s);
PrintSList(&s);
//获取链表中的第一个元素
SListBack(&s);
PrintSList(&s);
//销毁链表
SListDestory(&s);
PrintSList(&s);
system("pause");
return 0;
}
运行结果如下: