鏈表

Warring: 本篇文章純粹是爲了勾引你去使用 stl 或 java 集合類,未必面面俱到,在文末我會推薦一些其他鏈接。

  大三以前我一直沒寫過什麼大程序,一個程序頂多兩三百行了事,總是不停地重造車輪:每個程序都重寫一遍鏈表、棧、隊列,認爲這是依賴最少的“純C程序”。

  後來《數據挖掘》第一次上機作業——挖頻繁項集,我又開始寫“純C程序”了:一開始就輕鬆地實現了一個鏈表,然後我發現還得實現多個鏈表組成的集合,於是又得去實現一個“鏈表的鏈表”,這時我就覺得有點煩了:編程應該是一件快樂的事情,老是去折騰鏈表就無聊了,要是有直接能用的鏈表就好了。

  恰好C++的 stl 庫和java的 util 包就提供了這樣的鏈表: C++中的 list、java中 LinkedList。

使用它們至少有如下優點:

一 支持任意數據類型

  list 使用了模版,LinkedList 使用了泛型,使得它們支持各種數據類型:

// C++ 例子
#include <iostream>
#include <list>
using namespace std;

typedef struct _MyStruct{
    int a;
    double b;
}MyStruct;

int main()
{
    list<int> lint;
    list<MyStruct> lstruct;
    list<string> lclass;
    list<int*> lpoint;

    // 鏈表的鏈表
    list<list<int> > llist;
    /*上面有個空格是給VC6吃的,
    VS2010等都表示沒胃口*/

    return 0;
}
// java 例子
import java.util.LinkedList;

interface MyInterface{
    public void nothing();
}

public class Temp {

    @SuppressWarnings("unused")
    public static void main(String[] args) {
        LinkedList<Integer> lint; // 基本類型使用包裝類
        LinkedList<String> lclass;
        LinkedList<MyInterface> linter;// 接口也可以

        // 鏈表的鏈表
        LinkedList<LinkedList<Integer>> llist;
    }

}

二 定義後即可進行操作

  list 和 LinkedList 都是基於對象的,面向對象的一個特性就是數據和操作的整合,對象不僅有成員數據,還有成員函數,所以我們在定義了鏈表後就可以使用各種操作啦!VC、VS中C++對象引用成員函數可自動補齊,既省腦力又省指力,eclipse中java對象引用成員方法的自動補齊則更爲犀利。

// C++ 例子
#include <iostream>
#include <list>
using namespace std;

int main()
{
    list<int> L;

    L.push_back(2);// 尾部追加

    L.push_back(3);
    L.push_front(1);// 頭部添加

    L.pop_back();// 尾部刪除
    L.pop_front();// 頭部刪除

    cout<<L.front()<<endl;
    // 輸出結果是 2

    return 0;
}
// java 例子
import java.util.LinkedList;

public class Temp {

    public static void main(String[] args) {
        // java 的對象都是 new 出來的
        LinkedList<Integer> L = new LinkedList<Integer>();

        // 以下流程同 C++ 版
        L.addLast(2);

        L.add(3);// 同addLast
        L.addFirst(1);

        L.removeLast();
        L.removeFirst();

        System.out.println(L.getFirst());
    }

}

三 源碼可見(授人以漁

list 和 LinkedList 等集合類是完全開源的,閱讀源代碼能解開一切疑惑。

C++

在 VC、VS 中選中記號,右鍵彈出菜單,選擇“轉到定義”:

然後就跳到了它定義的地方:

  printf 等函數如果選擇“轉到定義”,我們還是隻能看到它們在頭文件中的聲明,其具體實現是看不到的。但是 stl 的集合類的源代碼全部寫在頭文件中,所以我們能看到完整的源代碼。

  不過由於 stl 的實現使用了大量的宏,很難看明白,而我也不是靠 C++ 吃飯的,所以也就不自找麻煩,懶得去看了。所以如果你看到我說“list 是雙向鏈表”,那是我從書上看到的,或者我猜的^_^。

java (eclipse中)

選中記號,一個框框自己就冒出來了:

下面有兩個按鈕:

  •  是轉到定義
  •  是轉到在線文檔,沒有源代碼,但是有豐富的使用方法 或 類關係樹 等。

首次使用“轉到定義”時可能會提示“Source not found”:

點擊 Attach Source 按鈕,選擇 jdk 安裝目錄下的 src.zip就可以了:
我的路徑是D:/Program Files/Java/jdk1.7.0/src.zip

我是怎麼知道這些菜單/按鈕的

  一開始剛使用 VC、eclipse 開發環境的時候我也什麼都不懂,然後會寫、編譯、運行 Hello World 級的程序了,然後就試驗性地使用一些平時不用的菜單/按鈕,也許有些菜單/按鈕可有可無,但是它們能提高效率,這也是很值得去掌握的。

四 可靠

  windows 和 linux 下 C++ 中都可以使用 stl,否則也不會被稱爲“標準模板庫”了;而 java 的 util 包中的各種集合類也是跨平臺使用的。

  我們自己寫的鏈表有可能存在 Bug,但是使用 stl 和 util 的集合類就不用擔心了:那是一羣專業人士開發出來的,都用了N年了,要是程序中出現了 Bug,一定不是 list 或 LinkedList 的責任。

棧和隊列

  查看源代碼可以知道 list 和 LinkedList 都是雙向鏈表, 兩端都可以添加、刪除元素,於是它們又是天生的棧和隊列:

棧操作 list LinkedList
方案一 方案二 方案一 方案二
Push push_back push_front addLast addFirst
Pop 先back後pop_back 先front後pop_front removeLast removeFirst

隊列

隊列操作 list LinkedList
方案一 方案二 方案一 方案二
Enqueue push_back push_front addLast addFirst
Dequeue 先front後pop_front 先back後pop_back removeFirst removeLast

這些操作的時間複雜度都是 O(1),最優的O(∩_∩)O~。

 

這篇介紹了鏈表,順帶着把棧和隊列也搞定了,我想你已經感覺到 stl 或 util 的強大了。C++ 設計得很複雜,還有操作符重載,所以我一直對 C++ 懷有成見,也正是發現了 stl 的強大,我才逐漸喜歡上 C++,現在如果做可執行程序的話我肯定選 C++,複雜的語言也可以簡單地用不是!

推薦鏈接

三十分鐘掌握STL(前半部分很不錯,後半部分真心沒看懂o(╯□╰)o)

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