【问题标题】:Construct a model of an electric circuit in java用java构建电路模型
【发布时间】:2014-01-08 07:52:57
【问题描述】:

我最近参加了 Java 开发人员职位的面试。我被分配了一个任务:思考一种用 Java 表示电路(如下图所示电路)的好方法。

电路是逻辑门 XOR、AND、OR 等的组合。每个门都有两个输入端口和一个输出端口。每个输出都连接到另一个门的输入,该输入一直到更高的门(如图所示)。使系统简单,不允许循环(尽管现实生活中的电路可以有它们)。 我被要求考虑使用以下准则在 Java 中表示此模型的好方法:

  1. 我得到了一个电路和一个应该提供给其输入的值列表。
  2. 我需要创建一个模型来用 Java 表示电路,即,我需要定义可用于表示电路的类和 API。
  3. 根据输入值和门的连接方式,我需要计算所表示的电路会产生的输出。
  4. 我需要考虑一种方法来表示板,使用抽象类或接口,并展示对模型的理解(如果需要使用模式设计)。

我选择将系统设计为一棵树,面试官告诉我这是一个不错的选择。然后我构建这些类:

节点

public class gate_node {
    gate_node right_c,left_c;
    Oprtator op;
    int value;
    int right_v,left_v;
    public gate_node(gate_node right,gate_node left,Oprtator op){
        this.left_c=left;
        this.right_c=right;
        this.op=op;
        right_v=left_v=0;
    }
    
}

public class tree {
    gate_node head;

    tree(gate_node head) {
        this.head = head;
    }

    void go_right() {
        head = head.right_c;
    }

    void go_left() {
        head = head.left_c;
    }

    static int arr[] = { 0, 0, 1, 0 };
    static int counter=0;

    static int compute(gate_node head) {

        if ((head.left_c == null) && (head.right_c == null))
        {
            int ret=(head.op.calc(arr[counter], arr[counter+1]));
            counter++;
            counter++;
            return ret;
        }
        return (head.op.calc(compute(head.left_c), compute(head.right_c)));

    }

    public static void main(String[] args) {
        tree t = new tree(new gate_node(null, null, new and()));
        t.head.left_c = new gate_node(null, null, new and());
        t.head.right_c = new gate_node(null, null, new or());
        System.out.println(tree.compute(t.head));
    }
}

经营者类:

public abstract class Oprtator {
        abstract int calc(int x, int y);
}

或门:

public class or extends Oprtator {
        public int calc(int x, int y){
            return (x|y);
        }
}

在上面的代码中,我将板子实现为具有当前头部的树(可以向下到左/右子节点)。每个节点有 2 个子节点(也是节点类型)、2 个条目(0/1)、一个值和一个运算符(抽象类,可以通过 OR/AND.. 扩展)。

我使用了一个计数器和一个数组将值插入到树的适当叶子中(如代码中所述)。

它有效,但我仍然觉得我的面试官想要更多东西。我的代码是否正确?有没有人有更好的方式来表示这个电路板以及如何提供良好的输出(在复杂性或使用从一个类到另一个类的更好连接、设计模式等方面?)

【问题讨论】:

  • 好吧,我会先花一些时间考虑输入表示,以及如何从文件中读取该表示。然后有几种不同的方法可以在内部构造数据并模拟操作。
  • (这是基于 38 年前在 FORTRAN 中实际完成的。)
  • 他们可能一直在寻找模拟,而不是逻辑模型,涉及时序模型、侦听器(可能)等。
  • @EdStaub 时序模型需要未提供的输入,相当于组件数据表,而不仅仅是逻辑操作的名称。
  • 我在阅读代码时最初的想法是,这家伙习惯于用 Java 以外的东西进行编程。类应该以大写字母开头,并且应该使用 camelCase 而不是下划线。加上您拼写错误的运算符,加上静态方法,所以不是特别面向对象。当有人从一种语言转换为另一种语言时,您总是会看到这样的代码。如果这份工作有很多竞争,那可能就足以错过。

标签: java algorithm design-patterns representation


【解决方案1】:

这不是一个“完美”的答案,但您可以使用几个类来保存逻辑连接/评估,然后递归地评估电路来解决这个问题。

创建一个基类LogicalNode 并为其提供要管理的输入列表。给它一个基类函数来评估所有输入并返回一个输出。这在派生类中被覆盖。每种类型的节点(INPUT、NOT、AND、OR)都有一个具有特殊“ComputOutput”覆盖版本的派生类。如果您在输出节点计算输出,它应该递归树,计算输入的所有输入等,直到它到达“INPUT”节点,这些节点是系统的固定/逻辑输入。

您可以相当快地创建新类型(参见代码)。这里的 cmets 不多,但应该有点不言自明。

