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

C語言數(shù)據(jù)結(jié)構(gòu)不掛科指南之線性表詳解

 更新時(shí)間:2022年09月27日 14:10:46   作者:夢想橡皮擦  
線性表是由?n(n≥0)個(gè)數(shù)據(jù)元素組成的有窮序列,這篇文章主要來和大家來了C語言數(shù)據(jù)結(jié)構(gòu)中的線性表,感興趣的小伙伴可以跟隨小編一起了解一下

基本概念

線性表是由 n(n≥0)個(gè)數(shù)據(jù)元素組成的有窮序列

大白話:在內(nèi)存上一個(gè)個(gè)排著,找到一個(gè),剩下的挨著找就行

數(shù)據(jù)元素又稱作結(jié)點(diǎn)

吐槽:人類在創(chuàng)造術(shù)語的路上就是這么帶勁,上節(jié)課剛說數(shù)據(jù)元素又稱元素,這又來一個(gè)結(jié)點(diǎn),得,記住吧

結(jié)點(diǎn)個(gè)數(shù)叫做表長,那么我們用一張完整的圖來說明一下

線性表的基本運(yùn)算,需要了解一下

  • 初始化 Initiate(L)
  • 求表長 Length(L)
  • 讀表元素 Get(L,i)
  • 定位 Locate(L,i)
  • 插入 Insert(L,x,i)
  • 刪除 Delete(L,i)

線性表的順序存儲(chǔ)

用順序存儲(chǔ)實(shí)現(xiàn)的線性表稱為順序表。一般使用數(shù)組來表示順序表

接下就是刺激的時(shí)刻了,比較難的部分來了,因?yàn)橐?C 來實(shí)現(xiàn)線性表的基本運(yùn)算

首先假定線性表的數(shù)據(jù)元素的類型為DataType ,這個(gè)DataType 可以是自定義的,也可以是默認(rèn)的int,char等類型

const int Maxsize = 100 ;  // 預(yù)先定義一個(gè)足夠大的常數(shù)
typedef struct{
	DataType data[Maxsize]; // 存放數(shù)據(jù)的數(shù)組
	int length ; // 順序表的實(shí)際長度
} SeqList; // 順序表類型名為SeqList
SeqList L ;  // 定義一個(gè)L為順序表

實(shí)現(xiàn)插入操作,函數(shù)名字為InsertSeqList(SeqList L,DataType x,int i) 表示在順序表第 i(1≤i≤n+1)個(gè)元素之前,插入一個(gè)新元素。使得線性表長度加 1。

上面是邏輯上的 C 語言實(shí)現(xiàn),接下來咱們先引用一個(gè)圖,說明一下如何用 C 語言在內(nèi)存上開辟一塊空間,并且向里面存數(shù)據(jù)

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

const int Maxsize = 10;
typedef struct SeqList{
    int *data; //一個(gè)int指針,后面用來初始化數(shù)組用
    int length;
} seq;

// 順序表的初始化函數(shù)
seq init(){
    seq s;
    s.data = (int*)malloc(Maxsize*sizeof(int)); // 構(gòu)造一個(gè)空的順序表,動(dòng)態(tài)申請存儲(chǔ)空間
    if(!s.data) // 如果申請失敗,退出程序
    {
        printf("初始化失敗");
        exit(0);
    }
    s.length = 0; // 空表的長度初始化為0
    return s;
}

上述代碼,相當(dāng)于在內(nèi)存上做了圖示的操作

開辟空間之后,向每個(gè)小格子里面添加數(shù)字

void display(seq s){
    for(int i=0;i<s.length;i++){
        printf("%d",s.data[i]);
    }
    printf("\n");

}

int main()
{
    seq s = init();
    //添加一個(gè)元素進(jìn)入
    for(int i=1;i<=5;i++){
        s.data[i-1] = i;
        s.length++;
    }
    printf("初始化之后,表的數(shù)據(jù)為:\n");
    display(s);

    return 0;
}

