链表是一种非常常见和重要的数据结构,在java里也可以通过引用传递的方式进行实现。
1、基本概念
什么是链表,通俗的可以理解为一辆货车,火车头代表链表表头,后面的每一节车厢表示一个链表的结点,每一个结点除了存储本节点的数据以外,还得带上下一个结点的引用,也就是除了车尾以外的那些车厢,都必须连接后面的一节车厢。
2、链表的实现
要实现链表,我们必须定义一个链表类,在类中还得有一个属性,可以保存下一个节点的引用地址。
每一个节点除了要存储当前节点的数据,还得带上下一个结点的引用地址。
class Node{
private String data; // 节点的数据
private Node next; // 下一个节点的引用地址
public Node(String data){ // 构造函数设置节点内容
this.data = data;
}
public Node getNext() {
return this.next; // 获取下一个节点
}
public void setNext(Node next) {
this.next = next; // 设置下一个节点
}
public String getData(){
return this.data;
}
}
public class LinkDemo {
public static void main(String[] args) {
Node root = new Node("火车头");
Node node1 = new Node("一号车厢");
Node node2 = new Node("二号车厢");
Node node3 = new Node("三号车厢");
root.setNext(node1);
node1.setNext(node2);
node2.setNext(node3);
printNode(root); // 从头开始输出
}
public static void printNode(Node node) {
System.out.print(node.getData()+" -> ");
if(node.getNext()!=null){
printNode(node.getNext()); // 递归调用节点
}
}
}
上述例子中,所有的关系都是用户手动设置,如果想让它真正有意义,我们需要加入一个操作的封装。
2、链表的改进
可以看到,上面的实现的链表需要人工手动去操作节点,一个个添加,一个个处理引用关系,非常繁琐,因此我们应该将对节点的操作进行封装。常见的操作有:增加数据、查找数据、删除数据。
注意:删除数据其实只是改变节点引用地址而已
- 增加节点:在链表最后追加
- 查找节点:递归查找
- 删除节点:修改引用关系
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{ // 如果下一节点非空,则继续向后递归查找
this.next.add(newNode);
}
}
public void print(){
System.out.print(this.data + " -> "); // 输出节点内容
if(this.next!=null){ // 判断是否为最后一个节点,若不是则继续递归调用
this.next.print();
}
}
}
private Node root; // 设置根节点
public void addNode(String data){ // 增加节点
Node newNode = new Node(data); // 定义新的节点
if(this.root==null){ // 如果根节点为空,则设置 newNode 为根节点
this.root = newNode;
}else{ // 如果不是根节点,利用add方法把节点放在合适的位置
this.root.add(newNode);
}
}
public void printNode(){ // 输出链表内容
if(this.root!=null){ // 如果链表根元素不为空
this.root.print(); // 调用Node类中的输出操作
}
}
}
public class LinkDemo2 {
public static void main(String[] args) {
Link link = new Link();
link.addNode("A"); // 增加节点
link.addNode("B");
link.addNode("C");
link.addNode("D");
System.out.println("------------------");
link.printNode();
}
}
2.2 查找节点
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{ // 如果下一节点非空,则继续向后递归查找
this.next.add(newNode);
}
}
public void print(){
System.out.print(this.data + " -> "); // 输出节点内容
if(this.next!=null){ // 判断是否为最后一个节点,若不是则继续递归调用
this.next.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;
}
}
}
}
private Node root; // 设置根节点
public void addNode(String data){ // 增加节点
Node newNode = new Node(data); // 定义新的节点
if(this.root==null){ // 如果根节点为空,则设置 newNode 为根节点
this.root = newNode;
}else{ // 如果不是根节点,利用add方法把节点放在合适的位置
this.root.add(newNode);
}
}
public void printNode(){ // 输出链表内容
if(this.root!=null){ // 如果链表根元素不为空
this.root.print(); // 调用Node类中的输出操作
}
}
public boolean contains(String name){ // 判断元素是否存在
return this.root.search(name);
}
}
public class LinkDemo2 {
public static void main(String[] args) {
Link link = new Link();
link.addNode("A");
link.addNode("B");
link.addNode("C");
link.addNode("D");
System.out.println("------------------");
// link.printNode();
System.out.println(link.contains("X"));
}
}
2.3 删除节点
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{ // 如果下一节点非空,则继续向后递归查找
this.next.add(newNode);
}
}
public void print(){
System.out.print(this.data + " -> "); // 输出节点内容
if(this.next!=null){ // 判断是否为最后一个节点,若不是则继续递归调用
this.next.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;
}
}
}
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){ // 如果根节点为空,则设置 newNode 为根节点
this.root = newNode;
}else{ // 如果不是根节点,利用add方法把节点放在合适的位置
this.root.add(newNode);
}
}
public void printNode(){ // 输出链表内容
if(this.root!=null){ // 如果链表根元素不为空
this.root.print(); // 调用Node类中的输出操作
}
}
public boolean contains(String name){ // 判断元素是否存在
return this.root.search(name);
}
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); // 把下一个节点的前节点和数据传入继续判断
}
}
}
}
public class LinkDemo2 {
public static void main(String[] args) {
Link link = new Link();
link.addNode("A");
link.addNode("B");
link.addNode("C");
link.addNode("D");
System.out.println("--------- 删除之前 ---------");
link.printNode();
// System.out.println(link.contains("X"));
link.deleteNode("C");
link.deleteNode("B");
link.deleteNode("A");
System.out.println();
System.out.println("--------- 删除之后 ---------");
link.printNode();
System.out.println();
System.out.println("查找节点D: " + link.contains("D"));
}
}