前言?
? ? ? ? 單鏈表作為順序表的一種,了解并且熟悉它的結(jié)構(gòu)對(duì)于我們學(xué)習(xí)更加復(fù)雜的數(shù)據(jù)結(jié)構(gòu)是有一定意義的。雖然單鏈表有一定的缺陷,但是單鏈表也有它存在的價(jià)值,?它也是作為其他數(shù)據(jù)結(jié)構(gòu)的一部分出現(xiàn)的,比如在圖,哈希表中。
目錄
1.鏈表節(jié)點(diǎn)的結(jié)構(gòu)
2.頭插頭刪
3.尾插尾刪
4.任意位置的插入和刪除
5.查找鏈表的值和修改鏈表節(jié)點(diǎn)的值
6.銷毀鏈表
7.測(cè)試代碼
8.全部代碼
9.總結(jié)?
1.鏈表節(jié)點(diǎn)的結(jié)構(gòu)
? ? ? ? 單鏈表有節(jié)點(diǎn)的值和節(jié)點(diǎn)的next指針組成,如圖:
?
typedef int SListDatatype;
typedef struct SListNode
{
SListDatatype _data;//存儲(chǔ)節(jié)點(diǎn)的數(shù)據(jù)
struct SListNode* _next;
}SListNode;
2.頭插頭刪
? ? ? ? 頭插分為兩種情況,第一種是沒(méi)有節(jié)點(diǎn)的情況,第二種是?有節(jié)點(diǎn)的情況。如圖:
? ? ? ? ? ? ? ? 頭刪也分為兩種情況,如果只有一個(gè)節(jié)點(diǎn)的時(shí)候,直接刪除就行了,然后將頭結(jié)點(diǎn)置空。如果有多個(gè)節(jié)點(diǎn),需要先記錄頭結(jié)點(diǎn),然后再進(jìn)行刪除就可以了。
void SListPushFront(SListNode** ppHead, SListDatatype data)//頭插
{
SListNode* newNode = SlistBuyNode(data);//申請(qǐng)一個(gè)新的節(jié)點(diǎn)
if (*ppHead == NULL)
{
//鏈表為空
*ppHead = newNode;
return;
}
newNode->_next = (*ppHead);
*ppHead = newNode;//對(duì)頭結(jié)點(diǎn)進(jìn)行鏈接
}
void SListPopFront(SListNode** ppHead)//頭刪
{
assert(*ppHead);//確保指針的有效性
if ((*ppHead)->_next == NULL)
{
//鏈表只有一個(gè)節(jié)點(diǎn)
free(*ppHead);
*ppHead = NULL;
return;
}
//刪除頭結(jié)點(diǎn),然后更新頭結(jié)點(diǎn)
SListNode* newHead = (*ppHead)->_next;
free(*ppHead);
*ppHead = newHead;
return;
}
3.尾插尾刪
? ? ? ? 尾插也分為鏈表為空和指針不為空的情況,如果鏈表為空,申請(qǐng)節(jié)點(diǎn),讓鏈表的頭結(jié)點(diǎn)指向申請(qǐng)的節(jié)點(diǎn),然后將這個(gè)節(jié)點(diǎn)的_next置空,如果鏈表不為空,首先需要找到尾結(jié)點(diǎn),然后將尾結(jié)點(diǎn)與這個(gè)節(jié)點(diǎn)鏈接起來(lái),再將這個(gè)新申請(qǐng)的節(jié)點(diǎn)的_next置空。如圖:
?
? ? ? ? 尾刪也分為兩種情況:1只有一個(gè)節(jié)點(diǎn)和2存在多個(gè)節(jié)點(diǎn)
如果只有一個(gè)節(jié)點(diǎn),刪除以后需要將頭結(jié)點(diǎn)置空,防止出現(xiàn)野指針的問(wèn)題。
如果有多個(gè)節(jié)點(diǎn),刪除尾結(jié)點(diǎn)以后需要將新的尾結(jié)點(diǎn)置空。
如圖:?
void SListPushBack(SListNode** ppHead, SListDatatype data)//尾插
{
SListNode*newNode = SlistBuyNode(data);//申請(qǐng)一個(gè)新的節(jié)點(diǎn)
if (*ppHead == NULL)//鏈表為空
{
*ppHead = newNode;
return;
}
if ((*ppHead)->_next == NULL)//鏈表只存在一個(gè)節(jié)點(diǎn)
{
(*ppHead)->_next = newNode;
return;
}
SListNode* cur = *ppHead;
while (cur->_next)//找到尾節(jié)點(diǎn)
{
cur = cur->_next;
}
cur->_next = newNode;//進(jìn)行鏈接
return;
}
void SListPopBack(SListNode** ppHead)//尾刪
{
assert(*ppHead);
if (*ppHead == NULL)//鏈表為空不需要?jiǎng)h除
{
return;
}
if ((*ppHead)->_next == NULL)
{
free(*ppHead);//鏈表只有一個(gè)節(jié)點(diǎn)
(*ppHead) = NULL;
return;
}
SListNode* cur = *ppHead;
SListNode* prev = NULL;
while (cur->_next)//找到尾結(jié)點(diǎn)
{
prev = cur;//保存上一個(gè)節(jié)點(diǎn)
cur = cur->_next;
}
free(cur);//釋放尾結(jié)點(diǎn)所在的空間
prev->_next = NULL;//將上一個(gè)節(jié)點(diǎn)的_next置空
return;
4.任意位置的插入和刪除
? ? ? ? 由于單鏈表結(jié)構(gòu)的限制,這里只實(shí)現(xiàn)了在pos位置之后的插入和刪除,如果刪除pos的后一個(gè)節(jié)點(diǎn)就需要確保pos的后一個(gè)節(jié)點(diǎn)是存在的,否則就會(huì)出現(xiàn)問(wèn)題。
void SListInsertAfter(SListNode*pos, SListDatatype data)//任意位置的插入,在pos之后插入
{
assert(pos);//確保指針不為空
SListNode* newNode = SlistBuyNode(data);
SListNode* next = pos->_next;
pos->_next = newNode;
newNode->_next = next;
}
void SListErase(SListNode*pos)//任意位置的刪除,pox位置之后的刪除
{
assert(pos);//確保節(jié)點(diǎn)的有效性
//如果只有一個(gè)節(jié)點(diǎn)
if (pos->_next )//pos節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)存在
{
SListNode* next = pos->_next;
SListNode* nextNext = next->_next;
free(next);//刪除節(jié)點(diǎn),重新鏈接
pos->_next = nextNext;
}
}
5.查找鏈表的值和修改鏈表節(jié)點(diǎn)的值
? ? ? ? 遍歷鏈表就可以對(duì)鏈表中的數(shù)據(jù)進(jìn)行查找,找到查找的值,就可以對(duì)節(jié)點(diǎn)的值進(jìn)行修改。?
SListNode* SListFind(SListNode* pHead, SListDatatype data)//查找
{
SListNode* cur = pHead;
while (cur)
{
if (cur->_data == data)
return cur;
cur = cur->_next;//迭代向后走
}
return NULL;//找不到
}
?
void testSList()
{
//查找和修改的測(cè)試
SListNode* pHead = NULL;
SListPushFront(&pHead, 1);
SListPushFront(&pHead, 2);
SListPushFront(&pHead, 3);
SListPushFront(&pHead, 4);
SListPushFront(&pHead, 5);
SListPushFront(&pHead, 6);
SListPrint(pHead);
SListNode* node = SListFind(pHead, 5);//查找
if (node)
{
//節(jié)點(diǎn)的數(shù)據(jù)
node->_data = 50;
}
SListPrint(pHead);
}
6.銷毀鏈表
void SListDestory(SListNode** ppHead)//銷毀
{
assert(*ppHead);
//確保指針有效性
SListNode* cur = *ppHead;
while (cur)
{
SListNode* freeNode = cur;
cur = cur->_next;
free(freeNode);
}
*ppHead = NULL;
}
?
7.測(cè)試代碼
void testSListBack()
{
//尾插尾刪的測(cè)試代碼
SListNode* pHead = NULL;
SListPushBack(&pHead, 1);
SListPushBack(&pHead, 2);
SListPushBack(&pHead, 3);
SListPushBack(&pHead, 4);
SListPushBack(&pHead, 5);
SListPushBack(&pHead, 6);
SListPrint(pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
}
void testSListFront()
{
//頭插頭刪的測(cè)試代碼
SListNode* pHead = NULL;
SListPushFront(&pHead, 1);
SListPushFront(&pHead, 2);
SListPushFront(&pHead, 3);
SListPushFront(&pHead, 4);
SListPushFront(&pHead, 5);
SListPushFront(&pHead, 6);
SListPrint(pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
}
void testSList()
{
//查找和修改的測(cè)試
SListNode* pHead = NULL;
SListPushFront(&pHead, 1);
SListPushFront(&pHead, 2);
SListPushFront(&pHead, 3);
SListPushFront(&pHead, 4);
SListPushFront(&pHead, 5);
SListPushFront(&pHead, 6);
SListPrint(pHead);
SListNode* node = SListFind(pHead, 5);//查找
if (node)
{
//節(jié)點(diǎn)的數(shù)據(jù)
node->_data = 50;
}
SListPrint(pHead);
}
void TestSList1()
{
//對(duì)在pos節(jié)點(diǎn)之后進(jìn)行插入和刪除的測(cè)試
SListNode* pHead = NULL;
SListPushFront(&pHead, 1);
SListPushFront(&pHead, 2);
SListPushFront(&pHead, 3);
SListPushFront(&pHead, 4);
SListPushFront(&pHead, 5);
SListPushFront(&pHead, 6);
SListPrint(pHead);
SListNode* node = SListFind(pHead, 5);//查找
if (node)
{
//插入節(jié)點(diǎn)
SListInsertAfter(node, -2);
SListPrint(pHead);
SListErase(node);
SListPrint(pHead);
}
SListDestory(&pHead);
}
8.全部代碼
//SList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
typedef int SListDatatype;
typedef struct SListNode
{
SListDatatype _data;//存儲(chǔ)節(jié)點(diǎn)的數(shù)據(jù)
struct SListNode* _next;
}SListNode;
SListNode* SlistBuyNode(SListDatatype data);
void SListDestory(SListNode** ppHead);//銷毀
void SListPushBack(SListNode**ppHead,SListDatatype data);//尾插
void SListPopBack(SListNode** ppHead );//尾刪
void SListPushFront(SListNode** ppHead, SListDatatype data);//頭插
void SListPopFront(SListNode** ppHead);//頭刪
void SListInsertAfter(SListNode* pos, SListDatatype data);//任意位置的插入
void SListErase(SListNode*pos);//任意位置的刪除
SListNode* SListFind(SListNode*pHead, SListDatatype data);//查找
void SListPrint(SListNode* pHead);//顯示鏈表數(shù)據(jù)
//void SListDestory(SListNode** ppHead);//刪除鏈表
?//SList.c
#include"SList.h"
SListNode* SlistBuyNode(SListDatatype data)
{
SListNode*newNode = (SListNode*)malloc(sizeof(SListNode));
if (newNode == NULL)
{
//申請(qǐng)節(jié)點(diǎn)失敗
printf("申請(qǐng)節(jié)點(diǎn)失敗\n");
exit(-1);//暴力返回
}
newNode->_data = data;//給節(jié)點(diǎn)賦值
newNode->_next = NULL;
return newNode;
}
void SListDestory(SListNode** ppHead)//銷毀
{
assert(*ppHead);
//確保指針有效性
SListNode* cur = *ppHead;
while (cur)
{
SListNode* freeNode = cur;
cur = cur->_next;
free(freeNode);
}
*ppHead = NULL;
}
void SListPushBack(SListNode** ppHead, SListDatatype data)//尾插
{
SListNode*newNode = SlistBuyNode(data);//申請(qǐng)一個(gè)新的節(jié)點(diǎn)
if (*ppHead == NULL)//鏈表為空
{
*ppHead = newNode;
return;
}
if ((*ppHead)->_next == NULL)//鏈表只存在一個(gè)節(jié)點(diǎn)
{
(*ppHead)->_next = newNode;
return;
}
SListNode* cur = *ppHead;
while (cur->_next)//找到尾節(jié)點(diǎn)
{
cur = cur->_next;
}
cur->_next = newNode;//進(jìn)行鏈接
return;
}
void SListPopBack(SListNode** ppHead)//尾刪
{
assert(*ppHead);
if (*ppHead == NULL)//鏈表為空不需要?jiǎng)h除
{
return;
}
if ((*ppHead)->_next == NULL)
{
free(*ppHead);//鏈表只有一個(gè)節(jié)點(diǎn)
(*ppHead) = NULL;
return;
}
SListNode* cur = *ppHead;
SListNode* prev = NULL;
while (cur->_next)//找到尾結(jié)點(diǎn)
{
prev = cur;//保存上一個(gè)節(jié)點(diǎn)
cur = cur->_next;
}
free(cur);//釋放尾結(jié)點(diǎn)所在的空間
prev->_next = NULL;//將上一個(gè)節(jié)點(diǎn)的_next置空
return;
}
void SListPushFront(SListNode** ppHead, SListDatatype data)//頭插
{
SListNode* newNode = SlistBuyNode(data);//申請(qǐng)一個(gè)新的節(jié)點(diǎn)
if (*ppHead == NULL)
{
//鏈表為空
*ppHead = newNode;
return;
}
newNode->_next = (*ppHead);
*ppHead = newNode;//對(duì)頭結(jié)點(diǎn)進(jìn)行鏈接
}
void SListPopFront(SListNode** ppHead)//頭刪
{
assert(*ppHead);//確保指針的有效性
if ((*ppHead)->_next == NULL)
{
//鏈表只有一個(gè)節(jié)點(diǎn)
free(*ppHead);
*ppHead = NULL;
return;
}
//刪除頭結(jié)點(diǎn),然后更新頭結(jié)點(diǎn)
SListNode* newHead = (*ppHead)->_next;
free(*ppHead);
*ppHead = newHead;
return;
}
void SListInsertAfter(SListNode*pos, SListDatatype data)//任意位置的插入,在pos之后插入
{
assert(pos);//確保指針不為空
SListNode* newNode = SlistBuyNode(data);
SListNode* next = pos->_next;
pos->_next = newNode;
newNode->_next = next;
}
void SListErase(SListNode*pos)//任意位置的刪除,pox位置之后的刪除
{
assert(pos);//確保節(jié)點(diǎn)的有效性
//如果只有一個(gè)節(jié)點(diǎn)
if (pos->_next )//pos節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)存在
{
SListNode* next = pos->_next;
SListNode* nextNext = next->_next;
free(next);//刪除節(jié)點(diǎn),重新鏈接
pos->_next = nextNext;
}
}
SListNode* SListFind(SListNode* pHead, SListDatatype data)//查找
{
SListNode* cur = pHead;
while (cur)
{
if (cur->_data == data)
return cur;
cur = cur->_next;//迭代向后走
}
return NULL;//找不到
}
void SListPrint(SListNode* pHead)//顯示鏈表數(shù)據(jù)
{
assert(pHead);//確保指針的有效性
SListNode* cur = pHead;
while (cur)
{
printf("%d ", cur->_data);
printf("->");
cur = cur->_next;
}
printf("NULL\n");
}
//test.c
#include"SList.h"
void testSListBack()
{
//尾插尾刪的測(cè)試代碼
SListNode* pHead = NULL;
SListPushBack(&pHead, 1);
SListPushBack(&pHead, 2);
SListPushBack(&pHead, 3);
SListPushBack(&pHead, 4);
SListPushBack(&pHead, 5);
SListPushBack(&pHead, 6);
SListPrint(pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
SListPopBack(&pHead);
}
void testSListFront()
{
//頭插頭刪的測(cè)試代碼
SListNode* pHead = NULL;
SListPushFront(&pHead, 1);
SListPushFront(&pHead, 2);
SListPushFront(&pHead, 3);
SListPushFront(&pHead, 4);
SListPushFront(&pHead, 5);
SListPushFront(&pHead, 6);
SListPrint(pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
SListPopFront(&pHead);
}
void testSList()
{
//查找和修改的測(cè)試
SListNode* pHead = NULL;
SListPushFront(&pHead, 1);
SListPushFront(&pHead, 2);
SListPushFront(&pHead, 3);
SListPushFront(&pHead, 4);
SListPushFront(&pHead, 5);
SListPushFront(&pHead, 6);
SListPrint(pHead);
SListNode* node = SListFind(pHead, 5);//查找
if (node)
{
//節(jié)點(diǎn)的數(shù)據(jù)
node->_data = 50;
}
SListPrint(pHead);
}
void TestSList1()
{
//對(duì)在pos節(jié)點(diǎn)之后進(jìn)行插入和刪除的測(cè)試
SListNode* pHead = NULL;
SListPushFront(&pHead, 1);
SListPushFront(&pHead, 2);
SListPushFront(&pHead, 3);
SListPushFront(&pHead, 4);
SListPushFront(&pHead, 5);
SListPushFront(&pHead, 6);
SListPrint(pHead);
SListNode* node = SListFind(pHead, 5);//查找
if (node)
{
//插入節(jié)點(diǎn)
SListInsertAfter(node, -2);
SListPrint(pHead);
SListErase(node);
SListPrint(pHead);
}
SListDestory(&pHead);
}
int main()
{
TestSList1();
return 0;
}
?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-644026.html
9.總結(jié)?
? ? ? ? 鏈表與順序表區(qū)別和聯(lián)系。順序表是在數(shù)組的基礎(chǔ)上實(shí)現(xiàn)增刪查改的。并且插入時(shí)可以動(dòng)態(tài)增長(zhǎng)。順序表的缺陷:可能存在空間的浪費(fèi),增容有一定的效率損失,中間或者頭部數(shù)據(jù)的刪除,時(shí)間復(fù)雜度是O(n),因?yàn)橐矂?dòng)數(shù)據(jù)。這些問(wèn)題都是由鏈表來(lái)解決的,但是鏈表也有自己的缺陷,不能隨機(jī)訪問(wèn),存在內(nèi)存碎片等問(wèn)題。?其實(shí)沒(méi)有哪一種數(shù)據(jù)結(jié)構(gòu)是完美的,它們都有各自的缺陷,實(shí)際中的使用都是相輔相成的。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-644026.html
到了這里,關(guān)于數(shù)據(jù)結(jié)構(gòu)——單鏈表的實(shí)現(xiàn)(c語(yǔ)言版)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!