类似这样的东西(在 C# 中):

public class LogicalNode
    {
        private List<LogicalNode> _inputs = new List<LogicalNode>();
        private String _name = "Not Set";


        public override string ToString()
        {
            return String.Format("Node {0}", _name);
        }

        public void Reset()
        {
            _inputs.Clear();
        }

        public void SetName(String name)
        {
            _name = name;
        }

        protected List<LogicalNode> GetInputs()
        {
            return _inputs;
        }

        public void AddInput(LogicalNode node)
        {
            _inputs.Add(node);
        }

        protected virtual bool ComputeOutputInternal()
        {
            return false;
        }

        public bool ComputeOutput()
        {
           // Console.WriteLine("Computing output on {0}.", _name);
            return ComputeOutputInternal();
        }
    }

    public class LogicalInput : LogicalNode
    {
        private bool _state = true;

        public void SetState(bool state)
        {
            _state = state;
        }

        public bool GetState() { return _state; }

        protected override bool ComputeOutputInternal()
        {
            return _state;
        }
    }

    public class LogicalAND : LogicalNode
    {
        protected override bool ComputeOutputInternal()
        {
            List<LogicalNode> inputs = GetInputs();
            bool result = true;
            for (Int32 idx = 0; idx < inputs.Count && result; idx++)
            {
                result = result && inputs[idx].ComputeOutput();
            }
            return result;
        }
    }

    public class LogicalOR : LogicalNode
    {
        protected override bool ComputeOutputInternal()
        {
            List<LogicalNode> inputs = GetInputs();
            bool result = false;
            for (Int32 idx = 0; idx < inputs.Count; idx++)
            {
                result = inputs[idx].ComputeOutput();
                if (result)
                    // If we get one true, that is enough.
                    break;
            }
            return result;
        }
    }

    public class LogicalNOT : LogicalNode
    {
        protected override bool ComputeOutputInternal()
        {
            List<LogicalNode> inputs = GetInputs();
            if (inputs.Count > 0)
            {   // NOTE:  This is not an optimal design for
                // handling distinct different kinds of circuits.
                //
                // It it demonstrative only!!!!
                return !inputs[0].ComputeOutput();
            }
            return false;
        }

然后(快速)测试它:

static void Main(string[] args)
        {
            // The test circuit
            // !((A&&B) || C)
            // A    B   C   Out
            // 1    1   1   0 
            // 1    1   0   0
            // 1    0   1   0
            // 1    0   0   1
            // 0    1   1   0
            // 0    1   0   1
            // 0    0   1   0
            // 0    0   0   1
            // 
            //
            //
            /*     -------     -------
             * A - |     |     |     |
             *     | AND |-----|     |    -------
             * B - | (D) |     |     |    |     |
             *     -------     | OR  |----| NOT |----
             *                 | (E) |    | (F) |
             * C --------------|     |    |     |
             *                 -------    -------
             */

            LogicalInput A = new LogicalInput();
            LogicalInput B = new LogicalInput();
            LogicalInput C = new LogicalInput();
            LogicalAND   D = new LogicalAND();
            LogicalOR    E = new LogicalOR();
            LogicalNOT   F = new LogicalNOT();

            A.SetName("A");
            B.SetName("B");
            C.SetName("C");
            D.SetName("D");
            E.SetName("E");
            F.SetName("F");

            D.AddInput(A);
            D.AddInput(B);

            E.AddInput(D);
            E.AddInput(C);

            F.AddInput(E);

            // Truth Table
            bool[] states = new bool[]{ true, false };
            for(int idxA = 0; idxA < 2; idxA++)
            {
                for(int idxB = 0; idxB < 2; idxB++)
                {
                    for(int idxC = 0; idxC < 2; idxC++)
                    {
                        A.SetState(states[idxA]);
                        B.SetState(states[idxB]);
                        C.SetState(states[idxC]);

                        bool result = F.ComputeOutput();

                        Console.WriteLine("A = {0}, B = {1}, C = {2}, Output = {3}",
                            A.GetState(), B.GetState(), C.GetState(), result.ToString());

                    }
                }
            }
        }
    }

有输出:

A = True, B = True, C = True, Output = False
A = True, B = True, C = False, Output = False
A = True, B = False, C = True, Output = False
A = True, B = False, C = False, Output = True
A = False, B = True, C = True, Output = False
A = False, B = True, C = False, Output = True
A = False, B = False, C = True, Output = False
A = False, B = False, C = False, Output = True

这有帮助吗?

【讨论】:

  • 谢谢。我仍在查看您的代码,但对于我来说这是一种新的思维方式,可以解决这个特定的建模问题,再次感谢!
  • 这是一个有点“灵感”的解决方案。在阅读了你的帖子后,我把它放在一起......我不得不尝试一下,以确保它有意义。它可能无法解决您需要处理数值解决方案的模拟,但对于逻辑,它只是一种点击。如果您想要完整的 VS 解决方案,请告诉我。
【解决方案2】:

虽然我显然不能确切地说出面试官在寻找什么,但如果我正在面试你,我可能会敦促你让你的 compute 方法成为你的 gate_node 类的非静态成员。这样,您的网络就不必在一侧或另一侧“平衡”(它们可以更深,有更多输入)。

换句话说,看看你的计算代码,我不相信它适用于一般电路。

可能类似于以下内容(gate_node):

int compute() {
    /* The following use of a static sInputCounter assumes that the static/global 
     * input array is ordered from left to right, irrespective of "depth".  */

    final int left = (null != left_c ?  left_c.compute()  :  sInput[sInputCounter++]);
    final int right = (null != right_c ?  right_c.compute()  :  sInput[sInputCounter++]);

    return op.calc(left, right);
}

这样,“树”可以只由头/根 gate_node 表示(尽管您可能仍然想要像您的 tree 类这样的类——为了避免混淆,我可能称它为“网络”,使用用于构造树、设置输入等的静态方法)并通过调用 head.compute() 触发网络评估。

当然,您仍然面临从一些外部规范构建网络的重要问题。我想面试官的另一个问题可能是你的解决方案中没有很好地说明这个方面。 (我这里也不行,对不起。)

【讨论】:

  • 是的,面试官可能会认出一个有实际倾向的人,因为他们首先会担心如何指定输入。
  • 谢谢你,我认为你是对的。我将它改为非静态函数。快速浏览一下我的代码 - 您是否发现任何其他问题?我问它是因为我在那里有第二次面试,我担心再次被问到试图改善这个建模问题,我想来准备
猜你喜欢
  • 2020-10-14
  • 1970-01-01
  • 2020-02-13
  • 2012-06-19
  • 2018-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多