第三節、大秦帝國的連坐與鏈表(一)
孫皓暉先生在《大秦帝國(第一部)》中講到:
烈酒下喉,衛鞅精神為之一振,“《治秦九論》乃衛鞅謀劃的變法大綱。其一《田論》,立定廢井田、開阡陌、田得買賣之法令……其五《郡縣論》,將秦國舊世族的自治封地一律取締,設郡縣兩級官府,直轄於國府之下,使全國治權一統,如臂使指。其六《連坐論》,縣下設裏、村、甲三級小吏。民以十戶為一甲,一人犯罪,十戶連坐,使民眾怯於私鬥犯罪而勇於公戰立功。”
連坐制就是一條隱形的繩子,把“鄉裏鄉親”們串聯起來。
(連坐制確實在特定的歷史條件下發揮了巨大的作用,之後一系列的制度安排又將大秦帝國拖入了深淵。)
連坐制本身就像一個鏈表(Linked list ),一個個的人串聯起來,形成一種獨特的結構。
2、鏈表的由來和表示
存儲數據的時候我們通常用的是數組,數組最大的特點就是可以通過下標快速查找,也就是便於檢索。
但對於線性表(數組和鏈表都屬於線性表)常見的插入操作,數組就有些力不從心了。
為了在數組中插入一個數據,需要移動後面所有的數據!
鏈表正是為了快速插入的問題。
鏈表每一個節點都由數據域和指向下一個節點的指針構成;
多個節點首尾相連,構成線性表。
上一節《第二節、算法中的公平——隊列》我們講到了結構體,忘記結構體的定義的同學可以出門左轉,查看上一節。
這裏,我們就使用結構體表示鏈表,struct list_node就是鏈表的一個節點,包含一個數據域和一個指向下一個節點的指針。
typedef struct list_node {
int data ; //數據域,用於存儲數據
struct list_node *next ; //指向下一個節點的指針
}single_list;
這裏的struct list_node的用法與上一節的不同,使用typedef,大括號後面也有single_list。
這樣以後在定義struct list_node變量的時候就不用寫一大長串了,直接single_list就可以了。
//下面兩種方式等價
struct list_node node;
single_list node;
3、鏈表的基本用法
與此同時,為了實現便於插入數據
所以,鏈表的初始化以及插入操作需要申請存儲空間,函數為malloc()函數,用來分配存儲空間。對應的有釋放存儲空間,使用free()函數。
由於項目運行結束後會自動回收存儲空間,所以對於小項目而言,可以不手動回收,有興趣可以搜索free()函數的用法。
下面的代碼生成了一個最開始的一個節點,數據data存儲的是5,因為接下來沒有數據,所以next指針指向空NULL。
#include <stdlib.h> //malloc函數需要使用這個頭文件
single_list *node = NULL; //1、定義頭指針
node = (single_list *)malloc(sizeof(single_list)); //2、分配內存空間
node->data = 5; //3、給鏈表節點的數據賦值
node->next = NULL; //4、將鏈表的指針域指向空
我們可以printf打印數據,查看結果。
完整代碼:
/*
輸出:5
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct list_node
{
int data;
struct list_node *next;
}single_list;
int main()
{
single_list *node = NULL; //1、定義一個頭指針
node = (single_list *)malloc(sizeof(single_list)); //2、分配內存空間
node->data = 5; //3、給鏈表節點的數據賦值
node->next = NULL; //4、將鏈表的指針域指向空
printf("%d\n", node->data);
getchar();getchar();
return 0;
}
這裏我們使用了->這個運算符,叫做結構體指針運算符,用來表示結構體內部的指針指向空間存儲的數據,比較拗口,看個例子就知道了。
//兩者等價,省了個括號!程序員都是偷懶的!
node->data = 5;
(*node).data=5;
4、小結
這一小節介紹的新知識比較多,吃多了難以消化,所以就不介紹更多了。簡單回顧下:
- 鏈表,就是節點連在一起
- 每一個節點包含一個數據域和指向下一個節點的指針
- 鏈表最大的好處是插入數據快
- 為了實現插入數據快的功能,鏈表長度可變,要手動分配空間
鏈表的插入、刪除、遍歷操作,我們下一節再見!
第三節、大秦帝國的連坐與鏈表(一)