5
\$\开始组\$

简介

这篇文章不会介绍跳过列表的实际机制。相反,我在这里得到的只是将跳过列表转换为时髦的ASCII艺术的工具。例如,单元测试打印:

+-+                         +-+                         | |------------------------>| |                         +-+                         +-+                         |                           |                          V伏+-+            +-+          +-+               +-+       | |----------->| |--------->| |-------------->| |       +-+            +-+          +-+               +-+       |              |            |                 |        V V V V+-+  +-+  +-+  +-+  +----+  +-+  +---------+  +-+  +-+  ||->|0 |->|1 |->|2 |->|3000 |->|4 |->|5\n6\n\n7 |->|6 |->|7|+-+  +-+  +-+  +-+  +----+  +-+  +---------+  +-+  +-+

代码

com.github.coderodde.util.公司。SkipList.java:

包com.github.coderodde.util;导入java.util。阵列;导入java.util。HashMap;导入java.util。地图;导入java.util。物体;导入java.util。随机;公共最终类SkipList<K extends Comparable<?超级K>>{静态最终类节点<K>{公钥;公共节点<K>next;节点(K键,节点<K>下一个){this.key=密钥;this.next=下一个;}@覆盖public int hashCode(){return Objects.hashCode(key);}@覆盖公共布尔值等于(对象o){return Objects.equals(((Node<K>)o).key,this.key);}}静态最终类索引<K>{节点<K>节点;指数<K>下降;指数<K>右;索引(节点<K>节点,索引<K>向下,索引<K>向右){this.node=节点;this.down=向下;this.right=右;}}指数<K>头;int大小;@覆盖公共字符串toString(){return new ToStringConverter().convert();}private final类ToStringConverter{私有int级别;private char[][]charMatrix;private final Map<Node<K>,Integer>columnIndexMap=new HashMap();ToString转换器(){this.levels=获取级别();}字符串转换(){charMatrix=getCharacterMatrix();applyNodeChain();for(int l=0;l<levels;l++){应用IndexChainImpl(l);}return convertMatrixToString();}私有索引<K>getStartIndex(int级){指数<K>目标=头;while(级别-->0){target=目标向下;}返回目标;}私有void setBox(int x,int y){charMatrix[y-1][x-1]=“+”;charMatrix[y-1][x]=“-”;charMatrix[y-1][x+1]=“+”;charMatrix[y][x-1]=“|”;charMatrix[y][x+1]=“|”;charMatrix[y+1][x-1]=“+”;charMatrix[y+1][x]=“-”;charMatrix[y+1][x+1]=“+”;}private void applyIndexChainImpl(int级别){索引<K>索引=getStartIndex(级别);索引<K>next=Index.right;int startRowIndex=级别*5;while(索引!=空){//打印方框:int x=columnIndexMap.get(index.node);setBox(x,startRowIndex+1);//将箭头打印到节点:charMatrix[startRowIndex+3][x]=“|”;charMatrix[startRowIndex+4][x]=“V”;if(下一个!=空){//打印右边的箭头:int arrowLength=columnIndexMap.get(next.node)-columnIndexMap.get(index.node)- 4;int xx=columnIndexMap.get(index.node)+2;for(int i=0;i<箭头长度;i++){charMatrix[startRowIndex+1][xx++]='-';}charMatrix[startRowIndex+1][xx]=“>”;next=next.right;}index=索引右侧;}}私有void applyNodeChain(){int startRowIndex=级别*5;int startColIndex=0;for(节点<K>n=head.Node;n!=null;n=n.next){columnIndexMap.put(n,startColIndex+1);字符串节点内容=对象.toString(n.key==空?“”:n.key).replaceAll(“\n”,“\\\\n”);int nodeContentLength=nodeContent.length();charMatrix[startRowIndex][startColIndex]=“+”;charMatrix[startRowIndex+1][startColIndex]=“|”;charMatrix[startRowIndex+2][startColIndex]=“+”;startColIndex++;for(int i=0;i<nodeContentLength;i++){charMatrix[startRowIndex][startColIndex]=“-”;charMatrix[startRowIndex+1][startColIndex]=nodeContent.charAt(i);charMatrix[startRowIndex+2][startColIndex]=“-”;startColIndex++;}charMatrix[startRowIndex][startColIndex]=“+”;charMatrix[startRowIndex+1][startColIndex]=“|”;charMatrix[startRowIndex+2][startColIndex]=“+”;startColIndex++;if(n.next!=空){charMatrix[startRowIndex+1][startColIndex++]=“-”;charMatrix[startRowIndex+1][startColIndex++]='>';}}}私有字符串convertMatrixToString(){StringBuilder sb=新建StringBuilder(charMatrix.length*(charMatrix[0].length+1);for(char[]行:charMatrix){for(字符ch:row){某人附加(ch);}sb.append(“\n”);}将某人返回字符串();}私有int getLevels(){int级别=0;Index<K>Index=SkipList.this.head;while(索引!=空){级别++;索引=index.down;}回报水平;}私有字符[][]getCharacterMatrix(){int height=getCharMatrixHeight();int width=获取CharMatrixWidth();char[][]charMatrix=新字符[height][width];for(char[]行:charMatrix){Arrays.fill(行,“”);}返回charMatrix;}私有int getCharMatrixHeight(){返回5*级+3;}私有int getCharMatrixWidth(){int totalTextLength=0;节点<K>节点=head.Node;while(节点!=空){totalTextLength+=4;//计数框边框和箭头。字符串节点文本=node.key==空?" " : node.key.toString();nodeText=nodeText.replaceAll(“\n”,“\\\\n”);totalTextLength+=节点文本长度();节点=node.next;}return totalTextLength;}}}

com.github.coderodde.util.公司。SkipListTest.java:

包com.github.coderodde.util;导入com.github.coderodde.util。SkipList(跳过列表)。索引;导入com.github.coderodde.util。SkipList(跳过列表)。节点;导入组织junit。测试;公共类SkipListTest{@测试公共无效测试1(){SkipList<String>sl=getSkipList1();System.out.println(“打印测试:”);System.out.println(sl);}私有静态SkipList<String>getSkipList1(){SkipList();sl.size=8;节点<String>nx=新节点<>(null,null);节点<String>n0=新节点<>(null,null);节点<String>n1=新节点<>(null,null);节点<String>n2=新节点<>(null,null);节点<String>n3=新节点<>(null,null);节点<String>n4=新节点<>(null,null);节点<String>n5=新节点<>(null,null);节点<String>n6=新节点<>(null,null);节点<String>n7=新节点<>(null,null);n0.key=“0”;n1.key=“1”;n2.key=“2”;n3.键=“3000”;n4.key=“4”;n5.key=“5\n6\n\n7”;n6.key=“6”;n7.键=“7”;nx.next=n0;n0.next=n1;n1.next=n2;n2.next=n3;n3.next=n4;n4.next=n5;n5.下一个=n6;n6.next=n7;n7.next=空;索引<String>il10=新索引<>(null,null,null);索引<String>il11=新索引<>(null,null,null);索引<String>il20=新索引<>(null,null,null);索引<String>il21=新索引<>(null,null,null);索引<String>il22=新索引<>(null,null,null);索引<String>il23=新索引<>(null,null,null);//顶部索引层:il10向下=il20;il10.node=nx;il10.right=il11;il11向下=il22;il11.node=n4;il11.right=空;//底部索引层:il20.node=nx;il20.down=空;il20.right=il21;il21.node=n2;il21.down=空;il21.right=il22;il22.node=n4;il22.down=空;il22.right=il23;il23.node=n6;il23.down=空;il23.right=空;sl.head=il10;返回sl;}}

评论请求

和往常一样,我希望收到任何关于如何使我的代码变得更好的评论。

\$\端组\$
2
  • 2
    \$\开始组\$ 我看不到任何真实的测试(通过/失败)跳过列表测试-setup-execute-verify序列的“验证”步骤在哪里? \$\端组\$ 评论 5月24日10:16
  • \$\开始组\$ @TobySpeight我的坏蛋。我应该把它放在main()中。 \$\端组\$
    – 共电极
    评论 5月24日10:24

2个答案2

重置为默认值
7
\$\开始组\$

“显然”没有漂亮的字符串格式属于跳过列表数据结构。这只是一项严重违反责任原则的行为。问题是如何将内部跳过列表结构公开给外部格式化程序?

考虑从提供调试方法跳过列表它接受调试/跟踪接口作为参数跳过列表转储列表中所有节点和值的信息。然后调试接口实现对数据执行它需要的任何操作。

字符数组似乎是一个具有绘制方框和箭头方法的独立组件的候选者。

\$\端组\$
7
\$\开始组\$

SkipList中自动发现的缺陷:

  • 未使用的导入语句导入java.util。随机;.
  • 等于应该检查其参数的类。
  • 未选中的转换:对象到`SkipList。节点。
  • 领域水平可能是最终的。

等号不需要使用对象等式。实际上,这会递归地调用节点等于如果我没有搞错(无止境循环?)。

对的:

@覆盖公共布尔值等于(对象o){return this==o//启发式优化(?)。&&o节点n//null的实例将产生false。&&Objects.equals(key,n.key);}

对于那些没有预料到n个作为的别名声明类型为节点。它是安全演员的缩写节点.

您绝对不应该在外部创建SkipList的组件(这里是SkipListTest)。然后,您就不需要公开节点和索引,并用参数化它们。事实上这三个Ks不同,其中两个不可比较。更好私有静态类节点{(我可以想象没有静止的也是。)

所以你可能需要一个private final List<Node>nodes=new ArrayList();在里面跳过列表.

图形的定义可以通过索引号来完成,也可以通过JSON或XML来完成。可能是一些小型DSL:

节点:{nx:{key:null,next:“n0”},n0:{键:“0”,下一个:“n1”},n1:{键:“1”,下一个;“n2”},...}

这允许/需要检查所有组件的有效性。

最后但并非最不重要的一点:您可以使用Unicode及其方框图字符.正如您所知,甚至建议现在用UTF-8编码java源代码,这样您就可以编写'┐'用于右上角。

\$\端组\$
2
  • 1
    \$\开始组\$ @radarbob我认为这是对他的直接侮辱。人们可以投票选择多个答案,而我恰好来得更早,因此比其他人更快地获得曝光率。我认为你对这个网站为什么存在以及它是如何工作的有一个严重的误解。 \$\端组\$ 评论 5月25日9:24
  • \$\开始组\$ @托本·普科宁谢谢:你的回答是值得的。事实上,任何解决方案都会从多种输入中受益。 \$\端组\$ 评论 5月25日22:15

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.