欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言數(shù)據(jù)結(jié)構(gòu)之雙鏈表&循環(huán)鏈表&靜態(tài)鏈表詳解

 更新時(shí)間:2022年09月27日 10:09:36   作者:程序喵正在路上  
這篇文章主要為大家詳細(xì)介紹了C語言數(shù)據(jù)結(jié)構(gòu)中雙鏈表&循環(huán)鏈表&靜態(tài)鏈表的原理與使用,文中的示例代碼講解詳細(xì),感興趣的可以了解一下

單鏈表 VS 雙鏈表

我們都知道,單鏈表只有一個(gè)指向下一個(gè)結(jié)點(diǎn)的指針,當(dāng)我們想要找到前一個(gè)結(jié)點(diǎn)時(shí)就比較麻煩,而雙鏈表擁有兩個(gè)指針

總的來說:

  • 單鏈表 —— 無法逆向檢索,有時(shí)候不太方便
  • 雙鏈表 —— 可進(jìn)可退,存儲(chǔ)密度更低一丟丟

定義雙鏈表結(jié)點(diǎn)類型

typedef struct DNode{
    ElemType data;                //數(shù)據(jù)域
    struct DNode *prior, *next;    //前驅(qū)和后繼指針
}DNode, *DLinklist;

雙鏈表

雙鏈表的初始化(帶頭結(jié)點(diǎn))

定義一個(gè) InitLinklist 函數(shù),參數(shù)為雙鏈表的引用,加引用是因?yàn)橐淖冞@個(gè)雙鏈表

注意:頭結(jié)點(diǎn)的前驅(qū)指針永遠(yuǎn)指向 NULL

#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

typedef struct DNode{
	ElemType data;				//數(shù)據(jù)域
	struct DNode *prior, *next;	//前驅(qū)和后繼指針
}DNode, *DLinklist;

//初始化雙鏈表
bool InitLinklist(DLinklist &L) {
	L = (DNode *)malloc(sizeof(DNode));		//分配一個(gè)頭結(jié)點(diǎn)
	if (L == NULL) return false;			//內(nèi)存不足,分配失敗
	L->prior = NULL;						//頭結(jié)點(diǎn)的 prior 永遠(yuǎn)指向 NULL
	L->next = NULL;							//頭結(jié)點(diǎn)之后暫時(shí)還沒有結(jié)點(diǎn)
	return true;
}

//判斷雙鏈表是否為空(帶頭結(jié)點(diǎn))
bool Empty(DLinklist L) {
	if (L->next == NULL)
		return true;
	else
		return false;
}

void testDLinklist() {
	//初始化雙鏈表
	DLinklist L;
	InitLinklist(L);
}

雙鏈表的插入

后插法

//在p結(jié)點(diǎn)之后插入s結(jié)點(diǎn)
bool InsertNextDNode(DNode *p, DNode *s) {
	if (p == NULL || s == NULL) return false;	//非法參數(shù)

	s->next = p->next;
	if (p->next != NULL)		//如果p結(jié)點(diǎn)有后繼結(jié)點(diǎn)
		p->next->prior = s;
	s->prior = p;
	p->next = s; 
	return true;
}

學(xué)會(huì)了后插操作,我們也就學(xué)會(huì)了按位序插入和前插法,大概思路為找到目標(biāo)結(jié)點(diǎn)的前驅(qū)結(jié)點(diǎn),然后對(duì)其進(jìn)行后插操作

雙鏈表的刪除

//刪除p結(jié)點(diǎn)的后繼結(jié)點(diǎn)
bool DeleteNextDNode(DNode *p) {
	if (p == NULL) return false;

	DNode *q = p->next;				//找到p結(jié)點(diǎn)的后繼結(jié)點(diǎn)q
	if (q == NULL) return false;	//p沒有后繼
	
	p->next = q->next;
	if (q->next != NULL)			//q結(jié)點(diǎn)不是最后一個(gè)結(jié)點(diǎn)
		q->next->prior = p;
	free(p);						//釋放結(jié)點(diǎn)空間
	return true;
}

//銷毀雙鏈表
void DestoryList(DLinklist &L) {
	//循環(huán)釋放各個(gè)數(shù)據(jù)結(jié)點(diǎn)
	while (L->next != NULL) {
		DeleteNextDNode(L);
	}
	free(L);	//釋放頭結(jié)點(diǎn)
	L = NULL;	//頭指針指向NULL
}

雙鏈表的遍歷

由于雙鏈表不可隨機(jī)存取,所以按位查找、按值查找等操作都只能用遍歷的方式實(shí)現(xiàn),時(shí)間復(fù)雜度為 O(n)

