簡單數據結構之線性表之鏈表

—— 引子

今天給大家帶來的是一個新的數據結構,鏈表!

上一次的順序表,大家一定覺得非常的容易,沒錯,作爲一個入門級別的數據結構,要是讓大家感覺到喫力,那還了得!

一起來回顧一下我們上次的順序表,作爲一個比較簡單的數據結構,順序表利用自身的管理結構,完成了對於整個結構的控制,利用結構體將三個參數封裝起來,size用來表示當前順序表中一共有多少元素,而capacity表示最大可以儲存多少元素,最後,還有這一個指針,用來指向一片堆區中的連續空間,用來真正的保存我們的數據。

相信現在大家聽到我的介紹,恐怕陌生感要減少很多了吧,所以,不要放棄,要相信,熟能生巧,總有一天,這區區數據結構,你一定是能將他拿下的!


什麼是鏈表?

對於鏈表這個數據結構,相信很多小夥伴還是比較頭疼的,放心,等會,就讓你完全弄懂它!

首先,鏈表的關鍵,在窩瓜看來,就是這個“鏈”字!

我想佛珠大家一定都見過,窩瓜覺得,佛珠的整體形態就和我們的鏈表有着異曲同工之妙!

在這裏插入圖片描述
首先,我們可以將每一顆珠子看成是我們的一個節點,而這珠子與珠子之間的線,我們就將其想象爲一個看的見、摸得到的指針,這樣,每一顆佛珠,就可以通過這條線,找到下一個佛珠,這不正是我們的鏈表嗎!

現在我們來模擬一下鏈表的實現!

首先,桌面上什麼都沒有,當我們插入第一個元素的時候,桌面上出現了一個佛珠(也就是一個節點),這時,我們又需要第二顆佛珠,首先,將線從第一顆佛珠上穿過,然後拿出第二顆佛珠,用線將其串在第一顆佛珠的後面,以此類推,這種用線將佛珠一顆顆串在一起的過程,在鏈表中,就是我們的插入操作!

此時我們發現其中一顆佛珠的品相不好,不想要它了,我們要怎麼將它去掉呢?

很多小夥伴一定會說,這也太簡單了,直接把線間斷,然後把珠子取出來,然後將斷了的線連接上,不就好了!

沒錯,就是這麼簡單!其實在我們鏈表的世界中,也是這樣的,上面的情況,就完美的模擬了我們刪除節點的情況,在刪除節點的時候,我們只需要將要刪除節點的前一個節點找到,然後切斷這個節點與要刪除節點之間的線(指針),然後將這個節點直接指向要刪除節點的後一個節點,這不就完成了所謂的刪除操作。

所以說,鏈表其實也不難!

接下來,就讓我們看看怎樣用代碼模擬上面的過程,從而實現我們的鏈表!


鏈表的實現

上次介紹了順序表的特點,那麼,鏈表有着什麼特點呢?讓我們一起來看看!

鏈表的特點:
  1. 空間不固定,隨用隨建,避免浪費
  2. 邏輯上每個節點相鄰,物理上不一定
  3. 插入和刪除比較簡單,不用遍歷整個結構
  4. 查詢因爲沒有索引的緣故,性能不如順序表,時間複雜度爲O(n)
定義頭節點和節點
typedef struct N{
    int data;
    struct N * next;
}Node;
//節點

typedef struct{
    Node * head;
    Node * tail;
    int size;
}List;
//頭節點
初始化鏈表
List * init_list(List * p){
    p->head = (void *)0;
    p->tail = (void *)0;
    p->size = 0;
    return p;
}//初始化鏈表
清空鏈表
List * clear_list(List * p){
    while(p->head){
        Node * del = p->head;
        p->head = del->next;
        free(del);
    }
    p->tail = (void *)0;
    p->size = 0;
    return p;
}//清空鏈表
銷燬鏈表
void * destroy_list(List * p){
    clear_list(p);
}//銷燬鏈表
尾插法
List * push_back_list(List * p, int data){
    Node * new_node = make_node(data);
    if(!new_node){
        return (void *)0;
    }
    p->tail->next = new_node;
    p->tail = new_node;
    p->size++;
    return p;
}//尾部插入元素
頭插法
List * push_front_list(List * p, int data){
    Node * new_node = make_node(data);
    if(!new_node){
        return (void *)0;
    }
    new_node->next = p->head;
    p->head = new_node;
    p->size++;
    if(p->size == 1){
        p->tail = new_node;
    }
    return p;
}//頭部插入元素
頭刪法
List * pop_front_list(List * p){
    if(p->size == 0){
        return (void *)0;
    }
    Node * del = p->head;
    p->head = p->head->next;
    free(del);
    p->size--;
    if(p->size == 0){
        p->tail = (void *)0;
    }
    return p;
}//頭部刪除元素
尾刪法
List * pop_back_list(List * p){
    if(p->size == 0){
        return (void *)0;
    }
    Node * del = p->tail;
    Node * tem = p->head;
    if(p->size == 1){
        p->head = p->tail = (void *)0;
    }else{
        while(tem->next != p->tail){
            tem = tem->next;
        }
        tem->next = (void *)0;
        p->tail = tem;
    }
    free(del);
    p->size--;
    return p;
}//尾部刪除元素
打印鏈表
void print(List * p){
    Node * tem = p->head;
    if(tem){
        printf("現在有%d個元素,分別是:%d",p->size, tem->data);
        tem = tem->next;
        while(tem){
            printf("、%d",tem->data);
            tem = tem->next;
        }
        printf("\n");
    }else{
        printf("鏈表爲空!\n");
    }
}//打印鏈表
查找指定元素位置
Node * find_list(List * p, int data){
    if(p->size == 0){
        return (void *)0;
    }
    Node * tem = p->head;
    while(tem && tem->data == data){
        tem = tem->next;
    }
    return tem;
}//查找指定元素
刪除指定位置元素
List * erase_list(List * p, Node * pos){
    if(p->size == 0 || pos == p->tail){
        return (void *)0;
    }
    if(pos == (void *)0){
        return pop_back_list(p);
    }
    Node * del = pos->next;
    pos->next = del->next;
    p->size--;
    if(del == p->tail){
        p->tail = pos;
    }
    free(del);
    return p;
}//刪除指定
在指定位置插入元素
List * insert_list(List * p, Node * pos, int data){
    if(p->size == 0 || pos == (void *)0){
        return push_front_list(p , data);
    }
    if(pos == p->tail){
        return push_back_list(p , data);
    }
    Node * new_node = make_node(data);
    if(!new_node){
        return (void *)0;
    }
    new_node->next = pos->next;
    pos->next = new_node;
    p->size++;
    return p;
}//在指定位置插入元素
測試代碼
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main()
{
    int i;
    List list;
    init_list(&list);
    push_front_list(&list, 1);
    push_front_list(&list, 2);
    print(&list);
    push_back_list(&list, 3);
    push_back_list(&list, 4);
    print(&list);
    pop_front_list(&list);
    pop_back_list(&list);
    print(&list);
    insert_list(&list,find_list(&list, 3) , 5);
    print(&list);
    erase_list(&list, find_list(&list, 5));
    print(&list);
    clear_list(&list);
    print(&list);
    destroy_list(&list);
    return 0;
}
結果展示

在這裏插入圖片描述

這就是這次給大家帶來的關於鏈表的實現,下次,將會給大家帶來順序棧和鏈式棧的實現!謝謝大家~~~~~~~~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章