在單向鍊錶原理和實現中已經和動態陣列相比對比並分析了單向鍊錶的時間複雜度:
情況分類
新增刪除
最好 頭節點
o(1)
o(1)
最差 尾節點
o(n)
o(n)
平均o(n)
o(n)
因為對節點的新增和刪除操作需要查詢對於index的節點,首先分析以下查詢節點的**:
- (jkrlinkedlistnode *)nodewithindex:(nsinteger)index
return node;
} else
return node;
}}複製**
當index == 0 或 index == _size - 1時,即查詢頭節點和尾節點時,直接就可以一次查詢就拿到需要的節點。越靠近頭節點或尾節點,查詢需要遍歷的次數越小,最壞的情況就是查詢中間的節點,需要 n / 2 次查詢。
- (void)insertobject:(id)anobject atindex:(nsuinteger)index else
} else else
}_size++;
}複製**
由於新增的所有情況對節點prev和next操作都是相同的,區別就是通過index查詢節點,這取決於上面查詢節點的複雜度。因此可以推出結論,雙向鍊錶刪除頭節點、尾節點都是o(1),越靠近頭節點或尾節點操作時間越快,越靠近鍊錶中間越慢。平均複雜度為o(n),而刪除同新增。
情況分類
新增刪除
最好 頭節點
o(1)
o(1)
最好 尾節點
o(1)
o(1)
平均o(n)
o(n)
由上面的結論可以知道,單向鍊錶和雙向鍊錶在操作頭節點、鍊錶的前半部分、鍊錶的中間節點時都是一樣的。而雙向鍊錶在操作尾節點、鍊錶後半部分是大大優於單向鍊錶的。
下面是一段對比測試,分別對比了單向鍊錶和雙向鍊錶在對頭節點、尾節點、前半部分節點、後半部分節點、中間節點這五種情況下的對比:
void comparesinglelinkedlistandlinkedlist
() for (nsuinteger i = 0; i < testcount; i++)
nslog(@"單向鍊錶操作頭節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"雙向鍊錶操作頭節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"單向鍊錶操作尾節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"雙向鍊錶操作尾節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"單向鍊錶操作 index = 總節點數*0.25 節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"雙向鍊錶操作 index = 總節點數*0.25 節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"單向鍊錶操作 index = 總節點數*0.75 節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"雙向鍊錶操作 index = 總節點數*0.75 節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"單向鍊錶操作中間節點");
}];[jkrtimetool teskcodewithblock:^
for (nsuinteger i = 0; i < testcount; i++)
nslog(@"雙向鍊錶操作中間節點");
}];}複製**
列印結果:
單向鍊錶操作頭節點
耗時: 0.020 s
雙向鍊錶操作頭節點
耗時: 0.038 s
單向鍊錶操作尾節點
耗時: 49.085 s
雙向鍊錶操作尾節點
耗時: 0.033 s
單向鍊錶操作 index = 總節點數*0.25 節點
耗時: 12.144 s
雙向鍊錶操作 ndex = 總節點數*0.25 節點
耗時: 12.215 s
單向鍊錶操作 index = 總節點數*0.75 節點
耗時: 35.735 s
雙向鍊錶操作 index = 總節點數*0.75 節點
耗時: 18.488 s
單向鍊錶操作中間節點
耗時: 23.856 s
雙向鍊錶操作中間節點
耗時: 36.420 s
複製**
上面的列印可以看到,單向鍊錶在操作頭節點、尾節點、中間節點、前半部分節點時,部分情況是優於雙向鍊錶,這也是由於單向鍊錶對節點操作次數少於雙向鍊錶,因為它不用操作節點指向前乙個節點的指標。但是當操作後半部分節點、尾節點時,單向鍊錶的效率就會大大低於雙向鍊錶。
所以,當只需要對資料的頭部或者前半部分進行操作時,單向鍊錶和雙向鍊錶時間複雜度一致,並且單向鍊錶更加精簡高效。但是如果需要對資料的頭部、尾部都要進行操作時,雙向鍊錶大大優於單向鍊錶。
資料結構 反轉單向鍊錶和雙向鍊錶
程式設計師 面試指南 左程雲 讀書筆記 第三章反轉單向鍊錶和雙向鍊錶 單向鍊錶 public class node public class returnlist public static node relist node head 逆序後的第乙個節點 node pre null node nex...
資料結構四雙向鍊錶
雙向鍊錶也叫雙鏈表,是鍊錶的一種,它的每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅。所以,從雙向鍊錶中的任意乙個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。而之前的單鏈表為單向鍊錶,雙向鍊錶也就是在單鏈表的結點中增加乙個指向其前驅的pre指標。如圖 這裡介紹雙向鍊錶的常用操作 l ...
資料結構 003雙向鍊錶
雙鏈表 include using namespace std typedef int elemtype typedef struct lnode lnode,linklist 初始化 linklist init linklist 頭插法建立鍊錶 linklist head insert linkl...