單鏈表是一種鏈式存取的數據結構,用申請的地址存放每個節點,這些地址可能是連續,也可能是不連續的。每個結點的構成:元素(數據元素的映象,data) + 指針(指示後繼元素存儲位置,next)。通過指針將線性表的數據一個個串聯起來,要想訪問一個數據,就要知道前一個指針,想知道前一個就要知道前前一個,依次向前找。所以,一般訪問是從頭指針開始向後查找目標,方向是單向的。
頭指針一般是固定的,而尾指針隨着鏈表的增加或刪除可能會改變,但是尾指針的後繼節點一定是指向空,即NULL的。
下面便是單鏈表的增、刪、查、改操作。
SingleLinkedList.h(頭文件)
#pragma once
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<Windows.h>
typedef int DataType;
typedef struct SListNode
{
struct SListNode* _next;
DataType _data;
}SListNode;
SListNode* pStructInit();//結構體指針初始
SListNode* BuySListNode(DataType x);//創建節點
void SListPrint(SListNode* pHead);//打印
void SListDestory(SListNode** ppHead);//銷燬
void SListPushBack(SListNode** ppHead, DataType x);//尾插
void SListPopBack(SListNode** ppHead);//尾刪
void SListPushFront(SListNode** ppHead, DataType x);//頭插
void SListPopFront(SListNode** ppHead);//頭刪
SListNode* SListFind(SListNode* pHead, DataType x);//查找
void SListInsert(SListNode** ppHead, SListNode* pos, DataType x);//pos前插入
void SListErase(SListNode** ppHead, SListNode* pos);//pos位置刪除
void SListAt(SListNode** ppHead, SListNode *pos, DataType x);//替換
SingleLinkedList.c(功能函數的實現)
#include"SingleLinkedList.h"
SListNode* pStructInit()//結構體指針初始
{
SListNode* pStruct = (SListNode*)malloc(sizeof(SListNode));
if (pStruct == NULL)
{
perror("Initialize fail");
exit(1);
}
pStruct->_next = NULL;
return pStruct;
}
SListNode* BuySListNode(DataType x)//創建節點
{
SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
if (tmp == NULL)
{
perror("Malloc fail");
exit(1);
}
tmp->_data = x;
tmp->_next = NULL;
return tmp;
}
void SListPrint(SListNode* pHead)//打印單鏈表
{
assert(pHead);
SListNode* pnode = pHead->_next;
while (pnode)
{
printf("%d ", pnode->_data);
pnode = pnode->_next;
}
printf("\n");
}
void SListDestory(SListNode** ppHead)//銷燬
{
SListNode* tmp = NULL;
while (*ppHead)
{
tmp = (*ppHead)->_next;
free(*ppHead);
(*ppHead) = tmp;
}
}
void SListPushBack(SListNode** ppHead, DataType x)//尾插
{
assert(ppHead);
SListNode* tmp = *ppHead;
if (ppHead == NULL)
{
*ppHead = BuySListNode(x);
return;
}
while (tmp->_next)
{
tmp = tmp->_next;
}
tmp->_next = BuySListNode(x);
}
void SListPopBack(SListNode** ppHead)//尾刪
{
assert(ppHead);
SListNode* tmp = *ppHead;
if ((tmp->_next)==NULL)//無節點
{
return;
}
else//有節點
{
while (tmp->_next->_next)
{
tmp = tmp->_next;
}
//將最後一個元素銷燬置空
free(tmp->_next);
tmp->_next = NULL;
}
}
void SListPushFront(SListNode** ppHead, DataType x)//頭插
{
assert(ppHead);
if ((*ppHead) == NULL)
{
*ppHead = BuySListNode(x);
(*ppHead)->_next = NULL;
}
else
{
SListNode *tmp = BuySListNode(x);
tmp->_next = (*ppHead)->_next;
(*ppHead)->_next = tmp;
}
}
void SListPopFront(SListNode** ppHead)//頭刪
{
assert(ppHead);
if ((*ppHead)->_next == NULL)
{
return;
}
else
{
SListNode *tmp = (*ppHead)->_next;
(*ppHead)->_next = tmp->_next;
free(tmp);
tmp = NULL;
}
}
SListNode* SListFind(SListNode* pHead, DataType x)//查找
{
SListNode* tmp = pHead;
while (tmp)
{
if (tmp->_data == x)
return tmp;
else
tmp = tmp->_next;
}
return NULL;
}
void SListInsert(SListNode** ppHead, SListNode* pos, DataType x)//pos前插入
{
assert(ppHead && pos);
SListNode *p = (*ppHead);
SListNode *q = BuySListNode(x);
while (p->_next != pos)
{
p = p->_next;
}
p->_next = q;
q->_next = pos;
}
void SListErase(SListNode** ppHead, SListNode* pos)//pos位置刪除
{
assert(ppHead && pos);
SListNode* tmp = *ppHead;
while (tmp->_next != pos)
{
tmp = tmp->_next;
}
tmp->_next = pos->_next;
free(pos);
pos = NULL;
}
void SListAt(SListNode** ppHead, SListNode *pos, DataType x)//替換
{
assert(ppHead && pos);
SListNode *tmp = *ppHead;
while (tmp->_next != pos)
{
tmp = tmp->_next;
}
tmp->_next->_data = x;
}
Test.c(測試)
#include"SingleLinkedList.h"
void TestPushBack(SListNode *list)//尾插
{
SListPushBack(&list, 1);
SListPrint(list);
SListPushBack(&list, 2);
SListPrint(list);
SListPushBack(&list, 3);
SListPrint(list);
SListDestory(&list);
}
void TestPopBack(SListNode *list)//尾刪
{
SListNode*tmp = list;
//先插入3個數字
SListPushBack(&list, 1);
SListPushBack(&list, 2);
SListPushBack(&list, 3);
SListPrint(list);
list = tmp;
//開始尾刪
SListPopBack(&tmp);
SListPrint(tmp);
SListPopBack(&tmp);
SListPrint(tmp);
SListPopBack(&tmp);
SListPrint(tmp);
SListDestory(&list);
}
void TestPushFront(SListNode *list)//頭插
{
SListPushFront(&list, 1);
SListPrint(list);
SListPushFront(&list, 2);
SListPrint(list);
SListPushFront(&list, 3);
SListPrint(list);
SListDestory(&list);
}
void TestPopFront(SListNode *list)//頭刪
{
SListPushFront(&list, 1);
SListPushFront(&list, 2);
SListPushFront(&list, 3);
SListPrint(list);
SListPopFront(&list);
SListPrint(list);//刪掉3剩下2和1
SListPopFront(&list);
SListPrint(list);//剩下1
SListPopFront(&list);
SListPrint(list);//空
SListPopFront(&list);
SListPrint(list);//空
SListDestory(&list);
}
void TestInsert(SListNode *list)//pos前插入
{
SListNode*pos = NULL;
//尾插
SListPushBack(&list, 7);
SListPushBack(&list, 8);
SListPushBack(&list, 9);
//頭插
SListPushFront(&list, 3);
SListPushFront(&list, 2);
SListPushFront(&list, 1);
SListPrint(list);
pos = SListFind(list,7);
SListInsert(&list,pos, 6);
SListPrint(list);
pos = SListFind(list, 6);
SListInsert(&list, pos, 5);
SListPrint(list);
pos = SListFind(list, 5);
SListInsert(&list, pos, 4);
SListPrint(list);
/*pos = SListFind(list, 20);//因爲鏈表沒有20,pos爲空指針,在SListInsert函數的斷言會報錯
SListInsert(&list, pos, 10);
SListPrint(list);*/
SListDestory(&list);
}
void TestErase(SListNode *list)//pos位置刪除
{
SListNode*pos = NULL;
//尾插
SListPushBack(&list, 7);
SListPushBack(&list, 8);
SListPushBack(&list, 9);
//頭插
SListPushFront(&list, 3);
SListPushFront(&list, 2);
SListPushFront(&list, 1);
SListPrint(list);
pos = SListFind(list,1);
SListErase(&list, pos);
SListPrint(list);
pos = SListFind(list, 2);
SListErase(&list, pos);
SListPrint(list);
pos = SListFind(list, 3);
SListErase(&list, pos);
SListPrint(list);
pos = SListFind(list, 7);
SListErase(&list, pos);
SListPrint(list);
pos = SListFind(list, 8);
SListErase(&list, pos);
SListPrint(list);
pos = SListFind(list, 9);
SListErase(&list, pos);
SListPrint(list);
SListDestory(&list);
}
void TestFind(SListNode *list)//查找
{
SListPushBack(&list, 1);
SListPushBack(&list, 2);
SListPushBack(&list, 3);
//數據存在,打印該數據;查找不存在數據會發生異常
printf("%d\n", SListFind(list, 3)->_data);
printf("%d\n", SListFind(list, 2)->_data);
printf("%d\n", SListFind(list, 1)->_data);
//printf("%d\n", SListFind(list, 0)->_data);//鏈表內沒有數據data存放0,因此返回NULL,而用空指針訪問data數據會異常
SListDestory(&list);
}
void TestAt(SListNode *list)//替換
{
SListNode*pos = NULL;
//頭插
SListPushFront(&list, 3);
SListPushFront(&list, 2);
SListPushFront(&list, 0);
//尾插
SListPushBack(&list, 4);
SListPushBack(&list, 8);
SListPushBack(&list, 9);
SListPrint(list);
pos = SListFind(list, 0);
SListAt(&list, pos, 1);
SListPrint(list);
pos = SListFind(list, 8);
SListAt(&list, pos, 5);
SListPrint(list);
pos = SListFind(list, 9);
SListAt(&list, pos, 6);
SListPrint(list);
SListDestory(&list);
}
int main()//想要測試哪個,則放開前面的雙斜線
{
SListNode *list = pStructInit();
//TestPushBack(list);//尾插
//TestPopBack(list);//尾刪
//TestPushFront(list);//頭插
//TestPopFront(list);//頭刪
//TestInsert(list);//pos前插入
//TestErase(list);//pos位置刪除
//TestFind(list);//查找
//TestAt(list);//替換
system("pause");
return 0;
}