【问题标题】:Make an int search(Object o) method for a stack that uses nodes为使用节点的堆栈创建一个 int search(Object o) 方法
【发布时间】:2021-01-25 15:51:50
【问题描述】:

我正在尝试创建一个使用通用节点类的通用堆栈和队列类。它有empty()pop()peek()push()search() 方法。我知道有一个内置的Stack 类和堆栈search 方法,但我们必须使用Node 类来实现。

我不确定如何制作search 方法。 search 方法应该返回距堆栈顶部最近的事件的堆栈顶部的距离。最上面的项目被认为在距离 1 处;下一项在距离 2 处;等等

我的课程如下:

import java.io.*; 
import java.util.*;

public class MyStack<E> implements StackInterface<E>
{
    private Node<E> head;
    private int nodeCount;

    public static void main(String args[]) {
    }
    
    public E peek() {
        return this.head.getData();
    }
   
    public E pop() {
        E item;
        item = head.getData();
        head = head.getNext();
        nodeCount--;
        return item;
    }
    
    public boolean empty() {
        if (head==null) {
            return true; 
        } else {
            return false;
        }
    }
   
    public void push(E data) {
        Node<E> head = new Node<E>(data);
        nodeCount++;
    }
   
    public int search(Object o) {
        // todo
    }
}

public class Node<E>
{
    E data;
    Node<E> next;
    // getters and setters  
    public Node(E data) 
    { 
        this.data = data; 
        this.next = null; 
    } 
    public E getData() {
        return data;
    }
    public void setData(E data) {
        this.data = data;
    }
    public Node<E> getNext() {
        return next;
    }
    public void setNext(Node<E> next) {
        this.next = next;
    }
}

public class MyQueue<E> implements QueueInterface<E>
{
    private Node<E> head;
    private int nodeCount;
    Node<E> rear;
    public MyQueue() 
    { 
        this.head = this.rear = null; 
    } 
    
    public void add(E item){
        Node<E> temp = new Node<E>(item);
        if (this.rear == null) { 
            this.head = this.rear = temp; 
            return; 
        }  
        this.rear.next = temp; 
        this.rear = temp; 
    }
    
    public E peek(){
        return this.head.getData();
    }
    
    public E remove(){ 
        E element = head.getData();
        Node<E> temp = this.head;
        this.head = this.head.getNext();
        nodeCount--;
        return element;
    }
}

在根据第一条评论处理它之后,我有这个:

public int search(Object o){
    int count=0;
    Node<E> current = new Node<E> (head.getData());
    while(current.getData() != o){
        current.getNext();
        count++;
    }
    
    return count;
}

它没有任何错误,但我无法判断它是否真的正常工作。这看起来正确吗?

【问题讨论】:

  • current 开头head 并调用current=current.getNext() 直到current.getData() 等于您正在寻找的东西。数一数你这样做的次数。
  • 那么 current 会是一个新节点吗?
  • 不应该是public int search(E element)吗?
  • @NomadMaker Java 的Stack#search 的签名是public synchronized int search(Object o)。因此,我认为问题中写的是正确的。

标签: java search linked-list stack nodes


【解决方案1】:

它需要以下改进,

  1. 搜索方法应具有“E”类型的参数。所以,签名应该看起来像public int search(E element)
  2. 从 1 而不是 0 开始计数。正如您所提到的,最上面的项目被认为距离 1 处
  3. 用head初始化current,因为创建一个数据值为head(new node(head.getData()))的新节点会创建一个数据与head节点相同的独立节点;并且 while 将仅针对头节点运行,因为 current.getNext() 将始终为空。 Node&lt;E&gt; current = head 将创建另一个指向头部的引用变量。
  4. 在条件中使用 if( !current.getData().equals(element.getData())) ) 而不是 !=
  5. 如果使用您自己的类作为数据类型,请不要忘记重写 equals 方法。
  6. current.getNext(); 更改为current = current.getNext();