可以看動(dòng)畫理解

添加元素完成之后,就是刪除元素

刪除的基本步驟

  • 結(jié)點(diǎn) ai+1,....an依次向左移動(dòng)一個(gè)元素位置
  • 表長度減 1

看一下代碼吧

seq delete_seq(seq s,int i){
    if(i<1||i>s.length){
        printf("位置錯(cuò)誤");
        exit(0);
    }

    // 第i個(gè)元素下標(biāo)修改為i-1
    for(int j=i;j<s.length;j++){
        s.data[j-1] = s.data[j];
    }

    s.length--;
    return s;
}

接下來實(shí)現(xiàn)定位的算法,說白了,就是判斷一個(gè)值(x)的位置(i)

C 語言的代碼如下

// 注意,這個(gè)地方需要返回的為int了,也就是位置
int locate(seq s,int x){
    int i =0;
    while((i<s.length)&&(s.data[i]!=x)){
        i++;
    }
    if(i<s.length) return i+1;
    else return -1;
}

線性表的順序存儲(chǔ)的時(shí)間復(fù)雜度

運(yùn)算插入刪除定位求表長讀取元素
時(shí)間復(fù)雜度O(n)O(n)O(n)O(1)O(1)

具體是怎么來的,需要你自己看看算法的實(shí)現(xiàn)嘍,通過上述表格知道 順序表的插入、刪除算法在時(shí)間性能方面不是很理想,接下來我們就采用線性表的鏈接存儲(chǔ)來看一下,是否存在優(yōu)化。

線性表的鏈接存儲(chǔ)

鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),上來需要記住有三種常見的 單鏈表、循環(huán)鏈表、雙向循環(huán)鏈表

首先明確,單鏈表中每個(gè)結(jié)點(diǎn)由兩部分組成

  • data 表示==數(shù)據(jù)域==
  • next 表示==指針域==或==鏈域==

一些簡單的結(jié)點(diǎn)概念

線性表在單鏈表上實(shí)現(xiàn)基本運(yùn)算

接下來重頭戲來了,我們要用代碼實(shí)現(xiàn)一個(gè)簡單的單鏈表

空的單鏈表由一個(gè)頭指針和一個(gè)頭結(jié)點(diǎn)組成

初始化

初始化之前,我們需要先用 C 語言定義一個(gè)新的結(jié)構(gòu)體

//鏈表中的每個(gè)結(jié)點(diǎn)的實(shí)現(xiàn)
//包含數(shù)據(jù)域與指針域
typedef struct node{
	int data;// 數(shù)據(jù)域,為了計(jì)算方便,類型設(shè)置為數(shù)字
	struct node *next; // 指針域,指向后繼元素
} Node,*LinkList;

結(jié)構(gòu)體定義好了之后,就可以開始初始化操作了 頭結(jié)點(diǎn)初始化其實(shí)就是在內(nèi)存上開辟一塊空間,然后將指針域指向 NULL

請看代碼,注意返回的是一個(gè)指針類型,說白了就是頭結(jié)點(diǎn)的地址

// 初始化
LinkList init(){
    Node *L; // 定義一個(gè)頭結(jié)點(diǎn)
    L =(LinkList)malloc(sizeof(Node)); //頭結(jié)點(diǎn)申請地址
    if(L == NULL){
        printf("初始化失敗!\n");
        exit(0);
    }
    L->next =NULL;
    return L;
}
復(fù)制代碼

初始化成功,開始插入元素

插入元素,有頭插入、尾插、任意插

先說一下頭插,當(dāng)頭結(jié)點(diǎn)初始化完畢之后,第一個(gè)元素插入進(jìn)來就比較簡單了,看動(dòng)圖

這是插入一個(gè)元素,在用頭插法插入第二個(gè)元素呢?

新生成的 pnew2 首先將自己的指針域指向頭結(jié)點(diǎn)的指針域pnew2->next = L.next,然后L.next = pnew2 即可