//后向遍歷
while (p != NULL) {
	//對(duì)結(jié)點(diǎn)p做相應(yīng)處理,比如打印
	p = p->next;
}

//前向遍歷
while (p != NULL) {
	//對(duì)結(jié)點(diǎn)p做相應(yīng)處理
	p = p->prior;
}

//前向遍歷(跳過頭結(jié)點(diǎn))
while (p->prior != NULL) {
	//對(duì)結(jié)點(diǎn)p做相應(yīng)處理
	p = p->prior;
}

循環(huán)單鏈表

我們都知道,單鏈表的表尾結(jié)點(diǎn)的 next 指針是指向 NULL,顧名思義,循環(huán)單鏈表的表尾結(jié)點(diǎn)的 next 指針就是指向頭結(jié)點(diǎn)的

循環(huán)單鏈表的優(yōu)點(diǎn):從一個(gè)結(jié)點(diǎn)出發(fā)可以找到其他任何一個(gè)結(jié)點(diǎn)

typedef int ElemType;

typedef struct LNode{
	ElemType data;			//每個(gè)節(jié)點(diǎn)存放一個(gè)數(shù)據(jù)元素
	struct LNode *next;		//指針指向下一個(gè)節(jié)點(diǎn)
}LNode, *LinkList;

//初始化一個(gè)循環(huán)單鏈表
bool InitList(LinkList &L) {
	L = (LNode *)malloc(sizeof(LNode));		//分配一個(gè)頭結(jié)點(diǎn)
	if (L == NULL) return false;			//內(nèi)存不足,分配失敗
	L->next = L;			//頭結(jié)點(diǎn)next指針指向頭結(jié)點(diǎn)
	return true;
}

//判斷循環(huán)單鏈表是否為空
bool Empty(LinkList L) {
	if (L->next == L) 
		return true;
	else 
		return false;
}

//判斷結(jié)點(diǎn)p是否為循環(huán)單鏈表的表尾結(jié)點(diǎn)
bool isTail(LinkList L, LNode *p) {
	if (p->next == L)
		return true;
	else 
		return false;
}

循環(huán)雙鏈表

雙鏈表:

  • 表頭結(jié)點(diǎn)的 prior 指向 NULL
  • 表尾結(jié)點(diǎn)的 next 指向 NULL

循環(huán)雙鏈表

  • 表頭結(jié)點(diǎn)的 prior 指向表尾結(jié)點(diǎn)
  • 表尾結(jié)點(diǎn)的 next 指向頭結(jié)點(diǎn)

循環(huán)雙鏈表的初始化

#include <stdio.h>
#include <stdlib.h>

typedef int ElemType;

typedef struct DNode{
	ElemType data;				//數(shù)據(jù)域
	struct DNode *prior, *next;	//前驅(qū)和后繼指針
}DNode, *DLinklist;

//初始化空的循環(huán)雙鏈表
bool InitDLinklist(DLinklist &L) {
	L = (DNode *)malloc(sizeof(DNode));		//分配一個(gè)頭結(jié)點(diǎn)
	if (L == NULL) return false;			//內(nèi)存不足,分配失敗
	L->prior = L;							//頭結(jié)點(diǎn)的 prior 指向頭結(jié)點(diǎn)
	L->next = L;							//頭結(jié)點(diǎn)的 next 指向頭結(jié)點(diǎn)
	return true;
}

//判斷循環(huán)雙鏈表是否為空
bool Empty(DLinklist L) {
	if (L->next == L)
		return true;
	else
		return false;
}

//判斷結(jié)點(diǎn)p是否為循環(huán)雙鏈表的表尾結(jié)點(diǎn)
bool isTail(DLinklist L, DNode *p) {
	if (p->next = L)
		return true;
	else
		return false;
}

void testDLinklist() {
	//初始化雙鏈表
	DLinklist L;
	InitDLinklist(L);
}

循環(huán)雙鏈表的插入

//在p結(jié)點(diǎn)之后插入s節(jié)點(diǎn)
bool InsertNextDNode(DNode *p, DNode *s) {
    s->next = p->next;
    p->next->prior = s;
    s->prior = p;
    p->next = s;
    return true;
}

循環(huán)雙鏈表的刪除

//刪除p的后繼結(jié)點(diǎn)q
p->next = q->next;
q->next->prior = p;
free(q);

靜態(tài)鏈表

什么是靜態(tài)鏈表

單鏈表:各個(gè)結(jié)點(diǎn)在內(nèi)存中星羅棋布、散落天涯

靜態(tài)鏈表:分配一整片連續(xù)的內(nèi)存空間,各個(gè)結(jié)點(diǎn)集中安置,0 號(hào)結(jié)點(diǎn)充當(dāng) “頭結(jié)點(diǎn)”,下一個(gè)結(jié)點(diǎn)的數(shù)組下標(biāo)(也稱為游標(biāo))充當(dāng) “指針”,游標(biāo)為 -1 時(shí)表示已經(jīng)到達(dá)表尾

