數(shù)據(jù)結(jié)構(gòu)之線性表

前言

線性表是指數(shù)據(jù)之間是一對一的關(guān)系,比如數(shù)組和鏈表都屬于這一范疇腐泻。數(shù)組和鏈表又代表了兩種存儲方式:順序存儲和鏈?zhǔn)酱鎯Α2糠种R已在Java集合源碼分析之基礎(chǔ)(一):數(shù)組與鏈表中闡述,這里不再贅述圆雁,本文是對這些概念的補充由桌,以及給出可參考的Java代碼實現(xiàn)为黎。

順序存儲

順序存儲在大多數(shù)語言中定義為數(shù)組。它的特點就是地址連續(xù)行您,大小固定铭乾。下面,我們從增娃循、刪片橡、查三個方面說明它的操作性。首先淮野,我們聲明了一個數(shù)組捧书,并賦值了一些初始值吹泡,如下所示:

初始條件
  1. 如果要在空閑位置插入數(shù)據(jù),例如位置6经瓷,數(shù)據(jù)插入后無需任何額外操作爆哑,此時時間復(fù)雜度為O(1),如下所示:
插入12
  1. 如果要在中間某個位置插入數(shù)據(jù)舆吮,例如想把數(shù)據(jù)6插入到5和7之間揭朝,那么7及之后的數(shù)據(jù)都需要向后移動一位,如下所示:
插入6

此時時間復(fù)雜度就不再是O(1)了色冀。我們先用java代碼實現(xiàn)它潭袱,示例如下:

public static void main(String[] args) {
    int[] arr = {1,2,5,7,9,11,0,0};
    int len = arr.length;
    // 在arr[3]插入6,注意邊界锋恬,最后的數(shù)據(jù)會被刪除
    for (int i = len-1; i >= 3; i--) {
        arr[i] = arr[i-1];
    }
    arr[3] = 6;

    for (int i = 0; i < len; i++) {
        System.out.print(arr[i]);
        System.out.print(", ");   
    }
}

運行后打印結(jié)果如下:

2, 5, 6, 7, 9, 11, 0,

最壞情況下屯换,要把元素插入到位置0,需要執(zhí)行n-1次操作与学,所以時間復(fù)雜度為O(n)彤悔。

刪除操作正好和插入相反,刪除一個數(shù)據(jù)后索守,后邊的數(shù)據(jù)都要向前移動一位晕窑,所以它的最壞時間復(fù)雜度也是O(n)

這里查分兩種情況卵佛,一種是獲取某一位置的數(shù)據(jù)杨赤,一種是查找一個值。

  1. 獲取某個位置元素

對一個數(shù)組而言截汪,數(shù)組的每個位置都可以通過位置0與偏移量計算出來望拖,例如要獲取位置6的地址,只需要:

a[6] = a[0] + 6*{數(shù)據(jù)長度}

所以它對應(yīng)的時間復(fù)雜度為O(1)挫鸽。

  1. 查找值

遺憾的是说敏,數(shù)組僅記錄下標(biāo),卻不記錄數(shù)據(jù)本身位置丢郊,而且數(shù)組的數(shù)據(jù)也不是有序的(可以插入時排序盔沫,但這不是必需),我們要查詢一個元素是否存在于數(shù)組中枫匾,需要對它進行遍歷架诞。示例代碼如下:

public static void main(String[] args) {
    int[] arr = {1,2,5,7,9,11,0,0};
    int len = arr.length;
    // 查找元素9的位置
    for (int i = 0; i < len; i++) {
        if(9 == arr[i]){
            System.out.println("Index of num 9 is : " + i);
            break;
        }
    }
}

它的最壞時間復(fù)雜度也是O(n)

  • 總結(jié)

數(shù)組是一個中規(guī)中矩的數(shù)據(jù)結(jié)構(gòu)干茉,它在增刪查方面的時間復(fù)雜度都是O(n)谴忧,僅在通過Index索引數(shù)據(jù)時為O(1)。數(shù)組也有些高級的用法,比如動態(tài)調(diào)整大小沾谓,這部分知識大家可以看我分析ArrayList的文章:Java集合源碼分析之List(二):ArrayList

鏈?zhǔn)酱鎯?/h1>

線性存儲要求一塊完整的內(nèi)存委造,在增刪數(shù)據(jù)時也表現(xiàn)一般,而鏈?zhǔn)酱鎯t正好解決了這些問題均驶。我們依然從增昏兆、刪、查三個方面來解析妇穴。首先爬虱,我們先定義使用的Java模型:

class Node{
    Integer data;
    Node next;
}

其中data表示數(shù)據(jù),next表示下一個數(shù)據(jù)的信息√谒現(xiàn)在我們實現(xiàn)了一個鏈表跑筝,如下所示:

初始條件

要在一個鏈?zhǔn)酱鎯Φ慕Y(jié)構(gòu)中插入數(shù)據(jù),只需要修改一個節(jié)點的指針域即可瞒滴。比如要把元素7插入到1和5之間曲梗,把5掛在7后面,再將1的指針域指向7的位置逛腿,示意如下:

插入7

可以看到這個操作對其他數(shù)據(jù)不會產(chǎn)生影響,所以它的時間復(fù)雜度為O(1)仅颇。

刪除與插入類似单默,其時間復(fù)雜度也是O(1),不過其操作順序和插入時相反忘瓦。例如要把數(shù)據(jù)2從原表中刪除搁廓,需要先把11掛在5的后邊,再刪除2耕皮,示意如下:

刪除2

鏈?zhǔn)酱鎯Y(jié)構(gòu)不能像數(shù)組一樣根據(jù)Index獲取數(shù)據(jù)境蜕,它的查詢也必須要遍歷,所以時間復(fù)雜度為O(n)凌停。

  • 總結(jié)

鏈?zhǔn)酱鎯Y(jié)構(gòu)增刪數(shù)據(jù)時時間復(fù)雜度是O(1)粱年,查詢和數(shù)組一樣,都是O(n)罚拟,且不支持Index獲取台诗。對比數(shù)組可以發(fā)現(xiàn),數(shù)組適合靜態(tài)的赐俗、不變的數(shù)據(jù)拉队,而鏈?zhǔn)竭m合動態(tài)的、變化頻繁的數(shù)據(jù)阻逮。

單鏈表

單鏈表結(jié)構(gòu)與上述示例類似粱快,每個數(shù)據(jù)只知道下一個位置的數(shù)據(jù),卻不知道前一位置的數(shù)據(jù)。通常事哭,定義一個單鏈表會設(shè)置一個頭結(jié)點head漫雷,它的數(shù)據(jù)域沒有意義,它的指針域指向鏈表的第一個數(shù)據(jù)慷蠕。我們用java代碼實現(xiàn)一個簡單的單鏈表珊拼。

  1. 聲明一個空鏈表
Node head = new Node(null,null);
  1. 添加一條數(shù)據(jù)
Node first = new Node(2,null);
Node second = new Node(5,null);
first.next = second;
head.next = first;
  1. 插入一條數(shù)據(jù)
Node insert = new Node(7,null);
// 注意順序,①把first也鏈接在insert后流炕,②再把insert鏈接在head后
// 因為通常情況下我們只持有head實例的引用
insert.next = head.next;
head.next = insert;
  1. 遍歷
Node print = head.next;
while (print!=null) {
    System.out.println(print.data);
    print = print.next;
}
  1. 刪除一條數(shù)據(jù)
// 刪除數(shù)據(jù)2
Node delete = head.next;
Node prev = delete;
while(delete!=null){
    if(delete.data == 2){
        // 也要注意順序澎现,先把后邊的數(shù)據(jù),掛載在前一數(shù)據(jù)后邊
        prev.next = delete.next;
        // 再刪除數(shù)據(jù)2
        delete.next = null;
        break;
    }
    // 記錄前一數(shù)據(jù)
    prev = delete;
    delete = delete.next;
}

頭結(jié)點并非是必需的每辟,只是為了保證數(shù)據(jù)一致性所添加的輔助結(jié)點剑辫。

雙向鏈表

單鏈表的特點就是簡單,但是它在遍歷時只能從前往后渠欺,這在某些情況下是不適用的妹蔽。比如所有的數(shù)據(jù)都是有序的,按照從小到大排序挠将,數(shù)據(jù)依次是{1,3,5,6,8,9,11}胳岂,現(xiàn)在我們已經(jīng)找到了數(shù)據(jù)8的位置,想要找到6舔稀,按照單鏈表的設(shè)計只能從前向后遍歷乳丰。這時候如果鏈表是雙向的,從數(shù)據(jù)8開始内贮,只需要執(zhí)行一次操作就可以了产园。

雙向鏈表是在單鏈表的基礎(chǔ)上實現(xiàn)的,只需要在原有結(jié)構(gòu)上增加一個prev指針即可夜郁,如下所示:

class Node{
    Integer data;
    Node prev;
    Node next;
}

它的操作和單鏈表類似什燕,只是在增刪時一定要注意順序,下面對這兩部分做重點說明竞端。

  1. 聲明一個空鏈表

為了數(shù)據(jù)的一致性屎即,我們增加一個tail結(jié)點,作為尾幾點:

Node head = new Node(null);
Node tail = new Node(null);
  1. 添加一條數(shù)據(jù)
Node first = new Node(2);
Node second = new Node(5);
// next和prev成對設(shè)置
second.next = tail;
tail.prev = second;
first.next = second;
second.prev = first;
head.next = first;
first.prev = head;
  1. 刪除一條數(shù)據(jù)
// 刪除數(shù)據(jù)2
Node delete = head.next;
Node prev = delete;
while(delete!=null){
    if(delete.data == 2){
        // 要注意順序事富,先把后邊的數(shù)據(jù)剑勾,掛載在前一數(shù)據(jù)后邊
        prev.next = delete.next;
        delete.next.prev = prev;
        // 再刪除數(shù)據(jù)2
        delete.next = null;
        delete.prev = null;
        break;
    }
    // 記錄前一數(shù)據(jù)
    prev = delete;
    delete = delete.next;
}

