写给自己的JAVA工程师之路-链表

来源:互联网 发布:如何提高唱歌水平 知乎 编辑:程序博客网 时间:2024/06/07 04:19

1.1 认识链表

链表 = 可变长的对象数组,属于动态对象数组的范畴。

传统对象数组:

作用:对象数组可以保存一组对象方便开发。
缺点:对象数组的长度固定,而且数据的修改,删除,增加处理麻烦。

正因为如此,如果想要让其编写出便于维护的代码,那么就需要实现一个动态对象数组,于是可以使用链表完成。

1.2 实现链表

问题:保存数据为了方便使用Object;
   
           数据本身不包含有先后的逻辑关系,所以将数据封装在一个Node类,负责关系的维护。

class Node{//表示定义的节点private Object data;//表示保存的数据private Node next;//保存下一个节点public Node(Object data){//有数据才可以保存节点this.data=data;}public void setNext(Node next){//设置节点this.next=next;}public Node getNext(){//取得节点return this.next;}}
链表在整个实现过程最关键的就是Node类,Node类要保存数据与下一个节点。

虽然以上的代码已经实现了链的形式,但是实际上Node类对用户没有。所以还需要一个类,这个类可以负责所有Node的关系匹配,而用户只需通过这个类保存数据,取得数据即可。

于是代码变成:

class Node{//表示定义的节点private Object data;//表示保存的数据private Node next;//保存下一个节点public Node(Object data){//有数据才可以保存节点this.data=data;}public void setNext(Node next){//设置节点this.next=next;}public Node getNext(){//取得节点return this.next;}public Object getData(){//取得数据return this.data;}//第一次调用:this=Link.root//第二次调用:this=Link.root.next//第三次调用:this=Link.root.next.nextpublic void addNode(Node newNode){if(this.next==null){//当前节点后没有节点this.next=newNode;}else{//当前节点后有节点this.next.addNode(newNode);}}public void printNode(){System.out.println(this.data);if(this.next!=null){this.next.printNode();}}}class Link{//表示一个链表操作类,利用此类来隐藏Node的节点匹配private Node root;//根元素public void add(Object obj){//向链表里追加数据Node newNode = new Node(obj);//将数据包装为Node对象,这样才可以进行先后关系排列//没有根节点时if(this.root==null){this.root=newNode;//第一个节点作为根节点}else{//根节点存在,交由Node处理this.root.addNode(newNode);}}public void print(){//输出全部数据this.root.printNode();}}

链表在整个实现过程最关键的就是Node类,Node类要保存数据与下一个节点。

2.1 开发可用链表

以上的代码只能够说是基本的链表形式,可是如何才能实现一个好的链表呢?

1.让Node类只为Link类服务,但是又不让其他类访问。
2.如果要开发程序,那么一定要创建出自己的操作标准,那么一旦说到标准,就应该使用到接口完成。

于是代码结构变成:
interface Link{}class LinkImpl implements Link{private class Node{//使用私有内部类,防止外部使用此类private Object data;//表示保存的数据private Node next;//保存下一个节点public Node(Object data){//有数据才可以保存节点this.data=data;}}//*******************************************private Node root;//根节点}
在随后完善的代码过程之中,除了功能的实现之外,实际上也属于接口功能的完善。

2.2 完整链表实现

interface Link{public void add(Object data);//数据增加public int size();//获得链表大小public boolean isEmpty();//判断是否为空集合public boolean contains(Object data);//判断是否存在指定元素public Object get(int index);//根据索引取得数据public void set(int index,Object obj);//修改数据public void remove(Object data);//数据删除public void clear();//清空链表public Object[] toArray();//对象数组转换}class LinkImpl implements Link{private class Node{//使用私有内部类,防止外部使用此类private Object data;//表示保存的数据private Node next;//保存下一个节点public Node(Object data){//有数据才可以保存节点this.data=data;}//第一次调用:this=LinkImpl.root//第二次调用:this=LinkImpl.root.next//第三次调用:this=LinkImpl.root.next.nextpublic void addNode(Node newNode){if(this.next==null){//当前节点后没有节点this.next=newNode;}else{//当前节点后有节点this.next.addNode(newNode);}}public boolean containsNode(Object data){if(this.data.equals(data)){//该节点数据束符合于查找数据return true;}else {//继续向下查找if(this.next!=null){//当前节点还有下一个节点return this.next.containsNode(data);}else {return false;}}}public Object getNode(int index){//传递索引序号if(LinkImpl.this.foot++==index){//当前的索引为要查找的索引return this.data;//返回节点对象}else {return this.next.getNode(index);}}public void setNode(int index,Object data){if(LinkImpl.this.foot++==index){//当前的索引为要查找的索引this.data=data;//重新保存数据}else {this.next.setNode(index, data);}}public void removeNode(Node pre,Object data){if(this.data.equals(data)){//为当前要删除的数据pre.next=this.next;}else {pre.next.removeNode(this, data);}}public void toArrayNode(){LinkImpl.this.retData[LinkImpl.this.foot++]=this.data;if(this.next!=null){this.next.toArrayNode();}}}//*******************************************private Node root;//根节点private int count=0;//纪律链表大小private int foot=0;//操作的索引脚标private Object retData[]=null;public void add(Object data){if(data==null){//没有增加的数据return ;//结束调用}Node newNode = new Node(data);//将数据包装为Node对象,这样才可以进行先后关系排列//没有根节点时if(this.root==null){this.root=newNode;//第一个节点作为根节点}else{//根节点存在,交由Node处理this.root.addNode(newNode);}this.count++;//添加成功 ,链表长度+1}public int size(){//获得链表大小return this.count;}public boolean isEmpty(){return this.root==null;}public boolean contains(Object data) {if(this.root==null){return false;}return this.root.containsNode(data); }public Object get(int index) {if(index>=this.count){//索引不存在return null;}this.foot=0;//查询之前进行初始化return this.root.getNode(index);}public void set(int index, Object obj) {if(index>=this.count){//索引不存在return ;}this.foot=0;//查询之前进行初始化this.root.setNode(index, obj);}public void remove(Object data) {if(this.contains(data)){//数据如果存在即删除if(this.root.data.equals(data)){//跟元素为要删除的元素this.root=this.root.next;}else {//不是根元素this.root.next.removeNode(this.root, data);}}count--;}public void clear() {this.root=null;this.count=0;System.gc();//内存清空}public Object[] toArray() {if(this.root==null){return null;}this.retData=new Object[this.count];this.foot=0;this.root.toArrayNode();return this.retData;}}
以上的设计都没有考虑过性能问题,只是简单的单向链表,重点是方法的理解与实现



 
原创粉丝点击