因爲順序表的底層空間是連續的,所以如果對元素進行大量的任意位置添加或刪除,在順序表裏就要移動大量的元素,效率很低,因此我們需要讓元素存儲在不連續的空間中,但如果直接存儲,就不知道它的下一個元素是什麼,這時就可以利用鏈表這個結構
鏈表是一種物理存儲結構上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的鏈接次序實現(除了存儲元素信息外,還要給下一個節點的位置)
找到第一個節點,就可以通過鏈式結構找到下一個節點
鏈表:
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;
}
運行結果如下: