最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#實現(xiàn)塊狀鏈表的項目實踐

 更新時間:2023年11月27日 15:00:42   作者:神仙別鬧  
這篇文章主要介紹了C#實現(xiàn)塊狀鏈表的項目實踐,通過定義塊和鏈表類,利用塊內(nèi)元素引用實現(xiàn)塊與塊之間的鏈接關(guān)系,從而實現(xiàn)對塊狀鏈表的遍歷、插入和刪除等操作,感興趣的可以了解一下

在數(shù)據(jù)結(jié)構(gòu)的世界里,我們會認(rèn)識各種各樣的數(shù)據(jù)結(jié)構(gòu),每一種數(shù)據(jù)結(jié)構(gòu)都能解決相應(yīng)領(lǐng)域的問題,當(dāng)然每個數(shù)據(jù)結(jié)構(gòu),有他的優(yōu)點,必然就有它的缺點,那么如何創(chuàng)造一種數(shù)據(jù)結(jié)構(gòu)來將某兩種數(shù)據(jù)結(jié)構(gòu)進(jìn)行揚(yáng)長避短,那就非常完美了。這樣的數(shù)據(jù)結(jié)構(gòu)也有很多,比如:雙端隊列,還有就是今天講的塊狀鏈表。

我們都知道

  • 數(shù)組 具有 O(1)的查詢時間,O(N)的刪除,O(N)的插入。。。
  • 鏈表 具有 O(N)的查詢時間,O(1)的刪除,O(1)的插入。。。

那么現(xiàn)在我們就有想法了,何不讓“鏈表”和“數(shù)組”結(jié)合起來,來一起均攤 CURD 的時間,做法將數(shù)組進(jìn)行分塊,然后用指針相連接,比如我有 N=100 個元素,那么最理想情況下,我就可以將數(shù)組分成 x=10 段,每段 b=10 個元素(排好序),那么我可以用 √N 的時間找到段,因為段中的元素是已經(jīng)排好序的,所以可以用 lg√N 的時間找到段中的元素,那么最理想的復(fù)雜度為 √N+lg√N≈√N。。。

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

一、結(jié)構(gòu)定義

這個比較簡單,我們在每個鏈表節(jié)點中定義一個 頭指針,尾指針和一個數(shù)組節(jié)點。

 public class BlockLinkNode
 {
     /// <summary>
     /// 指向前一個節(jié)點的指針
     /// </summary>
     public BlockLinkNode prev;

     /// <summary>
     /// 指向后一個節(jié)點的指針
     /// </summary>
     public BlockLinkNode next;

     /// <summary>
     /// 鏈表中的數(shù)組
     /// </summary>
     public List<int> list;
 }

二、插入

剛才也說了,每個鏈表節(jié)點的數(shù)據(jù)是一個數(shù)組塊,那么問題來了,我們是根據(jù)什么將數(shù)組切開呢?總不能將所有的數(shù)據(jù)都放在一個鏈表的節(jié)點吧,那就退化成數(shù)組了,在理想的情況下,為了保持 √N 的數(shù)組個數(shù),所以我們定了一個界限 2√N,當(dāng)鏈表中的節(jié)點數(shù)組的個數(shù)超過 2√N 的時候,當(dāng)下次插入數(shù)據(jù)的時候,我們有兩種做法:

在元素的數(shù)組插入處,將當(dāng)前數(shù)組切開,插入元素處之前為一個鏈表節(jié)點,插入元素后為一個鏈表節(jié)點。將元素插入數(shù)組后,將數(shù)組從中間位置切開。

