經典演算法題每日演練 第二十五題 塊狀鍊錶

2021-09-23 21:52:04 字數 4543 閱讀 9447

在資料結構的世界裡,我們會認識各種各樣的資料結構,每一種資料結構都能解決相應領域的問題,每一種資料結構都像

是降龍十八掌中的某一掌,掌掌斃命。。。 當然每個資料結構,有他的優點,必然就有它的缺點,那麼如何創造一種資料結構

來將某兩種資料結構進行揚長避短,那就非常完美了。這樣的資料結構也有很多,比如:雙端佇列,還有就是今天講的 塊狀鍊錶,

我們都知道 陣列 具有 o(1)的查詢時間,o(n)的刪除,o(n)的插入。。。

鍊錶 具有 o(n)的查詢時間,o(1)的刪除,o(1)的插入。。。 

那麼現在我們就有想法了,何不讓「鍊錶」和「陣列」結合起來,來一起均攤curd的時間,做法將陣列進行分塊,然後用指標相連線,

比如我有n=100個元素,那麼最理想情況下,我就可以將陣列分成x=10段,每段b=10個元素(排好序),那麼我可以用√n的時

間找到段,因為段中的元素是已經排好序的,所以可以用lg√n的時間找到段中的元素,那麼最理想的複雜度為√n+lg√n≈√n。。。

下面我們看看怎麼具體使用:

一:結構定義

這個比較簡單,我們在每個鍊錶節點中定義乙個 頭指標,尾指標 和 乙個陣列節點。

public class blocklinknode

二: 插入

剛才也說了,每個鍊錶節點的資料是乙個陣列塊,那麼問題來了,我們是根據什麼將陣列切開呢?總不能將所有的資料都放在乙個

鍊錶的節點吧,那就退化成陣列了,在理想的情況下,為了保持√n的陣列個數,所以我們定了乙個界限2√n,當鍊表中的節點陣列

的個數超過2√n的時候,當下次插入資料的時候,我們有兩種做法:

① 在元素的陣列插入處,將當前陣列切開,插入元素處之前為乙個鍊錶節點,插入元素後為乙個鍊錶節點。

② 將元素插入陣列後,將陣列從中間位置切開。

/// /// 新增元素只會進行塊狀鍊錶的**

///

///

///

///

private blocklinknode add(blocklinknode node, int num)

else

var blocklen = (int)math.ceiling(math.sqrt(total)) * 2;

//如果該節點的陣列的最後位置值大於插入值,則此時我們找到了鍊錶的插入節點,

//或者該節點的next=null,說明是最後乙個節點,此時也要判斷是否要裂開

if (node.list[node.list.count - 1] > num || node.next == null)

total = total + 1;

return node;

}return add(node.next, num);}}

二:刪除

跟插入道理一樣,既然有裂開,就有合併,同樣也定義了乙個界限值√n /2  ,當鍊表陣列節點的陣列個數小於這個界限值

的時候,需要將此節點和後面的鍊錶節點進行合併。

/// /// 從塊狀鍊錶中移除元素,涉及到合併

///

///

///

///

private blocklinknode remove(blocklinknode node, int num)

else

else}}

return node;

}return remove(node.next, num);}}

四: 查詢

在理想的情況下,我們都控制在√n,然後就可以用√n的時間找到區塊,lg√n的時間找到區塊中的指定值,當然也有人在查詢

的時候做 鍊錶的合併和**,這個就有點像伸展樹一樣,在查詢的時候動態調整,拼的是均攤情況下的複雜度。這裡順便提醒你一

下,其實你也可以這麼做。。。

public string get(int num)

塊中的個位置", blockindex, arrindex);

}blockindex = blockindex + 1;

temp = temp.next;

}return string.empty;

}

好了,curd都分析好了,到這裡大家應該對 塊狀鍊錶 有個大概的認識了吧,這個**是我下午抽閒寫的,沒有仔細測試,

最後是總的**:

using system;

using system.collections.generic;

using system.linq;

using system.text;

;

//listlist = new list();

//for (int i = 0; i < 100; i++)

//blocklinklist blocklist = new blocklinklist();

foreach (var item in list)

//var b = blocklist.i***ist(333);

console.writeline(blocklist.get(27208));

#region myregion

隨機刪除150個元素

//for (int i = 0; i < 5000; i++)

//", list[rand]);

// blocklist.remove(list[rand]);

// console.writeline("\n\n");

// if (blocklist.getcount() == 0)

//

//}

#endregion

console.read();}}

public class blocklinklist;}

/// /// 定義塊狀鍊錶的總長度

///

private int total;

public class blocklinknode

/// /// 判斷指定元素是否存在

///

///

///

public bool i***ist(int num)

temp = temp.next;

}return i***ist;

}public string get(int num)

塊中的個位置", blockindex, arrindex);

}blockindex = blockindex + 1;

temp = temp.next;

}return string.empty;

}/// /// 將元素加入到塊狀鍊錶中

///

///

public blocklinknode add(int num)

/// /// 新增元素只會進行塊狀鍊錶的**

///

///

///

///

private blocklinknode add(blocklinknode node, int num)

else

var blocklen = (int)math.ceiling(math.sqrt(total)) * 2;

//如果該節點的陣列的最後位置值大於插入值,則此時我們找到了鍊錶的插入節點,

//或者該節點的next=null,說明是最後乙個節點,此時也要判斷是否要裂開

if (node.list[node.list.count - 1] > num || node.next == null)

total = total + 1;

return node;

}return add(node.next, num);}}

/// /// 從塊狀鍊錶中移除元素

///

///

///

public blocklinknode remove(int num)

/// /// 從塊狀鍊錶中移除元素,涉及到合併

///

///

///

///

private blocklinknode remove(blocklinknode node, int num)

else

else}}

return node;

}return remove(node.next, num);}}

/// /// 獲取塊狀鍊錶中的所有個數

///

///

public int getcount()

console.writeline("總共有: 個元素", count);

return count;}}

}

劍指offer第二十五題

題目描述 輸入乙個複雜鍊錶 每個節點中有節點值,以及兩個指標,乙個指向下乙個節點,另乙個特殊指標指向任意乙個節點 返回結果為複製後複雜鍊錶的head。注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空 思路 1 在原來的鍊錶每個節點後面新增乙個節點,該節點下面連線著原來節點的下乙個...

經典演算法題每日演練 第二十四題 梳排序

這篇再看看乙個經典的排序,梳排序,為什麼取名為梳,可能每個梳都有自己的gap吧,大梳子gap大一點,小梳子gap小一點。氣泡排序上我們的選擇是相鄰的兩個數做比較,就是他們的gap為1,其實梳排序提出了不同的觀點,如果將這裡的gap設定為一定的大小,效率反而必gap 1要高效的多。下面我們看看具體思想...

經典演算法題每日演練 第二十四題 梳排序

原文 經典演算法題每日演練 第二十四題 梳排序 這篇再看看乙個經典的排序,梳排序,為什麼取名為梳,可能每個梳都有自己的gap吧,大梳子gap大一點,小梳子gap小一點。氣泡排序上我們的選擇是相鄰的兩個數做比較,就是他們的gap為1,其實梳排序提出了不同的觀點,如果將這裡的gap設定為一定的大小,效率...