C語(yǔ)言學(xué)習(xí)之鏈表的實(shí)現(xiàn)詳解
一、鏈表的概念
鏈表是一種物理存儲(chǔ)結(jié)構(gòu)上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過(guò)鏈表中的指針鏈接次序?qū)崿F(xiàn)的
二、鏈表的結(jié)構(gòu)
(1)單鏈表

(2)帶頭結(jié)點(diǎn)的單鏈表

(3)雙向鏈表

(4)循環(huán)單鏈表

(5)雙向循環(huán)鏈表

注釋:
(1)無(wú)頭單向非循環(huán)鏈表:結(jié)構(gòu)簡(jiǎn)單,一般不會(huì)單獨(dú)用來(lái)存數(shù)據(jù)。實(shí)際中更多是作為其他數(shù)據(jù)結(jié)構(gòu)的子結(jié)構(gòu),如哈希桶、圖的鄰接表等等。
(2)帶頭雙向循環(huán)鏈表:結(jié)構(gòu)最復(fù)雜,一般用在單獨(dú)存儲(chǔ)數(shù)據(jù)。實(shí)際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表。另外這個(gè)結(jié)構(gòu)雖然結(jié)構(gòu)復(fù)雜,但是使用代碼實(shí)現(xiàn)以后會(huì)發(fā)現(xiàn)結(jié)構(gòu)會(huì)帶來(lái)很多優(yōu)勢(shì),實(shí)現(xiàn)反而簡(jiǎn)單了。
三、順序表和鏈表的區(qū)別和聯(lián)系
(1)順序表:
優(yōu)點(diǎn): 空間連續(xù),支持隨機(jī)訪問(wèn)。
缺點(diǎn): 中間或前面部分的插入刪除時(shí)間復(fù)雜度為O(n),并且增容代價(jià)比較大。
(2)鏈表
優(yōu)點(diǎn): 任意位置插入刪除時(shí)間復(fù)雜度為O(1) 2.沒(méi)有增容問(wèn)題,插入一個(gè)開(kāi)辟一個(gè)空間。
缺點(diǎn): 以節(jié)點(diǎn)為單位存儲(chǔ),不支持隨機(jī)訪問(wèn)。
四、鏈表的實(shí)現(xiàn)
(1)單鏈表的增刪查找等操作
#pragma once
#include"common.h"
typedef struct SListNode
{
ElemType data;
struct SListNode* next;
}SListNode;
typedef struct SList
{
SListNode* head;
}SList;
///
///
//單鏈表的函數(shù)接口聲明
void SListInit(SList* plist);
static SListNode* _Buynode(ElemType x);
void SListPushBack(SList* plist, ElemType item);//1
void SListPushFront(SList* plist, ElemType item);//2
void SListShow(SList* plist);//3
void SListPopBack(SList* plist);//4
void SListPopFront(SList* plist);//5
void SListInsertVal(SList* plist, ElemType val);//7
void SqListDeleteByVal(SList* plist, ElemType val);//9
SListNode* SListFind(SList* plist, ElemType key);//10
size_t SListLength(SList* plist);//11
void SListSort(SList* plist);//13
void SListReverse(SList* plist);//14
void SListClear(SList* plist);//15
void SListDestroy(SList* plist);
///
///
//單鏈表的函數(shù)接口實(shí)現(xiàn)
void SListInit(SList* plist)
{
plist->head = NULL;
}
static SListNode* _Buynode(ElemType x)
{
SListNode* s = (SListNode*)malloc(sizeof(SListNode));
assert(s != NULL);
s->data = x;
s->next = NULL;
return s;
}
//1
void SListPushBack(SList* plist, ElemType item)
{
assert(plist != NULL);
SListNode* s = _Buynode(item);
//插入的節(jié)點(diǎn)為第一個(gè)節(jié)點(diǎn)
if (plist->head == NULL)
{
plist->head = s;
return;
}
//O(n)
SListNode* p = plist->head;
//查找鏈表的尾部節(jié)點(diǎn)
while (p->next != NULL)
{
p = p->next;
}
p->next = s;
}
//2
void SListPushFront(SList* plist, ElemType item)
{
assert(plist != NULL);
SListNode* s = _Buynode(item);
s->next = plist->head;
plist->head = s;
}
//3
void SListShow(SList* plist)
{
assert(plist != NULL);
SListNode* p = plist->head;
while (p != NULL)
{
printf("%d-->", p->data);
p = p->next;
}
printf("Over.\n");
}
//4
void SListPopBack(SList* plist)
{
assert(plist != NULL);
SListNode* p = plist->head;
if (plist->head == NULL)
{
printf("單鏈表為空,輸出失敗!\n");
return;
}
if (p->next == NULL)
{
plist->head = NULL;
return;
}
SListNode* prev = NULL;
while (p->next != NULL)
{
prev = p;
p = p->next;
}
prev->next = NULL;
free(p);
}
//5
void SListPopFront(SList* plist)
{
assert(plist != NULL);
SListNode* p = plist->head;
if (plist->head == NULL)
{
printf("單鏈表為空,輸出失敗!\n");
return;
}
plist->head = p->next;
free(p);
}
//6
//7
void SListInsertVal(SList* plist, ElemType val)
{
assert(plist != NULL);
SListNode* prev = NULL;
SListNode* p = plist->head;
SListNode* s = _Buynode(val);
while (p != NULL && val > p->data)
{
prev = p;
p = p->next;
}
if (prev == NULL)
{
s->next = p;
plist->head = s;
}
else
{
s->next = prev->next;
prev->next = s;
}
}
//10
SListNode* SListFind(SList* plist, ElemType key)
{
assert(plist != NULL);
SListNode* p = plist->head;
while (p != NULL && p->data != key)
p = p->next;
return p;
}
//9
void SqListDeleteByVal(SList* plist, ElemType val)
{
assert(plist != NULL);
SListNode* prev = NULL;
SListNode* p = SListFind(plist, val);
if (p == NULL)
{
printf("要?jiǎng)h除的節(jié)點(diǎn)不存在.\n");
return;
}
if (p == plist->head)
plist->head = p->next;
else
{
prev = plist->head;
while (prev->next != p)
prev = prev->next;
//刪除
prev->next = p->next;
}
free(p);
}
//11
size_t SListLength(SList* plist)
{
assert(plist != NULL);
size_t len = 0;
SListNode* p = plist->head;
while (p != NULL)
{
len++;
p = p->next;
}
return len;
}
//13
void SListSort(SList* plist)
{
assert(plist != NULL);
SListNode* p = plist->head->next;
SListNode* q, * t, * prev = NULL;
plist->head->next = NULL; //斷開(kāi)鏈表
t = plist->head;
while (p != NULL)
{
q = p->next;
while (t != NULL && p->data > t->data)
{
prev = t;
t = t->next;
}
if (prev == NULL)
{
p->next = plist->head;
plist->head = p;
}
else //if(prev->next!=NULL)
{
p->next = prev->next;
prev->next = p;
}
p = q;
t = plist->head;
}
}
//14
void SListReverse(SList* plist)
{
assert(plist != NULL);
SListNode* p = plist->head->next;
SListNode* q;
if (p->next == NULL)
return;
//斷開(kāi)第一個(gè)節(jié)點(diǎn)
plist->head->next = NULL;
while (p != NULL)
{
q = p->next;
p->next = plist->head;
plist->head = p;
p = q;
}
}
//15
void SListClear(SList* plist)
{
assert(plist != NULL);
SListNode* p = plist->head;
while (p != NULL)
{
plist->head = p->next;
free(p);
p = plist->head;
}
}
void SListDestroy(SList* plist)
{
SListClear(plist);
plist->head = NULL;
}
```c
(2)帶頭的雙循環(huán)鏈表的實(shí)現(xiàn)
#pragma once
#include"common.h"
/
//帶頭的雙循環(huán)鏈表
typedef struct DCListNode
{
ElemType data;
struct DCListNode* next;
struct DCListNode* prev;
}DCListNode;
typedef struct DCList
{
DCListNode* head;
}DCList;
static DCListNode* _Buydnode(ElemType x);
void DCListInit(DCList* plist);
void DCListDestroy(DCList* plist);
void DCListPushBack(DCList* plist, ElemType x);//1
void DCListPushFront(DCList* plist, ElemType x);//2
void DCListShow(DCList* plist);//3
void DCListPopBack(DCList* plist);//4
void DCListPopFront(DCList* plist);//5
void DCListInsertByVal(DCList* plist, ElemType val);//7
void DCListDeleteByVal(DCList* plist, ElemType val);//9
size_t DCListLength(DCList* plist);//11
void DCListSort(DCList* plist);//13
void DCListReverse(DCList* plist);//14
void DCListClear(DCList* plist);//15
DCListNode* DCListFind(DCList* plist, ElemType key);//10
static DCListNode* _Buydnode(ElemType x)
{
DCListNode* s = (DCListNode*)malloc(sizeof(DCListNode));
assert(s != NULL);
s->data = x;
s->next = s->prev = s;
return s;
}
void DCListInit(DCList* plist)
{
plist->head = _Buydnode(0);
}
//1
void DCListPushBack(DCList* plist, ElemType x)
{
assert(plist != NULL);
DCListNode* s = _Buydnode(x);
s->prev = plist->head->prev;
s->prev->next = s;
s->next = plist->head;
plist->head->prev = s;
}
//2
void DCListPushFront(DCList* plist, ElemType x)
{
assert(plist != NULL);
DCListNode* s = _Buydnode(x);
s->next = plist->head->next;
s->next->prev = s;
plist->head->next = s;
s->prev = plist->head;
}
//3
void DCListShow(DCList* plist)
{
assert(plist != NULL);
DCListNode* p = plist->head->next;
while (p != plist->head)
{
printf("%d->", p->data);
p = p->next;
}
printf("Over.\n");
}
//4
void DCListPopBack(DCList* plist)
{
assert(plist != NULL);
DCListNode* p = plist->head->prev;
if (plist->head->next == plist->head)
//if(p == plist->head)
{
printf("循環(huán)雙鏈表只有頭結(jié)點(diǎn),操作失敗.\n");
return;
}
plist->head->prev = p->prev;
p->prev->next = plist->head;
free(p);
}
//5
void DCListPopFront(DCList* plist)
{
assert(plist != NULL);
DCListNode* p = plist->head->next;
if (p == plist->head)
{
printf("循環(huán)雙鏈表只有頭結(jié)點(diǎn),操作失敗.\n");
return;
}
plist->head->next = p->next;
p->next->prev = plist->head;
free(p);
}
//7
void DCListInsertByVal(DCList* plist, ElemType val)
{
assert(plist != NULL);
DCListNode* p = plist->head->next;
while (p != plist->head && p->data < val)
{
p = p->next;
}
DCListNode* s = _Buydnode(val);
s->next = p;
s->prev = p->prev;
p->prev->next = s;
p->prev = s;
}
//9
void DCListDeleteByVal(DCList* plist, ElemType val)
{
assert(plist != NULL);
DCListNode* p = DCListFind(plist, val);
if (p == NULL)
return;
p->next->prev = p->prev;
p->prev->next = p->next;
free(p);
}
//10
DCListNode* DCListFind(DCList* plist, ElemType key)
{
assert(plist != NULL);
DCListNode* p = plist->head->next;
if (p == plist->head)
{
printf("雙循環(huán)鏈表只有頭結(jié)點(diǎn),查找失敗.\n");
return 0;
}
while (p != plist->head && p->data != key)
{
p = p->next;
}
if (p != plist->head)
return p;
return NULL;
}
//11
size_t DCListLength(DCList* plist)
{
assert(plist != NULL);
size_t len = 0;
DCListNode* p = plist->head->next;
while (p != plist->head)
{
len++;
p = p->next;
}
return len;
}
//13
void DCListSort(DCList* plist)
{
assert(plist != NULL);
DCListNode* p = plist->head->next;
DCListNode* q = p->next;
//斷開(kāi)鏈表
p->next = plist->head;
plist->head->prev = p;
while (q != plist->head)
{
p = q;
q = q->next;
//尋找p插入的位置
DCListNode* t = plist->head->next;
while (t != plist->head && t->data < p->data)
t = t->next;
p->next = t;
p->prev = t->prev;
p->next->prev = p;
p->prev->next = p;
p = q;
}
}
//14
void DCListReverse(DCList* plist)
{
assert(plist != NULL);
DCListNode* p = plist->head->next;
DCListNode* q = p->next;
//斷開(kāi)鏈表
p->next = plist->head;
plist->head->prev = p;
while (q != plist->head)
{
p = q;
q = q->next;
p->next = plist->head->next;
p->prev = plist->head;
p->next->prev = p;
p->prev->next = p; //plist->head->next = p;
}
}
//15
void DCListClear(DCList* plist)
{
assert(plist != NULL);
DCListNode* p = plist->head->next;
while (p != plist->head)
{
p->next->prev = p->prev;
p->prev->next = p->next;
free(p);
p = plist->head->next;
}
}
void DCListDestroy(DCList* plist)
{
DCListClear(plist);
free(plist->head);
plist->head = NULL;
}
以上就是C語(yǔ)言學(xué)習(xí)之鏈表的實(shí)現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言鏈表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)牛頓迭代法解方程詳解
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)牛頓迭代法解方程詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03
C語(yǔ)言使用ffmpeg實(shí)現(xiàn)單線程異步的視頻播放器
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言如何使用ffmpeg實(shí)現(xiàn)單線程異步的視頻播放器功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-12-12
C++無(wú)符號(hào)整數(shù)溢出問(wèn)題解析
這篇文章主要介紹了C++無(wú)符號(hào)整數(shù)溢出探究,本文主要探討C/C++中無(wú)符號(hào)整數(shù)超過(guò)范圍后的計(jì)算問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
C++設(shè)計(jì)模式之享元模式(Flyweight)
這篇文章主要為大家詳細(xì)介紹了C++設(shè)計(jì)模式之享元模式Flyweight,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
C語(yǔ)言實(shí)現(xiàn)火車票管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)火車票管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
詳解C/C++ Linux出錯(cuò)處理函數(shù)(strerror與perror)的使用
我們知道,系統(tǒng)函數(shù)調(diào)用不能保證每次都成功,必須進(jìn)行出錯(cuò)處理,這樣一方面可以保證程序邏輯正常,另一方面可以迅速得到故障信息。本文主要為大家介紹兩個(gè)出錯(cuò)處理函數(shù)(strerror、perror)的使用,需要的可以參考一下2023-01-01
基于C語(yǔ)言實(shí)現(xiàn)的TCP服務(wù)器的流程分析
本文詳細(xì)介紹了如何使用C語(yǔ)言編寫一個(gè)簡(jiǎn)單的TCP服務(wù)器,包括創(chuàng)建套接字、綁定IP和端口、監(jiān)聽(tīng)連接請(qǐng)求、接受客戶端連接、數(shù)據(jù)接收與發(fā)送以及關(guān)閉套接字等步驟,最后通過(guò)一個(gè)簡(jiǎn)單的示例展示了TCP服務(wù)器的基本實(shí)現(xiàn)過(guò)程2024-10-10
c 調(diào)用python出現(xiàn)異常的原因分析
本篇文章是對(duì)使用c語(yǔ)言調(diào)用python出現(xiàn)異常的原因進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05