上述的邏輯寫成代碼如下

// 頭插入法
void insert_head(Node *L){
    int i,n,num;  // n表示元素的個(gè)數(shù)
    Node *pnew;
    printf("請輸入要插入的元素個(gè)數(shù):n = ");
    scanf("%d",&n);
    for(i=0;i<n;i++){
        printf("請輸入第%d個(gè)元素: ",i+1);
        scanf("%d",&num);
        pnew = (LinkList)malloc(sizeof(Node));
        pnew->data = num; // 將數(shù)字存儲(chǔ)到數(shù)據(jù)域
        pnew->next = L->next; // 指針域指向L(頭結(jié)點(diǎn))的指針域
        L->next = pnew; // 頭結(jié)點(diǎn)指針域指向新結(jié)點(diǎn)地址

    }
}

接下來看一下尾插法,其實(shí)理解起來也不難,說白了就是在鏈表后面追加元素即可 !

代碼如下,這個(gè)地方看一下里面有一個(gè)p=L請問直接使用 L 可以嗎?為什么不直接用,搞清楚了,你也就明白了

// 尾插法
void insert_tail(Node *L){
    int i,n,num;
    Node *p,*pnew;
    p = L;

    printf("要輸入元素的個(gè)數(shù):n = ");
    scanf("%d",&n);
    for(i=0;i<n;i++){

        printf("請輸入第%d個(gè)元素:",i+1);
        scanf("%d",&num);
        pnew = (LinkList)malloc(sizeof(Node));
        if(pnew == NULL){
            printf("初始化失敗");
            exit(0);
        }
        pnew->data = num;
        p->next = pnew;
        p = pnew;

    }
    p->next = NULL;

}

剩下的算法實(shí)現(xiàn)就比較簡單了,例如求表長,通過循環(huán)的方式,計(jì)算一下即可

//求表長
int get_length(LinkList L){
    LinkList p;
    int length = 0;
    p = L->next;   // p 指向第一個(gè)結(jié)點(diǎn)
    while(p){
        printf("單鏈表的數(shù)據(jù)為%d\n",p->data);
        length++;
        p = p->next;
    }
    return length;
}

讀表中的元素

// 讀表中的元素
LinkList get_element(LinkList L,int i){
    // 在單鏈表L中查找第i個(gè)結(jié)點(diǎn),若找到,則返回指向該結(jié)點(diǎn)的指針,否則返回NULL
    Node *p;
    p = L->next;
    int position = 1;
    while((position<i)&&(p!=NULL)){ // 當(dāng)未到第i結(jié)點(diǎn)且未到尾結(jié)點(diǎn)時(shí)繼續(xù)后移
        p = p->next;
        position++;
    }
    if(i==position) return p; //找到第i個(gè)結(jié)點(diǎn)
    else return NULL;   // 查找失敗
}

讀取表的元素,還可以按照值去找,返回位置,嘗試一下吧,寫起來都是比較容易的

int get_element_by_data(LinkList L,int x){
    Node *p;
    p = L->next;
    int i = 0;
    while(p!=NULL && p->data == x){
        p = p->next;
        i++;
    }
    if (p!=NULL) return i+1;
    else return 0;
}

寫個(gè)復(fù)雜點(diǎn)的,在任意位置插入一個(gè)元素,這個(gè)還是好玩一些的

/在任意位置插入元素,x為要插入的內(nèi)容,i為插入的位置
void insert(LinkList L,int x,int i){

    Node *p,*q; //p表示要插入的元素,q表示要被插入的元素
    if(i==1) q = L; //如果i==1,那么p=L進(jìn)行初始化操作
    else q = get_element(L,i-1); // 找到第i-1個(gè)元素

    if(q==NULL){
        printf("找不到位置");
        exit(0);
    }
    else{
         p =(LinkList)malloc(sizeof(Node));
         p->data = x;
         p->next = q->next; // 新生成的p指向q的下一個(gè)結(jié)點(diǎn)
         q->next = p;//q的指針域指向新生成的p

    }
}