靜態(tài)鏈表是用數(shù)組的方式來實(shí)現(xiàn)的鏈表,其優(yōu)點(diǎn)為 —— 增、刪操作不需要大量移動(dòng)元素;缺點(diǎn)為 —— 不能隨機(jī)存取,只能從頭結(jié)點(diǎn)開始依次往后查找;容量固定不可變

定義靜態(tài)鏈表

#define MaxSize 10            //靜態(tài)鏈表的最大長(zhǎng)度
struct Node{
    ElemType data;            //存儲(chǔ)數(shù)據(jù)元素
    int next;                //下一個(gè)元素的數(shù)組下標(biāo)
};

或者

#define MaxSize 10            //靜態(tài)鏈表的最大長(zhǎng)度
typedef struct {
    ElemType data;            //存儲(chǔ)數(shù)據(jù)元素
    int next;                //下一個(gè)元素的數(shù)組下標(biāo)
} SLinkList[MaxSize];

SLinkList a 相當(dāng)于 struct Node a[MaxSize]

基本操作的實(shí)現(xiàn)

初始化

把 a[0] 的 next 設(shè)置為 -1

把空的結(jié)點(diǎn)的 next 設(shè)置為 -2

查找

從頭結(jié)點(diǎn)出發(fā)依次往后遍歷結(jié)點(diǎn)

插入位序?yàn)?i 的結(jié)點(diǎn)

  • 找到一個(gè)空的結(jié)點(diǎn),存入數(shù)據(jù)元素
  • 從頭結(jié)點(diǎn)出發(fā)找到位序?yàn)?i-1 的結(jié)點(diǎn)
  • 修改新結(jié)點(diǎn)的 next
  • 修改 i-1 號(hào)結(jié)點(diǎn)的 next

刪除某個(gè)結(jié)點(diǎn)

  • 從頭結(jié)點(diǎn)出發(fā)找到前驅(qū)結(jié)點(diǎn)
  • 修改前驅(qū)結(jié)點(diǎn)的游標(biāo)
  • 被刪除結(jié)點(diǎn)的 next 設(shè)置為 -2

順序表和鏈表的比較

從邏輯結(jié)構(gòu)來說,順序表和鏈表都屬于線性表,都是線性結(jié)構(gòu)

從存儲(chǔ)結(jié)構(gòu)來說,順序表采用順序存儲(chǔ),而鏈表采用鏈?zhǔn)酱鎯?chǔ)

順序表

優(yōu)點(diǎn):支持隨機(jī)存取,存取密度高

缺點(diǎn):大片連續(xù)空間分配不方便,改變?nèi)萘坎环奖?/p>

鏈表:

優(yōu)點(diǎn):離散的小空間分配方便,改變?nèi)萘糠奖?/p>

缺點(diǎn):不可隨機(jī)存取,存儲(chǔ)密度低

從基本操作來看

創(chuàng)

  • 順序表需要預(yù)分配大片連續(xù)空間,若分配空間過小,則之后不方便擴(kuò)展容量;若分配空間過大,則浪費(fèi)內(nèi)存資源。如果采取靜態(tài)分配的方式,則容量不可改變;如果采取動(dòng)態(tài)分配的方式,則容量可改變,但需要移動(dòng)大量元素,時(shí)間代價(jià)高
  • 鏈表只需分配一個(gè)頭結(jié)點(diǎn)(也可以不要頭結(jié)點(diǎn),只聲明一個(gè)頭指針),之后方便拓展

  • 對(duì)鏈表來說,你只需掃描整個(gè)鏈表,依次刪除(free)各個(gè)結(jié)點(diǎn)即可
  • 對(duì)順序表來說,首先你需要修改 length = 0,如果是采用靜態(tài)分配的方式,當(dāng)靜態(tài)數(shù)組的生命周期結(jié)束時(shí),系統(tǒng)會(huì)自動(dòng)回收空間;如果是采用動(dòng)態(tài)分配的方式,用 malloc 申請(qǐng)的空間是屬于內(nèi)存中的堆區(qū),在堆區(qū)的內(nèi)存空間不會(huì)由系統(tǒng)自動(dòng)回收,需要我們手動(dòng) free

