1. 程式人生 > >資料結構與演算法——連結串列

資料結構與演算法——連結串列

連結串列

定義

連結串列是一種物理儲存單元上非連續、非順序的儲存結構,資料元素的邏輯順序是通過連結串列中的指標連結次序實現的。連結串列由一系列結點(連結串列中每一個元素稱為結點)組成,結點可以在執行時動態生成。每個結點包括兩個部分:一個是儲存資料元素的資料域,另一個是儲存下一個結點地址的指標域。 相比於線性表順序結構,操作複雜。由於不必須按順序儲存,連結串列在插入的時候可以達到O(1)的複雜度,比另一種線性表順序錶快得多,但是查詢一個節點或者訪問特定編號的節點則需要O(n)的時間,而線性表和順序表相應的時間複雜度分別是O(logn)和O(1)。

使用連結串列結構可以克服陣列連結串列需要預先知道資料大小的缺點,連結串列結構可以充分利用計算機記憶體空間,實現靈活的記憶體動態管理。但是連結串列失去了陣列隨機讀取的優點,同時連結串列由於增加了結點的指標域,空間開銷比較大。連結串列最明顯的好處就是,常規陣列排列關聯專案的方式可能不同於這些資料專案在記憶體或磁碟上順序,資料的存取往往要在不同的排列順序中轉換。連結串列允許插入和移除表上任意位置上的節點,但是不允許隨機存取。連結串列有很多種不同的型別:單向連結串列,雙向連結串列以及迴圈連結串列。連結串列可以在多種程式語言中實現。像Lisp和Scheme這樣的語言的內建資料型別中就包含了連結串列的存取和操作。程式語言或面嚮物件語言,如C,C++和Java依靠易變工具來生成連結串列

特徵

連結串列主要有以下幾大特性:

  • 1、解決陣列無法儲存多種資料型別的問題

  • 2、解決陣列中,元素個數無法改變的限制(C99的變長陣列,C++也有變長陣列可以實現)。

  • 3、陣列移動元素的過程中,要對元素進行大範圍的移動,很耗時間,效率也不高。

用C語言—構建一個連結串列

先來感性的認識一下連結串列,我們先來認識下簡單的連結串列 在這裡插入圖片描述 從這幅圖我們得出以下資訊:

這個簡單鏈表的構成:

頭指標(Header),若干個節點(節點包括了資料域和指標域),最後一個節點要指向空。

實現原理: 頭指標指向連結串列的第一個節點,然後第一個節點中的指標指向下一個節點,然後依次指到最後一個節點,這樣就構成了一條連結串列。

接下來看看連結串列的資料結構:

//定義一個結構體
struct  list_node
{
	int data ; //資料域,用於儲存資料
	struct list_node *next ; //指標,可以用來訪問節點資料,也可以遍歷,指向下一個節點
};

那麼如何來建立一個連結串列的一個節點呢?

我們寫個程式演示一下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct  list_node
{
	int data ; 
	struct list_node *next ;
};
 
typedef struct list_node list_single ; 	//用list_single代替list_node型別,下面見到list_single就包含了上面自定義的結構體的資料型別
 
int main(void)
{
	list_single *node = NULL ;          //1、首先,當然是定義一個頭指標
	node = (list_single *)malloc(sizeof(list_single)); //2、然後分配記憶體空間,malloc函式功能是動態記憶體分配,用於申請一塊連續的指定大小的記憶體塊區域以 void*型別返回分配的記憶體區域地址,當無法知道記憶體具體位置的時候,想要繫結真正的記憶體空間,就需要用到動態的分配記憶體。具體可以自己查閱相關書籍和網頁。
	if(node == NULL)
	{
		printf("malloc fair!\n");
	}
	memset(node,0,sizeof(list_single)); //3、清一下 memset() 函式可以說是初始化記憶體的“萬能函式”,通常為新申請的記憶體進行初始化工作。它是直接操作記憶體空間,mem即“記憶體”(memory)的意思
	node->data = 100 ;		    		//4、給連結串列節點的資料賦值
	node->next = NULL ;                 //5、將連結串列的指標域指向空
	printf("%d\n",node->data);
	free(node);
	return 0 ;
}

那麼,這僅僅只是建立一個連結串列中的一個節點,為了好看,我們把建立節點封裝成函式,以後想建立多少個節點,我們就可以反覆呼叫一個函式來建立,會很方便:

list_single *create_list_node(int data)
{
	list_single *node = NULL ;
	node = (list_single *)malloc(sizeof(list_single));
	if(node == NULL){
		printf("malloc fair!\n");
	}
	memset(node,0,sizeof(list_single));
	node->data = 100 ;
	node->next = NULL ;
	return node ;
}

接下來在程式上完成的程式:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct  list_node
{
	int data ; 
	struct list_node *next ;
};
 
typedef struct list_node list_single ; 	
list_single *create_list_node(int data)
{
	list_single *node = NULL ;
	node = (list_single *)malloc(sizeof(list_single));
	if(node == NULL){
		printf("malloc fair!\n");
	}
	memset(node,0,sizeof(list_single));
	node->data = 100 ;
	node->next = NULL ;
	return node ;
}
int main(void)
{
	int data = 100 ;
	list_single *node_ptr = create_list_node(data); //建立一個節點
	printf("node_ptr->data=%d\n",node_ptr->data);   //列印節點裡的資料
	printf("node_ptr->next=%d\n",node_ptr->next);  
	free(node_ptr);
	return 0 ;
}

執行結果: 在這裡插入圖片描述 這樣我們就完成一個連結串列節點的建立了,那麼它現在的樣子如下圖:

連結串列的結構裡,資料儲存了100,因為這個連結串列只有一個節點,所以它的指標域指向了NULL。 在這裡插入圖片描述