一文弄懂C語(yǔ)言如何實(shí)現(xiàn)單鏈表
一、單鏈表與順序表的區(qū)別:
一、順序表:
1、內(nèi)存中地址連續(xù)
2、長(zhǎng)度可以實(shí)時(shí)變化
3、不支持隨機(jī)查找
4、適用于訪問(wèn)大量元素的,而少量需要增添/刪除的元素的程序
5、中間插入或者刪除比較方便,內(nèi)存命中率較高
二、鏈表
1、內(nèi)存中地址不連續(xù)(邏輯上連續(xù),物理上不連續(xù))
2、長(zhǎng)度可以實(shí)時(shí)變化(避免浪費(fèi)空間)
3、不支持隨機(jī)查找,查找的時(shí)間復(fù)雜度為o(1),
4、適用于訪問(wèn)大量元素的,對(duì)訪問(wèn)元素?zé)o要求的程序
5、中間插入或者刪除比較方便,效率高
二、關(guān)于鏈表中的一些函數(shù)接口的作用及實(shí)現(xiàn)
1、創(chuàng)建接口,開(kāi)辟空間
2、尾插尾刪
3、頭插頭刪
4、查找并修改
5、中插中刪
ps:我看了許多的單鏈表文章,在插刪的接口實(shí)現(xiàn)上大多數(shù)是往前進(jìn)行插刪,這里寫的則是往后進(jìn)行插刪
1、頭文件里的結(jié)構(gòu)體和函數(shù)聲明等等
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SListDataType;
//節(jié)點(diǎn)
typedef struct SListNode
{
SListDataType data;
struct SListNode* next;
}SListNode;
//struct SList
//{
// SListNode* head;
// SListNode* tail;
//};
//尾插尾刪
void SListPushBack(SListNode** pphead, SListDataType x);
void SListPopBack(SListNode** pphead);
//頭插頭刪
void SListPushFront(SListNode** pphead, SListDataType x);
void SListPopFront(SListNode** pphaed);
void SListPrint(SListNode* phead);
//查找并修改
SListNode* SListFind(SListNode* phead, SListDataType x);
//中插中刪
void SListInserAfter(SListNode**pphead,SListNode* pos, SListDataType x);
void SListEraseAfter(SListNode* pos);
//從頭到尾打印鏈表
void PrintTailToHead(SListNode* pList);
2、創(chuàng)建接口空間
//開(kāi)辟的下一個(gè)空間
SListNode* BuySListNode(SListDataType x)
{
SListNode* newNode = (SListNode*)malloc(sizeof(SListNode));
if (newNode == NULL)
{
printf("申請(qǐng)結(jié)點(diǎn)失敗\n");
exit(-1);
}
newNode->data = x;
newNode->next = NULL;
return newNode;
}
3.尾插尾刪
//尾插
void SListPushBack(SListNode** pphead, SListDataType x)
{
SListNode* newNode = BuySListNode(x);//我們指向頭指針的那個(gè)結(jié)點(diǎn)是**pphead,*pphead就是頭指針的地址
//如果頭指針的地址為空,我們就把新開(kāi)辟的這個(gè)空間指針(已經(jīng)傳入值)再賦給頭指針,也就是下面的這個(gè)if循環(huán)
if (*pphead == NULL)
{
*pphead = newNode;
}
else
{
//找尾巴,判斷尾巴是不是空地址,這個(gè)函數(shù)實(shí)現(xiàn)的是尾插,我們找到尾巴后,如果尾巴是空地址,我們將插入的newNode賦給尾巴,此時(shí)
//實(shí)現(xiàn)了尾插,在下面的代碼中,我們首先把頭指針當(dāng)成尾巴,從頭指針開(kāi)始依次往后找,如果下一個(gè)不是空指針,我們就令
//tail=tail->next,此時(shí)指向下一個(gè)結(jié)點(diǎn),進(jìn)入循環(huán)繼續(xù)判斷,當(dāng)找到后,我們?cè)倭钗舶?newNode,在上面我們也判斷了頭指針為空的情況
SListNode* tail = *pphead;
while (tail->next!= NULL)
{
tail = tail -> next;
}
tail->next = newNode;
}
}
void SListPopBack(SListNode** pphead)
{
//1、空
//2、一個(gè)結(jié)點(diǎn)
//3、一個(gè)以上
if (*pphead == NULL)
{
return;
}
else if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SListNode* prev = NULL;
SListNode* tail = *pphead;
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
//tail = NULL;//這個(gè)無(wú)所謂,因?yàn)槲覀冡尫藕?,出了這個(gè)作用域,tail和prev都被銷毀,沒(méi)人能拿到,所以不會(huì)被再找到
prev->next = NULL;
}
}
4、頭插頭刪
//頭插頭刪
void SListPushFront(SListNode** pphead, SListDataType x)
{
SListNode* newnode = BuySListNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
void SListPopFront(SListNode** pphead)
{
//1、空
//2、一個(gè)結(jié)點(diǎn)+3、一個(gè)以上
if (*pphead == NULL)
{
return;
}
//(*phead)->next:*和>都是解引用,同一優(yōu)先級(jí),我們需要給*pphead帶括號(hào),(*pphead)->next才是下一個(gè)結(jié)點(diǎn)
else{
//我們頭刪也會(huì)遇到情況,我們刪除第一個(gè)的話,第一個(gè)里面還存有第二個(gè)結(jié)點(diǎn)的地址,我們必須在刪除前,保存第二個(gè)結(jié)點(diǎn)的地址
SListNode* next = (*pphead)->next;
free(*pphead);//通過(guò)調(diào)試我們發(fā)現(xiàn):free前后,*pphead的地址不變,但是*pphead里的值被置為隨機(jī)值,free不僅僅把這塊空間還給操作系統(tǒng)
//而且還把這塊空間存的值和地址都置為隨機(jī)值
*pphead = next;
}
}
5、單鏈表查找
//單鏈表查找
SListNode* SListFind(SListNode* phead, SListDataType x)
{
SListNode* cur = phead;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
6、中間插入(在pos后面進(jìn)行插入)
void SListInserAfter(SListNode** pphead,SListNode* pos, SListDataType x)
{
assert(pos && pphead);
if (*pphead == pos)
{
SListPushFront(pphead, x);
}
else
{
SListNode* newnode = BuySListNode(x);
SListNode* tmp = *pphead;
while (tmp->next != pos)
{
tmp = tmp->next;
}
tmp->next = pos;
pos->next = newnode;
}
}
7、中間刪除(在pos后面進(jìn)行刪除)
void SListEraseAfter(SListNode* pos)
{
//刪除pos后面的
assert(pos);
if (pos->next)
{
//pos->next=pos->next->next//不推薦
SListNode* next = pos->next;
SListNode* nextnext = next->next;
pos->next = nextnext;
free(next);
}
}
8、單獨(dú)打印鏈表和從頭到尾打印鏈表
void SListPrint(SListNode* phead)
{
SListNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
void PrintTailToHead(SListNode* pList)
{
if (pList == NULL)
{
return;
}
PrintTailToHead(pList->next);
printf("%d->",pList->data);
}
9、test.c
#include"SList.h"
TestSList1()
{
SListNode* pList = NULL;//這個(gè)結(jié)構(gòu)體指針指向開(kāi)辟的空間,頭指針指向鏈表的開(kāi)頭
SListPushBack(&pList, 1);
SListPushBack(&pList, 2);
SListPushBack(&pList, 3);
SListPushBack(&pList, 4);
SListPrint(pList);
SListPopBack(&pList);
SListPopBack(&pList);
SListPopBack(&pList);
SListPopBack(&pList);
SListPopBack(&pList);
SListPrint(pList);
SListPushFront(&pList, 1);
SListPushFront(&pList, 2);
SListPushFront(&pList, 6);
SListPushFront(&pList, 4);
SListPushFront(&pList, 5);
SListPrint(pList);
SListPopFront(&pList);
SListPopFront(&pList);
SListPopFront(&pList);
SListPopFront(&pList);
SListPopFront(&pList);
SListPopFront(&pList);
SListPrint(pList);
}
TestSList2()
{
SListNode* pos1;
SListNode* pList = NULL;//這個(gè)結(jié)構(gòu)體指針指向開(kāi)辟的空間,頭指針指向鏈表的開(kāi)頭
SListPushBack(&pList, 1);
SListPushBack(&pList, 2);
SListPushBack(&pList, 3);
SListPushBack(&pList, 4);
SListPrint(pList);
SListNode* pos = SListFind(pList, 3);
if (pos)
{
pos->data = 30;//這里將cur-data改為pos->data,然后再將pos-data原來(lái)的值改為30
}
SListPrint(pList);
pos1 = SListFind(pList, 30);//我們先去找到這個(gè)pos1的位置,然后再去插入
SListInserAfter(&pList,pos1,50);//函數(shù)傳參要對(duì)應(yīng)起來(lái),我們用指針傳用指針接收,不能在pos1位置直接寫個(gè)數(shù)字
SListPrint(pList);
SListEraseAfter(pos1);//pList指向第一個(gè)結(jié)點(diǎn),pList->next指向第二個(gè)結(jié)點(diǎn),那么我們刪除的是目標(biāo)節(jié)點(diǎn)后面
SListPrint(pList);
//PrintTailToHead(&pList);
}
int main()
{
TestSList1();
TestSList2();
return 0;
}
總結(jié)
到此這篇關(guān)于C語(yǔ)言如何實(shí)現(xiàn)單鏈表的文章就介紹到這了,更多相關(guān)C語(yǔ)言實(shí)現(xiàn)單鏈表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++使用數(shù)組來(lái)實(shí)現(xiàn)哈夫曼樹(shù)
給定N個(gè)權(quán)值作為N個(gè)葉子結(jié)點(diǎn),構(gòu)造一棵二叉樹(shù),若該樹(shù)的帶權(quán)路徑長(zhǎng)度達(dá)到最小,稱這樣的二叉樹(shù)為最優(yōu)二叉樹(shù),也稱為哈夫曼樹(shù)(Huffman?Tree)。哈夫曼樹(shù)是帶權(quán)路徑長(zhǎng)度最短的樹(shù),權(quán)值較大的結(jié)點(diǎn)離根較近2022-05-05
C語(yǔ)言動(dòng)態(tài)鏈表實(shí)現(xiàn)學(xué)生學(xué)籍管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言動(dòng)態(tài)鏈表實(shí)現(xiàn)學(xué)生學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
詳解C語(yǔ)言結(jié)構(gòu)體,枚舉,聯(lián)合體的使用
這篇文章主要給大家介紹一下關(guān)于C語(yǔ)言中結(jié)構(gòu)體、枚舉、聯(lián)合體的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考一下2022-07-07
C語(yǔ)言超詳細(xì)講解隊(duì)列的實(shí)現(xiàn)及代碼
隊(duì)列(Queue)與棧一樣,是一種線性存儲(chǔ)結(jié)構(gòu),它具有如下特點(diǎn):隊(duì)列中的數(shù)據(jù)元素遵循“先進(jìn)先出”(First?In?First?Out)的原則,簡(jiǎn)稱FIFO結(jié)構(gòu)。在隊(duì)尾添加元素,在隊(duì)頭刪除元素2022-04-04
C++中字符串與整型及浮點(diǎn)型轉(zhuǎn)換全攻略
C++算法刷題等過(guò)程中經(jīng)常會(huì)遇到字符串與數(shù)字類型的轉(zhuǎn)換,在這其中雖然樸素的算法有不少,但是對(duì)于double等類型還是可以說(shuō)遇到一些麻煩,所以今天就來(lái)說(shuō)說(shuō)使用C++標(biāo)準(zhǔn)庫(kù)中的函數(shù)實(shí)現(xiàn)這些功能。感興趣的小伙伴一起參與閱讀吧2021-09-09

