Java实验六、链表类及应用

 实验目的:

  1. 进一步掌握Object类的主要特点;
  2. 进一步掌握上转型、下转型的含义;
  3. 掌握equals方法的具体应用;
  4. 掌握开发一个链表类的关键步骤。
  5. 利用链表类实现复杂程序。
  6. 掌握接口的概念和语法,并能够应用于实际。

● 参考学时:2学时

● 基本要求:

  1. 定义实验61.Node类和实验61.LinkedList类,并通过测试类测试上述类的正确性。LinkedList类组合了Node类,Node类与LinkList类之间的关系如图6.1所示。图中空心菱形的含义是LinkedList类聚合(Aggregation)了Node类对象,聚合是组合关系的一种
  2. 注意,Java语言已经提供了一个java.util.LinkedList类,请不要在本实验中导入并使用该类,而是重新定义“实验61.LinkedList

图6-1  Node类和LinkedList类之间的关系

  1. Node类:
  1. 要求Node类拥有如下2个私有属性:
    1. data:用于存放节点的数据。为了能够实现常见数据类型的链表,data类型定义为Object,即可以在链表中保存任何类型的对象。如果要保存int、double等基本数据类型,需要用到Java的自动“装箱”和“拆箱”机制。
    2. next:用于保存本节点的下一个节点的引用。
  1. 要求Node类里有一个构造方法Node(Object data),此外还拥有设置属性和获取属性的getter、setter方法以及简单的toString()方法(该方法将data转换为String并返回该值)。
  1. LinkedList类
  1. 要求LinkedList类拥有1个private属性head,用于存储链表第一个节点的引用。
  2. 要求为LinkedList实现7个public方法,关于这7个方法的要求如表6.1所示。
  3. 实现search()方法和remove()方法时需要用到链表中节点的数据所属类提供的equals()方法,因为这两个方法都涉及到比较链表中某一Node的getData().equals(所要查找的data),而不是getData()= = data

表6.1 LinkList类的方法

编号

方法名称

描述

1

void add(Object data)

将值为data的节点插入到链表尾。

2

boolean remove(Object data)

在链表中删除值为data的节点。若删除成功,返回true;否则,返回false。

3

Node search(Object data)

在链表中查找值为data的节点。若找到,返回该节点的引用,若没找到,返回null。

4

boolean insertAfter(Node previous, Object data)

在引用previous指向的节点后插入一个值为data的节点。若插入成功,返回true;否则,返回false。

5

Node get(int index)

在链表中找第index个节点。若找到,返回第index节点的引用,若找不到,返回null。

6

boolean set(Node node, Object data)

将node引用节点的内容改为data。若修改成功,返回true;否则,返回false。

7

int size()

返回链表长度。

一个初步的具有add方法的LinkedList代码如下:

public class LinkedList {

   private Node head;

   public void add(Object data) {

      Node node=new Node(data);   //创建包含data值的Node节点

      if(head==null)      //链表为空,则当前节点就是第一个节点

         head=node;

      else {      //链表不为空,需要找到最后一个节点

         Node tmp=head;      //利用tmp节点遍历

         while(tmp.getNext()!=null)   //tmp节点不是最后一个节点

            tmp=tmp.getNext();   //tmp指向下一个节点

         //循环结束时tmp为最后一个节点

         tmp.setNext(node);      //把当前节点链接在最后一个节点之后

      }

   }

}

  1. 实验61.Test类(测试类,其中含主方法)
  1. 要求在测试类的主方法中,测试LinkedList类的方法,可按如下步骤执行:

① 调用无参构造方法LinkedList(),创建一个空链表。

② 连续三次调用add()方法,在链表中插入三个Integer对象,如add(1); add(2); add(3)(此处Java自动将1、2、3等int值装箱为Integer对象)。

③ 调用search()方法,查找值为2的节点,将该方法返回的节点的引用赋给Node型变量p;

④ 调用set()方法,将p指向的节点的内容修改为22。

⑤ 调用insertAfter()方法,在p指向的节点后面插入一个值为23的节点。

