大型网站建设推荐网站平台建设成本
大型网站建设推荐,网站平台建设成本,厦门网站建设68,商标设计网图大全在数据结构的世界里#xff0c;我们会认识各种各样的数据结构#xff0c;每一种数据结构都能解决相应领域的问题#xff0c;当然每个数据结构#xff0c;有他的优点#xff0c;必然就有它的缺点#xff0c;那么如何创造一种数据结构来将某两种数据结构进行扬长避短#…在数据结构的世界里我们会认识各种各样的数据结构每一种数据结构都能解决相应领域的问题当然每个数据结构有他的优点必然就有它的缺点那么如何创造一种数据结构来将某两种数据结构进行扬长避短那就非常完美了。这样的数据结构也有很多比如双端队列还有就是今天讲的块状链表。 我们都知道 数组 具有 O(1)的查询时间O(N)的删除O(N)的插入。。。 链表 具有 O(N)的查询时间O(1)的删除O(1)的插入。。。 那么现在我们就有想法了何不让“链表”和“数组”结合起来来一起均摊 CURD 的时间做法将数组进行分块然后用指针相连接比如我有 N100 个元素那么最理想情况下我就可以将数组分成 x10 段每段 b10 个元素排好序那么我可以用 √N 的时间找到段因为段中的元素是已经排好序的所以可以用 lg√N 的时间找到段中的元素那么最理想的复杂度为 √Nlg√N≈√N。。。 下面我们看看怎么具体使用
一、结构定义
这个比较简单我们在每个链表节点中定义一个 头指针尾指针和一个数组节点。 public class BlockLinkNode{/// summary/// 指向前一个节点的指针/// /summarypublic BlockLinkNode prev;/// summary/// 指向后一个节点的指针/// /summarypublic BlockLinkNode next;/// summary/// 链表中的数组/// /summarypublic Listint list;}二、插入
刚才也说了每个链表节点的数据是一个数组块那么问题来了我们是根据什么将数组切开呢总不能将所有的数据都放在一个链表的节点吧那就退化成数组了在理想的情况下为了保持 √N 的数组个数所以我们定了一个界限 2√N当链表中的节点数组的个数超过 2√N 的时候当下次插入数据的时候我们有两种做法
在元素的数组插入处将当前数组切开插入元素处之前为一个链表节点插入元素后为一个链表节点。将元素插入数组后将数组从中间位置切开。 /// summary/// 添加元素只会进行块状链表的分裂/// /summary/// param namenode/param/// param namenum/param/// returns/returnsprivate BlockLinkNode Add(BlockLinkNode node, int num){if (node null){return node;}else{/** 第一步找到指定的节点*/if (node.list.Count 0){node.list.Add(num);total total 1;return node;}//下一步再比较是否应该分裂块var blockLen (int)Math.Ceiling(Math.Sqrt(total)) * 2;//如果该节点的数组的最后位置值大于插入值则此时我们找到了链表的插入节点//或者该节点的nextnull说明是最后一个节点此时也要判断是否要裂开if (node.list[node.list.Count - 1] num || node.next null){node.list.Add(num);//最后进行排序下当然可以用插入排序解决O(N)搞定node.list node.list.OrderBy(i i).ToList();//如果该数组里面的个数大于2*blockLen说明已经过大了此时需要对半分裂if (node.list.Count blockLen){//先将数据插入到数据库var mid node.list.Count / 2;//分裂处的前段部分var firstList new Listint();//分裂后的后段部分var lastList new Listint();//可以在插入点处分裂也可以对半分裂(这里对半分裂)firstList.AddRange(node.list.Take(mid));lastList.AddRange(node.list.Skip(mid).Take(node.list.Count - mid));//开始分裂节点需要新开辟一个新节点var nNode new BlockLinkNode();nNode.list lastList;nNode.next node.next;nNode.prev node;//改变当前节点的next和listnode.list firstList;node.next nNode;}total total 1;return node;}return Add(node.next, num);}}二、删除
跟插入道理一样既然有裂开就有合并同样也定义了一个界限值 √N /2 当链表数组节点的数组个数小于这个界限值的时候需要将此节点和后面的链表节点进行合并。 /// summary/// 从块状链表中移除元素,涉及到合并/// /summary/// param namenode/param/// param namenum/param/// returns/returnsprivate BlockLinkNode Remove(BlockLinkNode node, int num){if (node null){return node;}else{//第一步 判断删除元素是否在该节点内if (node.list.Count 0 num node.list[0] num node.list[node.list.Count - 1]){//定义改节点的目的在于防止remove方法假删除的情况发生var prevcount node.list.Count;node.list.Remove(num);total total - (prevcount - node.list.Count);//下一步 判断是否需要合并节点var blockLen (int)Math.Ceiling(Math.Sqrt(total) / 2);//如果当前节点的数组个数小于 blocklen的话那么此时改节点需要和后一个节点进行合并//如果该节点时尾节点则放弃合并if (node.list.Count blockLen){if (node.next ! null){node.list.AddRange(node.next.list);//如果下一个节点的下一个节点不为null则将下下个节点的prev赋值if (node.next.next ! null)node.next.next.prev node;node.next node.next.next;}else{//最后一个节点不需要合并如果list0则直接剔除该节点if (node.list.Count 0){if (node.prev ! null)node.prev.next null;node null;}}}return node;}return Remove(node.next, num);}}三、查询
在理想的情况下我们都控制在 √N然后就可以用 √N 的时间找到区块lg√N 的时间找到区块中的指定值当然也有人在查询的时候做 链表的合并和分裂这个就有点像伸展树一样在查询的时候动态调整拼的是均摊情况下的复杂度。 public string Get(int num){var blockIndex 0;var arrIndex 0;var temp blockLinkNode;while (temp ! null){//判断是否在该区间内if (temp.list.Count 0 num temp.list[0] num temp.list[temp.list.Count - 1]){arrIndex temp.list.IndexOf(num);return string.Format(当前数据在第{0}块中的{1}个位置, blockIndex, arrIndex);}blockIndex blockIndex 1;temp temp.next;}return string.Empty;}好了CURD 都分析好了到这里大家应该对 块状链表有个大概的认识了吧这个代码是我下午抽闲写的没有仔细测试最后是总的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication3
{class Program{static void Main(string[] args){Listint list new Listint() { 8959, 30290, 18854, 7418, 28749, 17313, 5877, 27208, 15771, 4335 };//list.Clear();//Listint list new Listint();//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随机删除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当前要删除元素{0}, list[rand]);// blockList.Remove(list[rand]);// Console.WriteLine(\n\n);// if (blockList.GetCount() 0)// {// Console.Read();// return;// }//} #endregionConsole.Read();}}public class BlockLinkList{BlockLinkNode blockLinkNode null;public BlockLinkList(){//初始化节点blockLinkNode new BlockLinkNode(){list new Listint(),next null,prev null};}/// summary/// 定义块状链表的总长度/// /summaryprivate int total;public class BlockLinkNode{/// summary/// 指向前一个节点的指针/// /summarypublic BlockLinkNode prev;/// summary/// 指向后一个节点的指针/// /summarypublic BlockLinkNode next;/// summary/// 链表中的数组/// /summarypublic Listint list;}/// summary/// 判断指定元素是否存在/// /summary/// param namenum/param/// returns/returnspublic bool IsExist(int num){var isExist false;var temp blockLinkNode;while (temp ! null){//判断是否在该区间内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){//判断是否在该区间内if (temp.list.Count 0 num temp.list[0] num temp.list[temp.list.Count - 1]){arrIndex temp.list.IndexOf(num);return string.Format(当前数据在第{0}块中的{1}个位置, blockIndex, arrIndex);}blockIndex blockIndex 1;temp temp.next;}return string.Empty;}/// summary/// 将元素加入到块状链表中/// /summary/// param namenum/parampublic BlockLinkNode Add(int num){return Add(blockLinkNode, num);}/// summary/// 添加元素只会进行块状链表的分裂/// /summary/// param namenode/param/// param namenum/param/// returns/returnsprivate BlockLinkNode Add(BlockLinkNode node, int num){if (node null){return node;}else{/** 第一步找到指定的节点*/if (node.list.Count 0){node.list.Add(num);total total 1;return node;}//下一步再比较是否应该分裂块var blockLen (int)Math.Ceiling(Math.Sqrt(total)) * 2;//如果该节点的数组的最后位置值大于插入值则此时我们找到了链表的插入节点//或者该节点的nextnull说明是最后一个节点此时也要判断是否要裂开if (node.list[node.list.Count - 1] num || node.next null){node.list.Add(num);//最后进行排序下当然可以用插入排序解决O(N)搞定node.list node.list.OrderBy(i i).ToList();//如果该数组里面的个数大于2*blockLen说明已经过大了此时需要对半分裂if (node.list.Count blockLen){//先将数据插入到数据库var mid node.list.Count / 2;//分裂处的前段部分var firstList new Listint();//分裂后的后段部分var lastList new Listint();//可以在插入点处分裂也可以对半分裂(这里对半分裂)firstList.AddRange(node.list.Take(mid));lastList.AddRange(node.list.Skip(mid).Take(node.list.Count - mid));//开始分裂节点需要新开辟一个新节点var nNode new BlockLinkNode();nNode.list lastList;nNode.next node.next;nNode.prev node;//改变当前节点的next和listnode.list firstList;node.next nNode;}total total 1;return node;}return Add(node.next, num);}}/// summary/// 从块状链表中移除元素/// /summary/// param namenum/param/// returns/returnspublic BlockLinkNode Remove(int num){return Remove(blockLinkNode, num);}/// summary/// 从块状链表中移除元素,涉及到合并/// /summary/// param namenode/param/// param namenum/param/// returns/returnsprivate BlockLinkNode Remove(BlockLinkNode node, int num){if (node null){return node;}else{//第一步 判断删除元素是否在该节点内if (node.list.Count 0 num node.list[0] num node.list[node.list.Count - 1]){//定义改节点的目的在于防止remove方法假删除的情况发生var prevcount node.list.Count;node.list.Remove(num);total total - (prevcount - node.list.Count);//下一步 判断是否需要合并节点var blockLen (int)Math.Ceiling(Math.Sqrt(total) / 2);//如果当前节点的数组个数小于 blocklen的话那么此时改节点需要和后一个节点进行合并//如果该节点时尾节点则放弃合并if (node.list.Count blockLen){if (node.next ! null){node.list.AddRange(node.next.list);//如果下一个节点的下一个节点不为null则将下下个节点的prev赋值if (node.next.next ! null)node.next.next.prev node;node.next node.next.next;}else{//最后一个节点不需要合并如果list0则直接剔除该节点if (node.list.Count 0){if (node.prev ! null)node.prev.next null;node null;}}}return node;}return Remove(node.next, num);}}/// summary/// 获取块状链表中的所有个数/// /summary/// returns/returnspublic int GetCount(){int count 0;var temp blockLinkNode;Console.Write(各节点数据个数为);while (temp ! null){count temp.list.Count;Console.Write(temp.list.Count ,);temp temp.next;}Console.WriteLine(总共有:{0} 个元素, count);return count;}}}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/90207.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!