简体   繁体   English

递归词搜索算法

[英]Recursive word search algorithm

It's time for me to write your grandmother her first Java word search program. 是时候让我为您的祖母写她的第一个Java单词搜索程序了。 But instead of having her do all the work by looking for words within the letter grid, a recursive function 4WaySearch does it for her! 但是,不是让她通过在字母网格内查找单词来完成所有工作,而是递归函数4WaySearch替她做到了!

The only problem is: 唯一的问题是:

I am finding it hard to conceptualize a recursive algorithm that builds every possible letter combination when starting at once place in the grid. 我发现很难概念化一种递归算法,该算法在网格中一次开始时会构建每种可能的字母组合。

Here's code I already have written that I deem a big step in the right direction: 这是我已经编写的代码,我认为朝正确的方向迈出了一大步:

/* 
* This is the method that calls itself repeatedly to wander it's way
* through the grid using a 4 way pattern,
* creating every possibly letter combination and checking it against a
* dictionary. If the word is found in the dictionary, it gets added to a
* collection of found words.
* 
* Here an example of a 3x3 grid with the valid words of RATZ and BRATZ, but
* the word CATZ isn't valid. (the C is not tangent to the A).
* 
* CXY
* RAT
* BCZ
*
* @param row Current row position of cursor
* @param col Current column position of cursor
*/
private void 4WaySearch(int row, int col) {

    // is cursor outside grid boundaries?
    if (row < 0 || row > ROWS - 1 || col < 0 || col > COLS - 1)
        return; 

    GridEntry<Character> entry = getGridEntry(row, col);

    // has it been visited?
    if (entry.hasBreadCrumb())
        return; 

    // build current word
    currentWord += entry.getElement(); // returns character

    // if dictionay has the word add to found words list
    if (dictionary.contains(currentWord))
        foundWords.add(currentWord);

    // add a mark to know we visited
    entry.toggleCrumb();

    // THIS CANT BE RIGHT
    4WaySearch(row, col + 1);   // check right
    4WaySearch(row + 1, col);   // check bottom
    4WaySearch(row, col - 1);   // check left
    4WaySearch(row - 1, col);   // check top

    // unmark visited
    entry.toggleCrumb();

    // strip last character
    if (currentWord.length() != 0)
        currentWord = currentWord.substring(
        0, 
        (currentWord.length() > 1) ? 
            currentWord.length() - 1 : 
            currentWord.length()
        );
}

In my head, I visualize the search algorithm just like a recursive tree traveral algorithm, but each node (entry in this case) has 4 children (tangent entrys), and the leaf nodes are the boundaries of the grid. 在我的脑海中,我像递归树遍历算法一样可视化搜索算法,但是每个节点(在这种情况下为条目)都有4个子节点(切线条目),叶节点是网格的边界。

Also, the location of the cursor upon initial entry into the function is determined by a simple for loop psuedocoded here: 同样,在最初进入函数时,游标的位置由一个简单的for循环伪代码确定,该伪代码在此处:

for (int r = 0; r < ROWS; r++)
  for (int c = 0; r < COLS; c++)
    4WaySearch(r,c);
  end for;
end for;

I have been thinking about this for a while now, and trying different approaches... but I still cant seem to wrap my mind around it and make it work. 我已经考虑了一段时间,并尝试了不同的方法...但是我似乎仍然无法将其束之高阁并使之发挥作用。 Can someone show me the light? 有人可以给我看光吗? (For the sake of me and your grandmother! :D) (为了我和你祖母!:D)

So what you need to do is first establish the grid. 因此,您需要做的是首先建立网格。 In this instance you have elected for 3x3 . 在这种情况下,您选择了3x3。 What you need is a way to keep track of all the valid points on the grid, might I recommend an object called Point that takes two int s as its constructor. 您需要的是一种跟踪网格上所有有效点的方法,我可能建议您使用一个名为Point的对象,该对象采用两个int作为其构造函数。 The next thing you need is a class that is composed of a Point and a char , this will enable us to see what letter is available at each Point . 接下来需要做的是一个由Pointchar组成的类,这将使我们能够看到每个Point可用的字母。