增刪

  • 對(duì)順序表來說,插入或刪除都要講后續(xù)元素全部后移或前移,時(shí)間復(fù)雜度為 O(n),時(shí)間開銷主要來自移動(dòng)元素
  • 對(duì)鏈表來說,插入或刪除元素只需要修改指針即可,時(shí)間復(fù)雜度為 O(n),時(shí)間開銷主要來自查找目標(biāo)元素
  • 雖然時(shí)間復(fù)雜度一樣,但是結(jié)合實(shí)際因素,鏈表增刪的效率要比順序表高得多

  • 對(duì)順序表來說,按位查找的時(shí)間復(fù)雜度為 O(1);按值查找的時(shí)間復(fù)雜度為 O(n),如果表內(nèi)元素有序,可采用折半查找等方法在 O(log2n) 時(shí)間內(nèi)找到
  • 對(duì)鏈表來說,按位查找的時(shí)間復(fù)雜度為 O(n);按值查找的時(shí)間復(fù)雜度也為 O(n)

綜上所述

  • 表長(zhǎng)難以預(yù)估、經(jīng)常要增加或刪除元素 —— 鏈表
  • 表長(zhǎng)可預(yù)估、查詢操作較多 —— 順序表

以上就是C語言數(shù)據(jù)結(jié)構(gòu)之雙鏈表&循環(huán)鏈表&靜態(tài)鏈表詳解的詳細(xì)內(nèi)容,更多關(guān)于C語言鏈表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++中#pragma once與#ifndef對(duì)比分析

    C++中#pragma once與#ifndef對(duì)比分析

    當(dāng)我們編寫C++代碼時(shí),經(jīng)常需要使用頭文件來引入一些常用的函數(shù)、類或者變量,如果一個(gè)頭文件被重復(fù)包含,就會(huì)導(dǎo)致編譯錯(cuò)誤或者運(yùn)行時(shí)錯(cuò),為了避免發(fā)生,我們需要使用預(yù)處理指令來防止頭文件被重復(fù)包含,常用的預(yù)處理指令有#pragma once和#ifndef,需要的朋友可以參考下
    2023-05-05
  • C++實(shí)現(xiàn)對(duì)RGB圖片進(jìn)行編碼的示例代碼

    C++實(shí)現(xiàn)對(duì)RGB圖片進(jìn)行編碼的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用得到的RGB信息重新對(duì)RGB圖片進(jìn)行編碼,以及對(duì)其他圖片如BMP所得到的RGB信息進(jìn)行編碼從而得到*.jpg文件,感興趣的可以了解一下
    2023-05-05
  • C語言實(shí)現(xiàn)BMP圖像細(xì)化處理

    C語言實(shí)現(xiàn)BMP圖像細(xì)化處理

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)BMP圖像細(xì)化處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Qt實(shí)現(xiàn)網(wǎng)絡(luò)聊天室的示例代碼

    Qt實(shí)現(xiàn)網(wǎng)絡(luò)聊天室的示例代碼

    本文主要介紹了Qt實(shí)現(xiàn)網(wǎng)絡(luò)聊天室,實(shí)現(xiàn)一個(gè)在線聊天室, 使用tcp對(duì)客戶端和服務(wù)器端進(jìn)行通訊。具有一定的參考價(jià)值,具有一定的參考價(jià)值,
    2021-06-06
  • 基于C語言中段錯(cuò)誤的問題詳解

    基于C語言中段錯(cuò)誤的問題詳解

    本篇文章是對(duì)C語言中段錯(cuò)誤的問題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++的字符串分割函數(shù)的使用詳解

    C++的字符串分割函數(shù)的使用詳解

    本篇文章主要介紹了C++的字符串分割函數(shù),主要用strtok、STL、Boost進(jìn)行字符串分割,有需要的可以了解一下。
    2016-11-11
  • C語言線性表之雙鏈表詳解

    C語言線性表之雙鏈表詳解

    這篇文章主要為大家詳細(xì)介紹了C語言線性表之雙鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • 深入理解鏈表的各類操作詳解

    深入理解鏈表的各類操作詳解

    本篇文章是對(duì)鏈表的各類操作進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++中CString string char* char 之間的字符轉(zhuǎn)換(多種方法)

    C++中CString string char* char 之間的字符轉(zhuǎn)換(多種方法)

    在寫程序的時(shí)候,我們經(jīng)常遇到各種各樣的類型轉(zhuǎn)換,比如 char* CString string 之間的互相轉(zhuǎn)換,這里簡(jiǎn)單為大家介紹一下,需要的朋友可以參考下
    2017-09-09
  • C語言實(shí)現(xiàn)的PNPoly算法代碼例子

    C語言實(shí)現(xiàn)的PNPoly算法代碼例子

    這篇文章主要介紹了C語言實(shí)現(xiàn)的PNPoly算法代碼例子,PNPoly算法j是判斷一個(gè)坐標(biāo)點(diǎn)是否在不規(guī)則多邊形內(nèi)部的算法,需要的朋友可以參考下
    2014-07-07

最新評(píng)論