image.png

 /// <summary>
 /// 添加元素只會進(jìn)行塊狀鏈表的分裂
 /// </summary>
 /// <param name="node"></param>
 /// <param name="num"></param>
 /// <returns></returns>
 private BlockLinkNode Add(BlockLinkNode node, int num)
 {
     if (node == null)
     {
         return node;
     }
     else
     {
         /*
          *  第一步:找到指定的節(jié)點
          */
         if (node.list.Count == 0)
         {
             node.list.Add(num);

             total = total + 1;

             return node;
         }

         //下一步:再比較是否應(yīng)該分裂塊
         var blockLen = (int)Math.Ceiling(Math.Sqrt(total)) * 2;

         //如果該節(jié)點的數(shù)組的最后位置值大于插入值,則此時我們找到了鏈表的插入節(jié)點,
         //或者該節(jié)點的next=null,說明是最后一個節(jié)點,此時也要判斷是否要裂開
         if (node.list[node.list.Count - 1] > num || node.next == null)
         {
             node.list.Add(num);

             //最后進(jìn)行排序下,當(dāng)然可以用插入排序解決,O(N)搞定
             node.list = node.list.OrderBy(i => i).ToList();

             //如果該數(shù)組里面的個數(shù)大于2*blockLen,說明已經(jīng)過大了,此時需要對半分裂
             if (node.list.Count > blockLen)
             {
                 //先將數(shù)據(jù)插入到數(shù)據(jù)庫
                 var mid = node.list.Count / 2;

                 //分裂處的前段部分
                 var firstList = new List<int>();

                 //分裂后的后段部分
                 var lastList = new List<int>();

                 //可以在插入點處分裂,也可以對半分裂(這里對半分裂)
                 firstList.AddRange(node.list.Take(mid));
                 lastList.AddRange(node.list.Skip(mid).Take(node.list.Count - mid));


                 //開始分裂節(jié)點,需要新開辟一個新節(jié)點
                 var nNode = new BlockLinkNode();

                 nNode.list = lastList;
                 nNode.next = node.next;
                 nNode.prev = node;

                 //改變當(dāng)前節(jié)點的next和list
                 node.list = firstList;
                 node.next = nNode;
             }

             total = total + 1;

             return node;
         }

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

二、刪除

跟插入道理一樣,既然有裂開,就有合并,同樣也定義了一個界限值 √N /2 ,當(dāng)鏈表數(shù)組節(jié)點的數(shù)組個數(shù)小于這個界限值的時候,需要將此節(jié)點和后面的鏈表節(jié)點進(jìn)行合并。
image.png

 /// <summary>
 /// 從塊狀鏈表中移除元素,涉及到合并
 /// </summary>
 /// <param name="node"></param>
 /// <param name="num"></param>
 /// <returns></returns>
 private BlockLinkNode Remove(BlockLinkNode node, int num)
 {
     if (node == null)
     {
         return node;
     }
     else
     {
         //第一步: 判斷刪除元素是否在該節(jié)點內(nèi)
         if (node.list.Count > 0 && num >= node.list[0] && num <= node.list[node.list.Count - 1])
         {
             //定義改節(jié)點的目的在于防止remove方法假刪除的情況發(fā)生
             var prevcount = node.list.Count;

             node.list.Remove(num);

             total = total - (prevcount - node.list.Count);

             //下一步: 判斷是否需要合并節(jié)點
             var blockLen = (int)Math.Ceiling(Math.Sqrt(total) / 2);

             //如果當(dāng)前節(jié)點的數(shù)組個數(shù)小于 blocklen的話,那么此時改節(jié)點需要和后一個節(jié)點進(jìn)行合并
             //如果該節(jié)點時尾節(jié)點,則放棄合并
             if (node.list.Count < blockLen)
             {
                 if (node.next != null)
                 {
                     node.list.AddRange(node.next.list);

                     //如果下一個節(jié)點的下一個節(jié)點不為null,則將下下個節(jié)點的prev賦值
                     if (node.next.next != null)
                         node.next.next.prev = node;

                     node.next = node.next.next;
                 }
                 else
                 {
                     //最后一個節(jié)點不需要合并,如果list=0,則直接剔除該節(jié)點
                     if (node.list.Count == 0)
                     {
                         if (node.prev != null)
                             node.prev.next = null;

                         node = null;
                     }
                 }
             }

             return node;
         }

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

三、查詢

在理想的情況下,我們都控制在 √N,然后就可以用 √N 的時間找到區(qū)塊,lg√N 的時間找到區(qū)塊中的指定值,當(dāng)然也有人在查詢的時候做 鏈表的合并和分裂,這個就有點像伸展樹一樣,在查詢的時候動態(tài)調(diào)整,拼的是均攤情況下的復(fù)雜度。

 public string Get(int num)
 {
     var blockIndex = 0;
     var arrIndex = 0;

     var temp = blockLinkNode;

     while (temp != null)
     {
         //判斷是否在該區(qū)間內(nèi)
         if (temp.list.Count > 0 && num >= temp.list[0] && num <= temp.list[temp.list.Count - 1])
         {
             arrIndex = temp.list.IndexOf(num);

             return string.Format("當(dāng)前數(shù)據(jù)在第{0}塊中的{1}個位置", blockIndex, arrIndex);
         }

         blockIndex = blockIndex + 1;
         temp = temp.next;
     }

     return string.Empty;
 }

好了,CURD 都分析好了,到這里大家應(yīng)該對 塊狀鏈表有個大概的認(rèn)識了吧,這個代碼是我下午抽閑寫的,沒有仔細(xì)測試,最后是總的代碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
             List<int> list = new List<int>() { 8959, 30290, 18854, 7418, 28749, 17313, 5877, 27208, 15771, 4335 };
 
             //list.Clear();
 
             //List<int> list = new List<int>();
 
             //for (int i = 0; i < 100; i++)
             //{
             //    var num = new Random((int)DateTime.Now.Ticks).Next(0, short.MaxValue);
 
             //    System.Threading.Thread.Sleep(1);
 
             //    list.Add(num);
             //}
 
 
             BlockLinkList blockList = new BlockLinkList();
 
             foreach (var item in list)
             {
                 blockList.Add(item);
             }
 
             //var b = blockList.IsExist(333);
             //blockList.GetCount();
 
             Console.WriteLine(blockList.Get(27208));
 
 
             #region MyRegion
             隨機(jī)刪除150個元素
             //for (int i = 0; i < 5000; i++)
             //{
             //    var rand = new Random((int)DateTime.Now.Ticks).Next(0, list.Count);
 
             //    System.Threading.Thread.Sleep(2);
 
             //    Console.WriteLine("\n**************************************\n當(dāng)前要刪除元素:{0}", list[rand]);
 
             //    blockList.Remove(list[rand]);
 
             //    Console.WriteLine("\n\n");
 
             //    if (blockList.GetCount() == 0)
             //    {
             //        Console.Read();
             //        return;
             //    }
             //} 
             #endregion
 
             Console.Read();
         }
     }
 
     public class BlockLinkList
     {
         BlockLinkNode blockLinkNode = null;
 
         public BlockLinkList()
         {
             //初始化節(jié)點
             blockLinkNode = new BlockLinkNode()
             {
                 list = new List<int>(),
                 next = null,
                 prev = null
             };
         }
 
         /// <summary>
         /// 定義塊狀鏈表的總長度
         /// </summary>
         private int total;
 
         public class BlockLinkNode
         {
             /// <summary>
             /// 指向前一個節(jié)點的指針
             /// </summary>
             public BlockLinkNode prev;
 
             /// <summary>
             /// 指向后一個節(jié)點的指針
             /// </summary>
             public BlockLinkNode next;
 
             /// <summary>
             /// 鏈表中的數(shù)組
             /// </summary>
             public List<int> list;
         }

         /// <summary>
         /// 判斷指定元素是否存在
         /// </summary>
         /// <param name="num"></param>
         /// <returns></returns>
         public bool IsExist(int num)
         {
             var isExist = false;
 
             var temp = blockLinkNode;
 
             while (temp != null)
             {
                 //判斷是否在該區(qū)間內(nèi)
                 if (temp.list.Count > 0 && num >= temp.list[0] && num <= temp.list[temp.list.Count - 1])
                 {
                     isExist = temp.list.IndexOf(num) > 0 ? true : false;
 
                     return isExist;
                 }
 
                 temp = temp.next;
             }
 
             return isExist;
         }
 
         public string Get(int num)
         {
             var blockIndex = 0;
             var arrIndex = 0;
 
             var temp = blockLinkNode;
 
             while (temp != null)
             {
                 //判斷是否在該區(qū)間內(nèi)
                 if (temp.list.Count > 0 && num >= temp.list[0] && num <= temp.list[temp.list.Count - 1])
                 {
                     arrIndex = temp.list.IndexOf(num);
 
                     return string.Format("當(dāng)前數(shù)據(jù)在第{0}塊中的{1}個位置", blockIndex, arrIndex);
                 }
 
                 blockIndex = blockIndex + 1;
                 temp = temp.next;
             }
 
             return string.Empty;
         }
 
         /// <summary>
         /// 將元素加入到塊狀鏈表中
         /// </summary>
         /// <param name="num"></param>
         public BlockLinkNode Add(int num)
         {
             return Add(blockLinkNode, num);
         }
 
         /// <summary>
         /// 添加元素只會進(jìn)行塊狀鏈表的分裂
         /// </summary>
         /// <param name="node"></param>
         /// <param name="num"></param>
         /// <returns></returns>
         private BlockLinkNode Add(BlockLinkNode node, int num)
         {
             if (node == null)
             {
                 return node;
             }
             else
             {
                 /*
                  *  第一步:找到指定的節(jié)點
                  */
                 if (node.list.Count == 0)
                 {
                     node.list.Add(num);
 
                     total = total + 1;
 
                     return node;
                 }
 
                 //下一步:再比較是否應(yīng)該分裂塊
                 var blockLen = (int)Math.Ceiling(Math.Sqrt(total)) * 2;
 
                 //如果該節(jié)點的數(shù)組的最后位置值大于插入值,則此時我們找到了鏈表的插入節(jié)點,
                 //或者該節(jié)點的next=null,說明是最后一個節(jié)點,此時也要判斷是否要裂開
                 if (node.list[node.list.Count - 1] > num || node.next == null)
                 {
                     node.list.Add(num);
 
                     //最后進(jìn)行排序下,當(dāng)然可以用插入排序解決,O(N)搞定
                     node.list = node.list.OrderBy(i => i).ToList();
 
                     //如果該數(shù)組里面的個數(shù)大于2*blockLen,說明已經(jīng)過大了,此時需要對半分裂
                     if (node.list.Count > blockLen)
                     {
                         //先將數(shù)據(jù)插入到數(shù)據(jù)庫
                         var mid = node.list.Count / 2;
 
                         //分裂處的前段部分
                         var firstList = new List<int>();
 
                         //分裂后的后段部分
                         var lastList = new List<int>();
 
                         //可以在插入點處分裂,也可以對半分裂(這里對半分裂)
                         firstList.AddRange(node.list.Take(mid));
                         lastList.AddRange(node.list.Skip(mid).Take(node.list.Count - mid));
 
 
                         //開始分裂節(jié)點,需要新開辟一個新節(jié)點
                         var nNode = new BlockLinkNode();
 
                         nNode.list = lastList;
                         nNode.next = node.next;
                         nNode.prev = node;
 
                         //改變當(dāng)前節(jié)點的next和list
                         node.list = firstList;
                         node.next = nNode;
                     }
 
                     total = total + 1;
 
                     return node;
                 }
 
                 return Add(node.next, num);
             }
         }
 
         /// <summary>
         /// 從塊狀鏈表中移除元素
         /// </summary>
         /// <param name="num"></param>
         /// <returns></returns>
         public BlockLinkNode Remove(int num)
         {
             return Remove(blockLinkNode, num);
         }
 
         /// <summary>
         /// 從塊狀鏈表中移除元素,涉及到合并
         /// </summary>
         /// <param name="node"></param>
         /// <param name="num"></param>
         /// <returns></returns>
         private BlockLinkNode Remove(BlockLinkNode node, int num)
         {
             if (node == null)
             {
                 return node;
             }
             else
             {
                 //第一步: 判斷刪除元素是否在該節(jié)點內(nèi)
                 if (node.list.Count > 0 && num >= node.list[0] && num <= node.list[node.list.Count - 1])
                 {
                     //定義改節(jié)點的目的在于防止remove方法假刪除的情況發(fā)生
                     var prevcount = node.list.Count;
 
                     node.list.Remove(num);
 
                     total = total - (prevcount - node.list.Count);
 
                     //下一步: 判斷是否需要合并節(jié)點
                     var blockLen = (int)Math.Ceiling(Math.Sqrt(total) / 2);
 
                     //如果當(dāng)前節(jié)點的數(shù)組個數(shù)小于 blocklen的話,那么此時改節(jié)點需要和后一個節(jié)點進(jìn)行合并
                     //如果該節(jié)點時尾節(jié)點,則放棄合并
                     if (node.list.Count < blockLen)
                     {
                         if (node.next != null)
                         {
                             node.list.AddRange(node.next.list);
 
                             //如果下一個節(jié)點的下一個節(jié)點不為null,則將下下個節(jié)點的prev賦值
                             if (node.next.next != null)
                                 node.next.next.prev = node;
 
                             node.next = node.next.next;
                         }
                         else
                         {
                             //最后一個節(jié)點不需要合并,如果list=0,則直接剔除該節(jié)點
                             if (node.list.Count == 0)
                             {
                                 if (node.prev != null)
                                     node.prev.next = null;
 
                                 node = null;
                             }
                         }
                     }
 
                     return node;
                 }

                 return Remove(node.next, num);
             }
         }
 
         /// <summary>
         /// 獲取塊狀鏈表中的所有個數(shù)
         /// </summary>
         /// <returns></returns>
         public int GetCount()
         {
             int count = 0;
 
             var temp = blockLinkNode;
 
             Console.Write("各節(jié)點數(shù)據(jù)個數(shù)為:");
 
             while (temp != null)
             {
                 count += temp.list.Count;
 
                 Console.Write(temp.list.Count + ",");
 
                 temp = temp.next;
             }
 
             Console.WriteLine("總共有:{0} 個元素", count);
 
             return count;
         }
     }
 }

到此這篇關(guān)于C#實現(xiàn)塊狀鏈表的項目實踐的文章就介紹到這了,更多相關(guān)C# 塊狀鏈表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C# 線性插值的實現(xiàn)示例

    C# 線性插值的實現(xiàn)示例

    線性插值是針對一維數(shù)據(jù)的插值方法,本文主要介紹了C# 線性插值的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • LZW數(shù)據(jù)壓縮算法的原理分析

    LZW數(shù)據(jù)壓縮算法的原理分析

    我希望通過本文的介紹,能給那些目前不太了解lzw算法和該算法在gif圖像中應(yīng)用,但渴望了解它的人一些啟發(fā)和幫助。拋磚引玉而已,更希望兄弟們提出寶貴的意見。
    2016-06-06
  • 深入解析C#中的交錯數(shù)組與隱式類型的數(shù)組

    深入解析C#中的交錯數(shù)組與隱式類型的數(shù)組

    這篇文章主要介紹了深入解析C#中的交錯數(shù)組與隱式類型的數(shù)組,隱式類型的數(shù)組通常與匿名類型以及對象初始值設(shè)定項和集合初始值設(shè)定項一起使用,需要的朋友可以參考下
    2016-01-01
  • c#獲取兩個特定字符之間的內(nèi)容并輸出的方法

    c#獲取兩個特定字符之間的內(nèi)容并輸出的方法

    今天小編就為大家分享一篇c#獲取兩個特定字符之間的內(nèi)容并輸出的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • 利用C#編寫掃雷游戲(附源碼)

    利用C#編寫掃雷游戲(附源碼)

    掃雷游戲相信不用給大家過多介紹,大家基本都玩過,下面這篇文章主要給大家介紹了關(guān)于如何利用C#編寫掃雷游戲的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2019-01-01
  • C# Winform 讓整個窗口都可以拖動

    C# Winform 讓整個窗口都可以拖動

    Windows 的 API 果然強(qiáng)大啊.以前要實現(xiàn)全窗口拖動, 要寫鼠標(biāo)按下和抬起事件, 很是麻煩, 偶爾還會出現(xiàn) BUG
    2011-05-05
  • 詳解c#與js的rsa加密互通

    詳解c#與js的rsa加密互通

    這篇文章主要介紹了詳解c#與js的rsa加密互通,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • C# API中模型與它們的接口設(shè)計詳解

    C# API中模型與它們的接口設(shè)計詳解

    這篇文章主要給大家介紹了關(guān)于C# API中模型與它們的接口設(shè)計的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-06-06
  • c#獲取存儲過程返回值示例分享

    c#獲取存儲過程返回值示例分享

    這篇文章主要介紹了C#獲取存儲過程返回值的方法,大家參考使用吧
    2014-01-01
  • C#使用FolderBrowserDialog類實現(xiàn)選擇打開文件夾方法詳解

    C#使用FolderBrowserDialog類實現(xiàn)選擇打開文件夾方法詳解

    這篇文章主要介紹了C#選擇文件夾/打開文件夾/瀏覽文件夾等代碼方法,大家參考使用
    2013-11-11

最新評論

靖安县| 连城县| 邵武市| 河南省| 通城县| 沙雅县| 隆林| 安阳县| 汶上县| 西乌珠穆沁旗| 敦煌市| 太白县| 长武县| 贵溪市| 如皋市| 忻州市| 揭东县| 双辽市| 曲靖市| 许昌县| 吉木萨尔县| 壶关县| 湖南省| 邳州市| 资中县| 迁安市| 黎川县| 呈贡县| 阿巴嘎旗| 云浮市| 呼图壁县| 子长县| 梅河口市| 噶尔县| 义乌市| 雷山县| 藁城市| 奉贤区| 安丘市| 越西县| 顺义区|