实例讲解——单向链表(2)
深入链表的操作
将使用内部类,完成链表的操作!
一,链表的改进
之前已经实现了简单的单向链表,但是因为要用手工去处理各个节点的关系,这样肯定不行。
所以此处最好将节点的操作进行封装。这样用户操作就很方便了。
假设现在的节点操作有以下几种:增加数据,查找数据,删除数据。
特别强调的是,如果要删除节点的话,直接修改上一个节点就可以。
增加节点:就是在节点最后进行增加。
查找节点:就是依次递归的方式查找。
删除节点:就是改变引用传递地址。
在程序开发中,必须考虑两种情况:
1)第一次执行的时候,第一次执行的时候,其根节点不存在,则需要将第一个数据设置成为根节点。
class Link{ // 链表的完成类 class Node{ // 保存每一个节点,此处为了方便直接定义成内部类 private String data ; // 保存节点的内容 private Node next ; // 保存下一个节点 public Node(String data){ this.data = data ; // 通过构造方法设置节点内容 } public void add(Node newNode){ // 将节点加入到合适的位置 if(this.next==null){ // 如果下一个节点为空,则把新节点设置在next的位置上 this.next = newNode ; }else{ // 如果不为空,则表示后面还有其他节点,这里不能添加,则需要向下继续找next为空的节点,自动完成在链表的最后添加。 this.next.add(newNode) ; } } public void print(){ System.out.print(this.data + "\t") ; // 输出节点内容 if(this.next!=null){ // 还有下一个元素,需要继续输出 this.next.print() ; // 下一个节点继续调用print } } public boolean search(String data){ // 内部搜索的方法 if(data.equals(this.data)){ // 判断输入的数据是否和当前节点的数据一致 return true ; }else{ // 向下继续判断 if(this.next!=null){ // 下一个节点如果存在,则继续查找 return this.next.search(data) ; // 返回下一个的查询结果 }else{ return false ; // 如果所有的节点都查询完之后,没有内容相等,则返回false } } } public void delete(Node previous,String data){ if(data.equals(this.data)){ // 找到了匹配的节点 previous.next = this.next ; // 空出当前的节点 }else{ if(this.next!=null){ // 还是存在下一个节点 this.next.delete(this,data) ; // 继续查找 } } } }; private Node root ; // 链表中必然存在一个根节点 public void addNode(String data){ // 增加节点 Node newNode = new Node(data) ; // 定义新的节点 if(this.root==null){ // 没有根节点 this.root = newNode ; // 将第一个节点设置成根节点 }else{ // 不是根节点,放到最后一个节点之后 this.root.add(newNode) ; // 通过Node自动安排此节点放的位置,从根节点开始查找着添加节点。 } } public void printNode(){ // 输出全部的链表内容 if(this.root!=null){ // 如果根元素不为空 this.root.print() ; // 调用Node类中的输出操作 } } public boolean contains(String name){ // 判断元素是否存在 return this.root.search(name) ; // 调用Node类中的查找方法 } public void deleteNode(String data){ // 删除节点 if(this.contains(data)){ // 判断节点是否存在 // 一定要判断此元素现在是不是根元素相等的 if(this.root.data.equals(data)){ // 内容是根节点 this.root = this.root.next ; // 修改根节点,将第一个节点设置成根节点 }else{ this.root.next.delete(root,data) ; // 把下一个节点的前节点和数据一起传入进去,用this.root.next调用方法,是利用在调用方法中利用this当前对象,作为第一个判断是不是等于要删除的节点。 } } } }; public class LinkDemo02{ public static void main(String args[]){ Link l = new Link() ; l.addNode("A") ; // 增加节点 l.addNode("B") ; // 增加节点 l.addNode("C") ; // 增加节点 l.addNode("D") ; // 增加节点 l.addNode("E") ; // 增加节点 System.out.println("======= 删除之前 ========") ; l.printNode() ; // System.out.println(l.contains("X")) ; l.deleteNode("C") ; // 删除节点 l.deleteNode("D") ; // 删除节点 l.deleteNode("A") ; // 删除节点 System.out.println("\n====== 删除之后 =========") ; l.printNode() ; System.out.println("\n查询节点:" + l.contains("B")) ; } };
2)为了查看全部链表,这里定义了一个打印链表的方法。
3)查找节点,肯定是继续使用递归的操作进行查找操作的。
4)完成删除功能,如果要想删除节点,肯定就是改变节点的引用对象的内容。但是在删除前要确保此节点存在。否则无法删除。
5)删除节点要判断是不是根节点,要是根节点的话,需要修改他的下一个为根节点。
6)做删除操作,需要把删除的节点和他前面的节点一起传入删除方法,因为要修改引用对象,必须要前一个节点的存在。
总结
1,这个题把链表本身作为一个外部类。而节点作为内部类。
2,这里用到的知识点包括递归,this的当前对象功能。
3,由于增加节点不知道首节点的位置,所以需要从根节点开始查找,所以用了根节点调用添加方法,然后根据判断下一个节点来视情况添加。
4,本程序实际上就是针对引用的扩展应用。而且在本程序中只是实现了最简单的单向链表功能。