Now that we have our data structure in place we need to keep track of valid moves for the game. 现在我们已经有了数据结构,我们需要跟踪游戏的有效动作。 For instance if I am at position 3,3 (the bottom right corner, or 2,2 if you are zero based) I would need to realize that the only valid moves I have are up or left. 例如,如果我处于位置3,3(右下角,或者如果您从零开始,则为2,2),则需要意识到我仅有的有效动作是向上或向左。 The way to determine this is to keep a Set of Point s that tell me all the places I have visited, this will enable the recursive algorithm to terminate. 确定这个问题的方法是保持一个SetPoint s表示告诉我,我到过的所有地方,这将使递归算法终止。

Some pseudocode for the recursion that may help 递归的一些伪代码可能会有所帮助

if(!validMovesRemaining)  
     return
else  
    removeValidPosition(pointToRemove);  
    captureLetter(composedObject);
    recurse(pointsRemaining);

What I would do is build a Tree structure. 我要做的是建立一个Tree结构。 Where a Node is defined like so 像这样定义节点的地方

public class Node {
    private String data;
    private int row,col;
    private Node parent;
    public Node(Node parent,int row,int col) {
        this.parent = parent;
        this.col = col;
        this.row = row;
    }
    public boolean hasParent(int row, int col) {
        Node current = this;
        while((current=current.parent)!=null) {
            if(current.row == row && current.col==col)
                return true;
        }
        return false;
    }

    public String toString() {
        Node current = this;
        StringBuffer sb = new StringBuffer();
        do {
            sb.append(current.data);
        }while((current = current.parent)!=null);
        return sb.reverse().toString();
    }
}

Each time you have a new starting place you want to create a new root node for the tree 每次您有一个新的起点时,都想为树创建一个新的根节点。

for (int r = 0; r < ROWS; r++)
  for (int c = 0; r < COLS; c++)
    4WaySearch(new Node(null,r,c);   //it is the root and has no parent
  end for;
end for;

And then you want to build the tree as you go 然后,您想随手搭建树

private void FourWaySearch(Node c) {
    if (c.row < 0 || c.row > ROWS - 1 || c.col < 0 || c.col > COLS - 1 || c.hasParent(c.row,c.col))
        return; 
    else {  

        c.data = grid[c.row][c.col];  //get the string value from the word search grid
        if(dictionary.contains(c.toString()))
            foundWords.add(c.toString());
        FourWaySearch(new Node(c,c.row-1,c.col));
        FourWaySearch(new Node(c,c.row,c.col-1));
        FourWaySearch(new Node(c,c.row+1,c.col));
        FourWaySearch(new Node(c,c.row,c.col+1));
    }
}

This might not be the best way to do it but to me it seems simple and easy to follow. 这可能不是最好的方法,但对我来说似乎很容易遵循。

I think a tree is the way to go, but not in the way other answers seem to be using it. 我认为一棵树是要走的路,但不是其他答案似乎正在使用它。 What I would do would be to build a parse tree of the words you're looking for (from the dictionary) -- each letter is a node, with 26 possible children, one for each letter of the alphabet (check for null children before recursing), and a flag saying whether it's a complete word. 我要做的是(从字典中)构建一个您要查找的单词的解析树-每个字母是一个节点,有26个可能的子代,每个字母对应一个(检查之前是否null子代)递归),以及一个标语,说明该单词是否完整。 Check each direction, see if you can move in that direction, and move accordingly. 检查每个方向,看是否可以沿该方向移动,并相应地移动。

I was going to say that the hard part would be building the tree and it shouldn't be done recursively, but I just had another thought. 我要说的是,最困难的部分将是构建树,并且不应该递归地完成它,但是我只是有另外一个想法。 The best way to build the tree is also recursive. 构造树的最佳方法也是递归的。

This is obviously just an overview, but hopefully enough to give you a start. 显然,这只是概述,但希望足以为您提供一个开始。 If you get stuck again, comment and I'll see if I can push you more in the right direction. 如果您再次遇到困难,请发表评论,我会看看是否可以在正确的方向上进一步推动您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM