如何在简单的有向图中向后计数?

时间:2016-02-25 22:14:11

标签: c#

所以我有这本图表,我正在迭代并打印出来。

public class Books : IBookFinder
{
    private Books(Books next, string book)
    {
        Next = next;
        Book = book;
    }

    public Books Next { get; }
    public string Book { get; }

    public Books Previous(string book)
    {
        return new Books(this, book);
    }

    public static Books Create(string book)
    {
        return new Books(null, book);
    }

    public string FromLeft(Books books, int numberFromLeft)
    {
        for (int i = 1; i < numberFromRight; i++)
        {
            books = books?.Next; //Go through the books and return null if books is null.
        }

        return books.book; //Should probably check for null here as it crashes if the input number is out of book range (something else than 1-4)
    }

    public string FromRight(Books books, int numberFromRight
    {
        //How to implement this bad boy?
    }
}

一切都很好,但我想实现一个方法FromRight,这样我就可以根据数字输入从图中的位置写出书的名称。例如,如果输入&#34; 3&#34;,它应该输出&#34;指环王&#34;。我该怎么做呢?任何提示都非常赞赏。

class Program
{
    static void Main(string[] args)
    {
        var curr = Books
            .Create("Harry Potter")
            .Previous("Lord of the Rings")
            .Previous("Twilight")
            .Previous("Da Vinci Code");

        while (curr != null)
        {
            if (curr.Next != null)
            {
                Console.Write(curr.Book + " --- ");
            }
            else
            {
                Console.WriteLine(curr.Book);
            }
            curr = curr.Next;
        }

        Console.WriteLine("Input number to pick a book");

        var bookNumber = Console.ReadLine();
        int n;

        if (int.TryParse(bookNumber, out n)) //Checking if the input is a #
        {

        }
        else
        {
            Console.WriteLine("Input was not a number!");
        }
        Console.WriteLine(bookNumber);

        Console.ReadLine();
    }
}

更新:

我设法找到了一种方法,而不必制作双重链表,即使这当然可能是解决此问题的最佳方案。

我已经创建了一个帮助函数Count(),它接受列表并计算条目:

    private int Count(Books books)
    {
        int count = 1;
        while (books.Next != null)
        {
            books = books.Next;
            count++;
        }

        return count;
    }

然后我使用此方法的返回值从右侧选择书籍:

    public string FromRight(Books books, int numberFromRight)
    {
        var bookCount = Count(books); //Getting the amount of books.
        for (int i = numberFromRight; i < bookCount; i++)
        {
            books = boos?.Next; 
        }

        return books.Book;
    }

2 个答案:

答案 0 :(得分:2)

由于您要像链接列表一样创建它,要向后移动,您需要创建一个双向链接列表:https://en.wikipedia.org/wiki/Doubly_linked_list

您当前的代码没有上一个节点的代表。将前一个节点设置为当前节点,同时创建下一个节点,然后其迭代就像您最初那样。

迭代直到没有Next,然后打印直到没有上一个。

答案 1 :(得分:1)

单链表只能在一个方向上迭代,所以不可能倒退。

要从左侧获取第n个元素,您只需要进入下一个n次。但要想从右边找出元素,首先需要达到目的。因此,要获得最后一个元素,您需要尽可能经常地去下一个元素。要获得倒数第二个元素,您需要转到结尾并在此之前返回元素。

您可能会看到它的位置:为了从右侧获取第n个元素,您需要在迭代链表时记住最后n个元素。这也意味着在最坏的情况下,当你从左边但是从右边获取第一个元素时,你会记住每个项目。

实现这一点并不困难,你可以使用长度为numberFromRight的列表轻松完成这项工作,但由于你在最后插入并从头开始删除元素,所以你将一直在移动元素。所以你最好使用固定长度的队列。或者您使用带有变量指针的数组,这样可以避免任何移动。 FromRight方法可能如下所示:

public Element FromRight(int numberFromRight)
{
    // increment the offset by one, so that `0` means the last element,
    // and `1` means the one before last, etc.
    numberFromRight++;

    // create an array with `numberFromRight` slots
    Element[] arr = new Element[numberFromRight];

    // add the current item to the array
    arr[0] = this;

    // `i` is the index where to add the next element
    int i = 1 % numberFromRight;

    // iterate through all elements until the very end
    Element current = this;
    while (current.Next != null)
    {
        current = current.Next;

        // add the current element to the array
        arr[i] = current;

        // increment the index by one, overflowing back to the beginning of the array
        i = (i + 1) % numberFromRight;
    }

    // the element at position `i` is the nth element from the right.
    return arr[i];
}

(我选择在没有Books类型的情况下实施此操作,因为您以混乱的方式混合了BooksCustomers而我没有得到它。这适用于任意链接列表。)

如果你发现自己更频繁地访问结尾的元素,你应该考虑使用doubly linked list而不是保持指向左边元素的指针。这意味着需要维护更多的引用(稍微增加列表操作的复杂性),但会产生更好的性能(因为从末尾迭代与从头开始迭代相同)。

通常,您应始终选择适合您的访问模式的数据结构。没有任何数据结构适用于所有内容,因此了解这些差异并了解您在应用程序中真正需要的内容非常重要,这样您就可以选择。