只要注意成對地處理prev和next,就不會出錯赵颅。

循環(huán)鏈表

無論是單鏈表還是雙向鏈表虽另,從某一數(shù)據(jù)開始遍歷,都不能循環(huán)整個鏈表饺谬,除非從head或tail開始遍歷捂刺。循環(huán)鏈表則可以從任意結(jié)點開始谣拣,遍歷整個鏈表极祸。它也是單鏈表的變種郭赐。

定義一個循環(huán)鏈表十分簡單袭灯,只需要把單鏈表的最后一個元素的next指針赏殃,指向head即可。示意圖如下所示:

循環(huán)鏈表

它的操作和以上鏈表都類似伴榔,這里不再贅述联喘。

總結(jié)

數(shù)組和鏈表是計算機可以存儲數(shù)據(jù)的最基本的結(jié)構(gòu)血柳,其他的數(shù)據(jù)結(jié)構(gòu)雖然定義不同恰画,但最終還是需要轉(zhuǎn)換成這兩種結(jié)構(gòu)才能進行存儲宾茂,所以我們必須深刻理解。鏈表也不是僅有以上三種形態(tài)拴还,但都是在單鏈表的基礎(chǔ)上進行改造跨晴,以適應(yīng)不同的需求。

在JDK中包裝的ArrayListLinkedList片林,就是數(shù)組和鏈表的應(yīng)用端盆,這些類包裝了數(shù)組和鏈表的常用操作,還增加了動態(tài)管理數(shù)組大小的技術(shù)费封,在性能上的表現(xiàn)十分優(yōu)秀焕妙,值得我們參考和學(xué)習(xí)。大家可以查看以下的文章學(xué)習(xí)相關(guān)知識:

Java集合源碼分析之List(二):ArrayList

Java集合源碼分析之LinkedList

以上涉及代碼均已上傳至我的github弓摘。


我是飛機醬焚鹊,如果您喜歡我的文章,可以關(guān)注我~

編程之路衣盾,道阻且長寺旺。唯爷抓,路漫漫其修遠兮势决,吾將上下而求索。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蓝撇,一起剝皮案震驚了整個濱河市果复,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渤昌,老刑警劉巖虽抄,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異独柑,居然都是意外死亡迈窟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門忌栅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來车酣,“玉大人,你說我怎么就攤上這事『保” “怎么了贫悄?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長娘摔。 經(jīng)常有香客問我窄坦,道長,這世上最難降的妖魔是什么凳寺? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任鸭津,我火速辦了婚禮,結(jié)果婚禮上读第,老公的妹妹穿的比我還像新娘曙博。我一直安慰自己,他們只是感情好怜瞒,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布父泳。 她就那樣靜靜地躺著,像睡著了一般吴汪。 火紅的嫁衣襯著肌膚如雪惠窄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天漾橙,我揣著相機與錄音杆融,去河邊找鬼。 笑死霜运,一個胖子當(dāng)著我的面吹牛脾歇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淘捡,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼藕各,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了焦除?” 一聲冷哼從身側(cè)響起激况,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎膘魄,沒想到半個月后乌逐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡创葡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年浙踢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灿渴。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡洛波,死狀恐怖呐芥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情奋岁,我是刑警寧澤思瘟,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站闻伶,受9級特大地震影響滨攻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蓝翰,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一光绕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧畜份,春花似錦诞帐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钙态,卻和暖如春慧起,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背册倒。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工蚓挤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驻子。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓灿意,卻偏偏與公主長得像,于是被迫代替她去往敵國和親崇呵。 傳聞我的和親對象是個殘疾皇子缤剧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)自:http://blog.csdn.net/oreo_go/article/details/52116214 ...
    YYT1992閱讀 976評論 0 4
  • 大學(xué)的時候不好好學(xué)習(xí),老師在講臺上講課演熟,自己在以為老師看不到的座位看小說鞭执,現(xiàn)在用到了老師講的知識司顿,只能自己看書查資...
    和玨貓閱讀 1,444評論 1 3
  • 一些概念 數(shù)據(jù)結(jié)構(gòu)就是研究數(shù)據(jù)的邏輯結(jié)構(gòu)和物理結(jié)構(gòu)以及它們之間相互關(guān)系芒粹,并對這種結(jié)構(gòu)定義相應(yīng)的運算,而且確保經(jīng)過這...
    Winterfell_Z閱讀 5,817評論 0 13
  • 每次看了電影都想寫影評大溜,但這次是第一次寫化漆。 心靈捕手很早很早就下了的,當(dāng)時下來看只是因為他是一部心理學(xué)的經(jīng)典作品钦奋。...
    橘冬林閱讀 422評論 0 0
  • 張開了血盆大口的獸座云,漆黑深邃的眼瞳擁有著無限魔力疙赠,令人迷幻,心甘情愿走進它的口朦拖。 只是那一個個無辜的前仆后繼的犧牲...
    西風(fēng)烈_df37閱讀 146評論 0 0