⑥ 调用remove()方法,删除值为22的节点。

⑦ 调用size()方法,获得链表长度赋给整型变量n。

⑧ 循环n次,每一轮通过调用get(i)方法得到第i个节点的引用,并将其内容输出。

  1. 在“实验61.LinkedList”和“实验61.Node”基础上,实现宠物商店的宠物上架、下架、查询等操作,其中宠物商店中的宠物需要用链表存储。在本程序中,最重要的是定义宠物标准(定义一个宠物接口Pet),进入宠物商店销售的所有宠物(如Cat类、Dog类、Fish类)都需要实现这个标准(即实现接口Pet)。根据以上原则,给出了图6.2所示的类图(图中的虚线三角形箭头表示实现接口,实线普通箭头表示关联(Association)关系)。

图6.2 实验相关的类、接口及其关系

  1. 定义宠物接口实验62.Pet

这个接口是宠物商店可处理的宠物标准。宠物商店并不关心具体的宠物是什么,只关心一点:只要是实现了标准接口的宠物,就可以进入宠物商店,并能够通过宠物商店进行各种操作。宠物接口Pet的定义如下:

package 实验62;

interface Pet {

   public String getName();

   public int getAge();

}

  1. 定义宠物商店类实验62.PetShop

宠物商店所售卖的宠物数量不定,因此要用链表(LinkedList)对象保存多个宠物。同时宠物商店能够售卖的宠物必须是具有宠物特征(比如具有名字和年龄)和行为(比如告知名字或年龄)的一切动物,因此在上架(添加)、卖出(删除)宠物时,接收的参数都应是Pet接口类型。

表6.2 宠物商店类的方法

编号

方法名称

描述

1

void add(Pet pet)

将宠物pet上架,即添加到链表中。

2

boolean delete(Pet pet)

从宠物商店下架宠物pet,即从链表中查找并删除。若删除成功,返回true;否则,返回false。

3

Pet get(int index)

查找第index个宠物。若找到,返回该宠物的引用,若找不到,返回null。

4

int size()

返回宠物总数。

提示:在宠物商店类中,先定义一个LinkedList类变量pets,并实例化。

package 实验62;

import 实验61.*;

public class PetShop { // 一个宠物商店要保存多个宠物信息

   private LinkedList pets = new LinkedList(); //用链表保存宠物信息

   public void add(Pet pet) {       //新宠物上架操作,以接口对象为参数!

      pets.add(pet);

   }

   public boolean delete(Pet pet) {    //宠物下架操作,以接口对象为参数!

      

   }

   public Pet get(int index){

//pets.get()返回Node节点,Node节点的getData()返回Object,该Object就是Pet

      return (Pet)( pets.get(index).getData() );

   }

}

  1. 定义宠物猫子类实验62.Cat

要求Cat类实现接口Pet。要求Cat类有两个私有属性name和age。Cat类中除了getName()和get getAge( ) 方法外,还要求为其实现3个public方法,关于这3个方法的要求如表6.4所示。Cat类的类图如图6.3所示。为了简洁起见,在图6.3所示的Cat类图中省略了getName()方法和getAge( ) 方法。

表6.3 Cat类的方法表

编号

方法名称

描述

1

Cat(String name, int age)

创建Cat类的实例,其名字为name,年龄为age。

2

equals(Object obj)

覆写Object中的equals()方法。判断猫类的两个对象值是否相等。

3

toString()

覆写Object中的方法。返回猫的完整信息。

  1. 定义宠物狗子类实验62.Dog

要求Dog类实现接口Pet。要求Dog类有两个私有属性name和age。Dog类中除了getName()和get getAge( ) 方法外,还要求为其要求实现3个public方法,对这3个方法的要求,与表6.4中对Cat类中方法的要求类似,因此不再赘述。Dog类的类图如图6.4所示。

图6.3  Cat类图                                图6.4  Dog类图

  1. 编写测试类实验62.Test。要求在测试类的主方法中,完成如下动作:

① 定义一个宠物商店类变量shop,并实例化;

② 在宠物商店shop中添加1岁的“波斯猫”;

③ 在宠物商店shop中添加2岁的“橘猫”;

④ 在宠物商店shop中添加1岁的“折耳猫”;

⑤ 在宠物商店shop中添加1岁的“柯基犬”;

⑥ 在宠物商店shop中添加2岁的“波尔多”(注:波尔多是一种狗名字);

⑦ 显示宠物商店shop中所有宠物;

⑧ 删除宠物商店shop中2岁的“橘猫”;

⑨ 显示宠物商店shop中所有宠物;

通过运行结果可以发现,由于本程序是面向接口的编程,所以返回的结果中即包含了Cat类对象,也包含了Dog类对象。

表6.4 链表类测试案例(仅用于编码测试)

编号

测试目的

输入或测试数据

期望结果

1

构造方法

list=new LinkedList()

list.size()返回0;

list.get(0)返回null;

list.search(1)返回null;

list.remove(1)返回false

2

add方法

list.add(1); list.add(2); list.add(3);

list.size()返回3

3

search方法

Node p= list.search(22);

System.out.println(p)显示null

4

search方法

Node p= list.search(2);

System.out.println(p)显示2

5

set方法

list.set(null,"22");

set方法返回false

6

set方法

list.set(p,"22");

System.out.println(p)显示22

7

insertAfter方法

list.insertAfter(p,23);

list.size()返回4

8

insertAfter方法

list.insertAfter(null,23);

insertAfter方法返回null

9

remove方法

list.remove(12)

返回false

10

remove方法

list.remove(22)

返回true

11

get方法

Node p=list.get(0);

System.out.println(p)显示1

12

get方法

Node p= list.get(-1);

System.out.println(p)显示null

13

get方法

Node p= list.get(100);

System.out.println(p)显示null

表6.5  宠物商店测试案例(仅用于编码测试)

编号

测试目的

输入或测试数据

期望结果

1

构造方法

size方法

get方法

delete方法

shop=new PetShop()

shop.size()返回0;

shop.get(0)返回null;

shop.delete(null)返回false

2

add方法

get方法

toString方法

shop.add(new Cat("波斯猫",1));

shop.add(new Cat("橘猫",2));

shop.add(new Cat("折耳猫",1));

shop.add(new Dog("柯基犬",1));

shop.add(new Dog("波尔多",2));

shop.size()返回5

shop.get(0).toString()返回“波斯猫,1岁”

3

delete方法

shop.delete(new Cat("橘猫",1));

返回false,因为商店中只有2岁橘猫,没有1岁橘猫

shop.size()返回5

4

delete方法

shop.delete(new Cat("波斯猫",1));

返回true

shop.size()返回4,因为已经删除了一个波斯猫

代码部分

LinkedList类

package shiyan6;

public class LinkedList {
    private Node head;
    private int size;

    public LinkedList() {
        this.head = null;
        this.size = 0;
    }

    public LinkedList(Node head) {
        this.head = head;
    }

    public void add(Object data) {
        Node node = new Node(data);
        if (this.head == null) {
            this.head = node;
        } else {
            Node temp = this.head;
            if (temp.getNext() != null) {
                temp = temp.getNext();
            }

            temp.setNext(node);
            ++this.size;
        }
    }

    public boolean remove(Object data) {
        Node temp = this.head;
        Node m = this.head;
        if (this.head == null) {
            return false;
        } else if (temp.getData().equals(data)) {
            this.head = temp.getNext();
            --this.size;
            return true;
        } else {
            while (!temp.getData().equals(data) && temp.getNext() != null) {
                m = temp;
                temp = temp.getNext();
            }

            if (!temp.getData().equals(data)) {
                return false;
            } else {
                m.setNext(temp.getNext());
                --this.size;
                return true;
            }
        }
    }

    public Node search(Object date) {
        Node temp = this.head;
        Node result;
        while (true) {
            if (temp.getData().equals(date)) {
                result = temp;
                break;
            }
            temp = temp.getNext();
        }

        return result;
    }