簡單說明一下吧 大白話為 要在第 i 個(gè)位置插入一個(gè)元素 x,那么需要找到i-1位置的元素,這個(gè)元素叫做 q

讓新元素p(數(shù)據(jù)域?yàn)?x,指針域?yàn)榭眨┑闹羔樣蛑赶虻?code>i 元素,也就是q原先的指針域,==防止丟失掉==

然后在叫q的指針域指向p的地址即可,如果還不明白,看圖

對于刪除任意位置的節(jié)點(diǎn),這個(gè)就要留給你自己了

如果將 ai移除鏈表,需要找到直接前驅(qū),讓直接前驅(qū)的指針域指向 ai+1的地址就可以了

記得,通過free(p)釋放結(jié)點(diǎn)

刪除全部結(jié)點(diǎn)也需要自己完成一下,盡量把代碼寫完哦~~~

單鏈表的時(shí)間復(fù)雜度

  • insert(LinkList L,int x,int i) 時(shí)間復(fù)雜度為 O(n^2^)
  • 頭插法和尾插法時(shí)間復(fù)雜度為 O(n)

循環(huán)鏈表

環(huán)狀鏈表只需要將表中最后一個(gè)結(jié)點(diǎn)的指針指向頭結(jié)點(diǎn),鏈表就形成了一個(gè)環(huán) 如圖

循環(huán)鏈表如何想研究一下可以去實(shí)現(xiàn)約瑟夫環(huán),由于本教材中不是重點(diǎn),所以選修即可

雙向循環(huán)鏈表

雙向循環(huán)鏈表就是在單鏈表中的每個(gè)結(jié)點(diǎn)在增加一個(gè)指向直接前驅(qū)的指針域prior ,這樣每個(gè)結(jié)點(diǎn)就有兩個(gè)指針了

注意點(diǎn)

  • 雙向循環(huán)鏈表是一種對稱結(jié)構(gòu),即可以直接訪問前驅(qū)結(jié)點(diǎn)又可以直接訪問后繼結(jié)點(diǎn),所以找前驅(qū)和后繼結(jié)點(diǎn)的時(shí)間復(fù)雜度都是 O(1),也可以得到結(jié)論雙向循環(huán)鏈表適合應(yīng)用在需要經(jīng)常查找結(jié)點(diǎn)的前驅(qū)和后繼場合
  • p = p->prior->next = p->next->prior

教材中重點(diǎn)給出了刪除和插入的兩個(gè)邏輯,我們看一下

// p表示的是待刪除的結(jié)點(diǎn)
p->prior->next = p->next;
p->next->prior = p->prior;
free(p)

圖示如下

大白話 先讓 p 等于要?jiǎng)h除的結(jié)點(diǎn),然后把 p 刪除前,需要將 p 的前驅(qū)和后繼結(jié)點(diǎn)連接起來,剛才的代碼干的就是這個(gè)事情!

插入邏輯

在 p 所指的結(jié)點(diǎn)后面插入一個(gè)新結(jié)點(diǎn)*t,需要修改四個(gè)指針:

t->prior = p;
p->next = t;  // 這兩個(gè)步驟將t和p連接起來了

t->next = p->next;
p->next->prior = t; //這兩個(gè)步驟將t和p后繼結(jié)點(diǎn)連接起來了

期末考試

這章是期末考試或者自考的一個(gè)比較重要的考試章節(jié),一般會(huì)出現(xiàn)算法設(shè)計(jì)題,難度系數(shù)挺高的

建議,在能力范圍內(nèi)用 C 語言實(shí)現(xiàn)順序表的基本運(yùn)算,實(shí)現(xiàn)單鏈表的基本運(yùn)算

