鍊錶
鍊錶是乙個常用且非常有用的資料結構,比如我之前的尋找多個色塊的聚類演算法中便是用了單向鍊錶來儲存影象資料。
先要知道什麼是鍊錶?鍊錶的作用(為什麼會使用鍊錶)?鍊錶的分類與特點,然後再選擇一種鍊錶來深入研究。
本文就按照上述步驟來講述鍊錶。
1、什麼是鍊錶?
位址不連續的節點序列,彼此通過指標相互連線,組成鍊錶。
2、鍊錶的作用(為什麼要使用鍊錶)
在c語言裡面,由於陣列需要提前申明大小,動態陣列也需要乙個明確的大小申請,這對於需要不斷插入與刪除物件的任務就會很有問題,因為如果使用陣列來完成,為了滿足要求,就不得不分配乙個超級大的空間,這樣子就會造成空間資源的浪費,而鍊錶就是專門為了解決這類需要頻繁插入與刪除的任務而生成的。
除此之外,很多演算法的都使用鍊錶來儲存資料,比如二叉樹。
3、鍊錶的分類與特點
(1)單向線性鍊錶
(2)雙向線性鍊錶
(3)單向迴圈鍊錶
(4)雙向迴圈鍊錶
(5)陣列鍊錶,鍊錶的資料是乙個指標,指向乙個連續位址空間,即陣列
(6)鍊錶陣列,陣列中每個元素是指標,指標指向乙個鍊錶。
(7)多維鍊錶,即乙個鍊錶的資料位放置乙個指標,該指標又指向乙個鍊錶。二維鍊錶,又稱十字鍊錶。
一般雙向線性鍊錶使用的最多。
4、雙向線性鍊錶
雙向線性鍊錶由節點組成,每乙個節點包含乙個資料和兩個指標,兩個指標分別指向該節點的前節點和後節點(如果沒有則為空)。
乙個鍊錶結構體成員包括4個指標,乙個指向頭節點的指標,乙個指向尾節點的指標,乙個正向迭代指標,乙個反向迭代指標。這裡的迭代指標是為了完成使用者需要的迭代操作而設立的,這樣子做的好處是對鍊錶實現的細節進行了比較好的封裝,使用者可以完全不用管怎麼實現的,呼叫我們提供的函式即可,由於一些原因,後面的**中沒有實現這個迭代功能,不過這個實現起來也比較簡單。
雙向線性鍊錶要實現的操作包括:
1、在尾部加入新節點
2、在頭部加入新節點
3、左插節點
4、右插節點
5、刪除乙個位置的節點
6、刪除鍊錶中所有特定資料的節點
7、訪問鍊錶中的乙個位置的資料
8、銷毀鍊錶
下面是乙個c語言版本的雙向線性鍊錶,來自2023年達內培訓的資料結構老師的講解,**可以說是完美。
標頭檔案ls.h
/*雙向線性鍊錶*/
#ifndef ls_h
#define ls_h
#include #include /*node*/
typedef struct listnode list_node;
/*鍊錶*/
typedef struct list list;
/*init*/
void list_init(list* list);
/*free rest node and recover to init*/
void list_deinit(list* list);
/*is empty?*/
bool list_emoty(list* list);
/*add to tail*/
/*add to head*/
/*add to one node front*/
void list_insert_front(list* list,size_t pos,int data);
/*add to one node back*/
void list_insert_back(list* list, size_t pos, int data);
/*rand visit*/
int* list_at(list* list,size_t pos);
/*delete*/
bool list_erase(list* list,size_t pos);
/*delete all 'data'*/
void list_remove(list* list,int data);
/*clear all*/
void list_clear(list* list);
/*how many*/
size_t list_size(list* list);
#endif/*ls_h*/
c檔案
#include #include "ls.h"
/*create a new node*/
static list_node* create_node(int data,list_node* prev,list_node* next)
/*delete node,return that node's next and prev*/
static list_node* destroy_node(list_node* node,list_node** prev)
/*init*/
void list_init(list* list)
/*free rest node and recover to init*/
void list_deinit(list* list)
/*is empty?*/
bool list_emoty(list* list)
/*add to tail*/
list->tail=create_node(data,list->tail,null);
if(list->tail->prev)
list->tail->prev->next=list->tail;
else
list->head=list->tail;
}/*add to head*/
list->head = create_node(data, null, list->head);
if (list->head->next)
list->head->next->prev = list->head;
else
list->tail = list->head;
}/*add to one node front*/
void list_insert_front(list* list,size_t pos,int data)
return false;
}/*add to one node back*/
void list_insert_back(list* list, size_t pos, int data)
return false;
}/*rand visit*/
int* list_at(list* list,size_t pos)
/*delete*/
bool list_erase(list* list,size_t pos)
}/*delete all aaaas*/
void list_remove(list* list,int data) }}
/*clear all*/
void list_clear(list* list)
/*how many*/
size_t list_size(list* list)
return size;
}
測試檔案
/*測試雙向線性鍊錶*/
#include #include "ls.h"
#include #include /*push data in list*/
void list_add(list* list)
/*print list's member*/
void list_print(list* list)
/*test insert front*/
void list_insert_front_test(list* list)
/*test_erase*/
void list_erase_test(list* list)
/*test_eraseall*/
void list_eraseall_test(list* list)
int main()
list_deinit(&list);
}
資料結構 表之煉表
頭插法建立 尾插法建立 顯示 銷毀 include include using namespace std typedef int elemtype typedef struct lnode linklist void createlinklistf linklist l,elemtype a,in...
資料結構之鍊錶
頭結點 第乙個有效結點之前的那個結點 頭結點並不存有效資料 加頭結點的目的主要是為了方便對鍊錶的操作 頭指標 指向頭結點的指標變數 尾指標 指向尾節點的指標變數 如果希望通過乙個函式對鍊錶進行處理,只需要乙個引數 頭指標 首先要定義乙個單鏈表儲存結構 然後建立乙個空表,即初始化,我寫的這個提前設定好...
資料結構之鍊錶
鍊錶是一種基本的資料結構型別,它由乙個個結點組成。每乙個結點包括乙個資料的儲存和乙個指向下乙個結點的引用。在這個定義中,結點是乙個可能含有任意型別資料的抽象實體,它所包含的指向結點的應用顯示了它在構造鍊錶之中的作用。和遞迴程式一樣,遞迴資料結構的概念一開始也令人費解,但其實它的簡潔性賦予了它巨大的價...