    public boolean inserAfter(Node previous, Object date) {
        Node temp = this.head;
        Node node = new Node(date);

        while (temp.getNext() != null) {
            if (temp.equals(previous)) {
                node.setNext(temp.getNext());
                temp.setNext(node);
                ++this.size;
                return true;
            }
            temp = temp.getNext();
        }
        return false;
    }

    public Node getNode(int index) {
        Node temp = this.head;
        if (this.size >= index && index >= 0 && this.head != null) {
            for (int i = 0; i < index; ++i) {
                temp = temp.getNext();
            }

            return temp;
        } else {
            return null;
        }
    }

    public boolean setNode(Node node, Object date) {
        Node temp = this.head;

        if (!temp.equals(node) && temp.getNext() != null) {
            temp = temp.getNext();
        }

        if (temp.equals(node)) {
            temp.setData(date);
            return true;
        } else {
            return false;
        }
    }

    public int size() {
        return this.head == null ? 0 : this.size + 1;
    }

    public void show() {
        for (Node temp = this.head; temp != null; temp = temp.getNext()) {
            System.out.printf(temp.toString() + "\t  ");
        }
        System.out.println();
    }


}

Node类

package shiyan6;

public class Node {
    private Object data;
    private Node next;

    public Node() {
        this.setData(0);
        this.setNext((Node) null);
    }

    public Node(Object date) {
        this.setData(date);
        this.setNext((Node) null);
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Object getData() {
        return data;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    public Node getNext() {
        return next;
    }

    @Override
    public String toString() {
        return "Node:" + this.getData();
    }
}

TestNode类

package shiyan6;

public class TestNode {
    public TestNode() {
    }
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println("链表大小:" + list.size());
        System.out.println("--------------------------");
        list.show();
        Node p = list.search(2);
        list.setNode(p, 22);
        list.inserAfter(p, 23);
        System.out.println("--------------------------");
        list.show();
        System.out.println("链表大小:" + list.size());
        System.out.println("--------------------------");
        System.out.println(list.remove(1));
        System.out.println(list.remove(23));
        list.show();
    }
}

Pet接口

package shiyan6;

public interface Pet {
    String getName();

    int getAge();
}

PetShop类

package shiyan6;

public class PetShop {
    private LinkedList pets = new LinkedList();

    public PetShop() {
    }

    public void add(Pet pet) {
        this.pets.add(pet);
    }

    public boolean delete(Pet pet) {
        boolean result = this.pets.remove(pet);
        return result;
    }

    public Pet get(int index) {
        Pet p = null;
        if (this.pets.getNode(index) == null) {
            return null;
        } else {
            p = (Pet) ((Pet) this.pets.getNode(index).getData());
            return p;
        }
    }
    public int size() {
        return this.pets.size();
    }
}

Cat类

package shiyan6;

public class Cat implements Pet {
    private String name;
    private int age;

    public Cat() {
        this("无名的猫", 0);
    }

    public Cat(String name, int age) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public String getName() {
        return this.name;
    }

    public boolean equals(Object o) {
        if (!(o instanceof Cat)) {
            return false;
        } else {
            Cat c = (Cat) o;
            return this.getAge() == c.getAge() && this.getName() == c.getName();
        }
    }

    public String toString() {
        return "Cat:{ " + this.getName() + "," + this.getAge() + "岁 }";
    }
}

Dog类

package shiyan6;

public class Dog implements Pet {
    private String name;
    private int age;

    public Dog() {
        this("无名的狗", 1);
    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return this.age;
    }

    public String getName() {
        return this.name;
    }

    public boolean equals(Object o) {
        if (!(o instanceof Dog)) {
            return false;
        } else {
            Dog c = (Dog) o;
            return this.getAge() == c.getAge() && this.getName() == c.getName();
        }
    }

    public String toString() {
        return "Dog: { " + this.getName() + "," + this.getAge() + "岁 }";
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值