【讨论】:

    【解决方案2】:

    您在使用其他方法时遇到问题。关注top == null。要计算search(),您只需遍历元素并找到所需值的位置:

    public class MyStack<E> {
    
        private Node<E> top;
        private int size;
    
        public void push(E val) {
            Node<E> node = new Node<>(val);
            node.next = top;
            top = node;
            size++;
        }
    
        public E element() {
            return top == null ? null : top.val;
        }
    
        public E pop() {
            if (top == null)
                return null;
    
            E val = top.val;
            top = top.next;
            size--;
            return val;
        }
    
        public boolean empty() {
            return size == 0;
        }
    
        public int search(E val) {
            int res = 1;
            Node<E> node = top;
    
            while (node != null && node.val != val) {
                node = node.next;
                res++;
            }
    
            return node == null ? -1 : res;
        }
    
        private static final class Node<E> {
    
            private final E val;
            private Node<E> next;
    
            public Node(E val) {
                this.val = val;
            }
    
        }
    }
    

    【讨论】:

    • 您的search 签名与java.util.Stack#search 不兼容。 != 运算符通过引用比较对象,这很可能不是这里想要的。想象一下堆栈包含一个字符串...您需要传递该字符串的相同 instance 才能获得匹配。因此,当要搜索的参数不是null 本身时,equals() 更合适。 headtopdataval 的重命名不是必需的,并且可能会使 OP 感到困惑,在 MyStack 中嵌套 Node 并删除 getter 和 setter 也是如此。
    • @Matt java.util.Stack不推荐使用。在Java 中正确实现stack data structureDequeue&lt;&gt; stack = new LinkedList&lt;&gt;()
    • 我不推荐使用Stack,但只是引用了它,因为这个原因:OP 想要使用search 方法构建自己的堆栈实现,其合同与该方法匹配Stack 之一。 Deque 不提供 search 方法。我同意,应该优先使用Deque 接口及其实现而不是Stack。但是,我强烈反对 LinkedList 是它的 正确 实现,尤其是当您需要并发时。针对不同的用例有多种实现方式,应适当使用。
    • @Matt 我不是在谈论并发。
    【解决方案3】:

    我假设您的 MyStack 类应该与 Java 提供的 Stack 类兼容,正如您在问题中提到的那样。这意味着您的签名public int search(Object o)java.util.Stack#search 的签名匹配(synchronised 除外)。

    要使用Node 类实现search 方法,我们需要遍历堆栈并返回第一个(最上面的)匹配项的索引。首先,将head 分配给一个局部变量(current)。然后你可以创建一个循环,最后你 current.getNext() 来获取下一个元素。如果下一个元素是null,则停止,因为我们已经到达堆栈的末尾。在循环中,您要么向上计数 index,要么在当前元素的数据与参数 o 匹配时返回此索引。

    评估需要能够处理您的论点onull 值。因此,您需要首先检查null 并相应地调整您的逻辑。当onull 时,对current.getData() 执行null-检查。如果o 不是null,则检查current.getData() 是否等于oequals()

    这是一个工作示例: (与java.util.Stack#search 兼容)

    public int search(Object o) {
        int index = 1;
        Node<E> current = head;
        while (current != null) {
            if (o == null) {
                if (current.getData() == null) {
                    return index;
                }
            } else {
                if (o.equals(current.getData())) {
                    return index;
                }
            }
            current = current.getNext();
            index++;
        }
        return -1; // nothing found
    }
    

    要对此进行测试,您可以使用 JUnit 编写一个简单的单元测试,如下所示:

    @Test
    public void testMyStackSearch() {
        // initialize
        final MyStack<String> stack = new MyStack<>();
        stack.push("e5");
        stack.push("e4");
        stack.push(null);
        stack.push("e2");
        stack.push("e1");
    
        // test (explicitly creating a new String instance)
        assertEquals(5, stack.search(new String("e5")));
        assertEquals(3, stack.search(null));
        assertEquals(2, stack.search(new String("e2")));
        assertEquals(1, stack.search(new String("e1")));
        assertEquals(-1, stack.search("X"));
    }
    

    由于您已经有一个参考实现,您可以将MyStack 替换为Stack (java.util.Stack) 并查看您的断言是否正确。如果运行成功,请将其改回MyStack 并查看您的实现是否正确


    注意:我不建议在 Java 中实际使用 Stack 实现。在这里,它只是作为java.util.Stack#search 方法的参考实现。 Deque 接口及其实现提供了一组更完整和一致的 LIFO 堆栈操作,应优先使用 Stack

    【讨论】:

      猜你喜欢
      • 2018-03-31
      • 1970-01-01
      • 2021-06-01
      • 2013-05-03
      • 2016-08-26
      • 2019-08-01
      • 1970-01-01
      • 2018-03-17
      • 2019-06-13
      相关资源
      最近更新 更多