以上就是C語言數(shù)據(jù)結(jié)構(gòu)不掛科指南之線性表詳解的詳細(xì)內(nèi)容,更多關(guān)于C語言數(shù)據(jù)結(jié)構(gòu)線性表的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++ 迭代器失效問題解決

    C++ 迭代器失效問題解決

    在C++中,當(dāng)一個(gè)vector進(jìn)行了插入或刪除操作時(shí),其迭代器可能會(huì)失效,本文就來介紹一下C++ 迭代器失效問題解決,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • C語言實(shí)現(xiàn)通訊錄系統(tǒng)課程設(shè)計(jì)

    C語言實(shí)現(xiàn)通訊錄系統(tǒng)課程設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)通訊錄系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • 實(shí)例分析一個(gè)簡單的Win32程序

    實(shí)例分析一個(gè)簡單的Win32程序

    這篇文章主要介紹了實(shí)例分析一個(gè)簡單的Win32程序,對于Win32應(yīng)用程序的原理、執(zhí)行流程、實(shí)現(xiàn)方法主要環(huán)節(jié)都做了較為詳細(xì)的分析,有助于讀者深入理解Windows應(yīng)用程序設(shè)計(jì),需要的朋友可以參考下
    2014-09-09
  • C語言實(shí)現(xiàn)掃雷游戲的方法

    C語言實(shí)現(xiàn)掃雷游戲的方法

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)掃雷游戲的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C語言中break與continue的用法和區(qū)別詳解

    C語言中break與continue的用法和區(qū)別詳解

    當(dāng)我們使用while或for循環(huán)時(shí),如果想提前結(jié)束循環(huán)(在不滿足結(jié)束條件的情況下結(jié)束循環(huán)),可以使用break或continue關(guān)鍵字,這篇文章主要給大家介紹了關(guān)于C語言中break與continue的用法和區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • C++實(shí)現(xiàn)LeetCode(101.判斷對稱樹)

    C++實(shí)現(xiàn)LeetCode(101.判斷對稱樹)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(101.判斷對稱樹),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言簡明講解隊(duì)列的實(shí)現(xiàn)方法

    C語言簡明講解隊(duì)列的實(shí)現(xiàn)方法

    隊(duì)列(Queue)與棧一樣,是一種線性存儲(chǔ)結(jié)構(gòu),它具有如下特點(diǎn):隊(duì)列中的數(shù)據(jù)元素遵循“先進(jìn)先出”(First?In?First?Out)的原則,簡稱FIFO結(jié)構(gòu)。在隊(duì)尾添加元素,在隊(duì)頭刪除元素
    2022-04-04
  • 詳解C++?轉(zhuǎn)換的非正式分類

    詳解C++?轉(zhuǎn)換的非正式分類

    C++?正式分類方法是直接按語法分類,分為:隱式轉(zhuǎn)換和顯示轉(zhuǎn)換。這篇文章主要介紹了C++?轉(zhuǎn)換的非正式分類,需要的朋友可以參考下
    2022-01-01
  • C++超詳細(xì)講解模擬實(shí)現(xiàn)vector

    C++超詳細(xì)講解模擬實(shí)現(xiàn)vector

    這篇文章主要介紹了C++ 容器 Vector 的使用方法,Vector 是一個(gè)能夠存放任意類型的動(dòng)態(tài)數(shù)組,有點(diǎn)類似數(shù)組,是一個(gè)連續(xù)地址空間,下文更多詳細(xì)內(nèi)容的介紹,需要的小伙伴可以參考一下
    2022-07-07
  • C++實(shí)現(xiàn)AVL樹的基本操作指南

    C++實(shí)現(xiàn)AVL樹的基本操作指南

    AVL樹是高度平衡的而二叉樹,它的特點(diǎn)是AVL樹中任何節(jié)點(diǎn)的兩個(gè)子樹的高度最大差別為1,下面這篇文章主要給大家介紹了關(guān)于C++實(shí)現(xiàn)AVL樹的相關(guān)資料,需要的朋友可以參考下
    2022-01-01

最新評(píng)論