简体   繁体   English

旋转双向链表

[英]Rotate Doubly Linked List

I am trying to rotate a doubly linked list both clockwise and counter clockwise.我正在尝试顺时针和逆时针旋转双向链表。 However my code only outputting a part of the list.但是我的代码只输出列表的一部分。 I understand that the list should not rotate if there are 0 or 1 elements.我知道如果有 0 或 1 个元素,列表不应旋转。 I would like to rotate to the right if the value is greater than 1. Also, I would like to rotate to the left if the value is less than 0. I'm not sure what I have done wrong with my list.如果值大于 1,我想向右旋转。另外,如果值小于 0,我想向左旋转。我不确定我的列表做错了什么。 The logic is very confusing.逻辑非常混乱。 The addLast method has intentionally not been included since it works.由于 addLast 方法有效,因此故意不包括在内。

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

    }
public class LinkedList
    {
        private Node head;
        private Node tail;
        public Node rotate(int k)
        {
            if (head == null )
            {
                return head;
            }
            Node node = head;

            k = k % listSize(head);
           
            if (k == 0 || k == 1)
            { 
                return head;
            }
             //Rotates
            while (node != null && k > 1)
            {
                node = node.next;
                k--;
            }

            Node newhead = node.next;
            newhead.previous = null;
            node.next = null;
            Node temp = newhead;
            while (temp.next != null)
            {
                temp = temp.next;
            }

            newhead = head;
            node.previous = temp.previous;
            tail = node;

            return newhead;
        }

        public int listSize(Node node)
        {
            if(node == null)
            {
                return 0;
            }
            int count = 0;
            while(node != null)
            {
                count++;
                node = node.next;
            }
            return count;

        }

        public void addLast(Object data)
        {
            Node toAdd = new Node();
            toAdd.data = data;
            toAdd.next = null;
            if (head == null)
            {
                head = toAdd;
                tail = null;
            }
            else
            {
                if (tail == null)
                {
                    head.next = toAdd;
                    tail = toAdd;
                }
                else
                {
                    tail.next = toAdd;
                    tail = toAdd;
                }
            }
        }
}
 static void Main(string[] args)
        {
            Console.WriteLine("Add Last: ");
            LinkedList myList2 = new LinkedList();

            myList2.addLast("Tim");
            myList2.addLast("Nick");
            myList2.addLast("Julie");
            myList2.addLast("Jessie");
            myList2.addLast("Jordan");
            myList2.addLast("Peter");
            myList2.addLast("John");
             myList2.rotate(2);
}

Edit: I have tried rewriting my code before reading any comments.编辑:在阅读任何评论之前,我尝试过重写我的代码。 It still does rotate the list successfully.它仍然可以成功轮换列表。

Yes, it's tough, and I had many of the same problems.是的,这很艰难,我也遇到过很多同样的问题。 One thing that helped was renaming some of the variables to make it clear in my head what was going on.有帮助的一件事是重命名一些变量,以便让我清楚地知道发生了什么。

In the rotate function:在旋转 function 中:

        public Node rotate(int k)
        {
            if (head == null)
            {
                return head;
            }

            k = -k;  
            k = k % listSize(head);
            if (k<0) { k+= listSize(head); }

            if (k == 0 )
            {
                return head;
            }
            //Rotates
            Node newhead = head;

            while (newhead != null && k > 0)
            {
                newhead = newhead.next;
                k--;
            }
            Node newtail = newhead.previous;
            
            newhead.previous = null;
            newtail.next = null;

            tail.next = head;
            head.previous = tail;
                

            head = newhead;
            tail = newtail;

            return newhead;
        }

(This assumes you're keeping the tail updated in addLast(). If you are, you may as well use it. Here's what I had:) (这假设您在 addLast() 中保持尾部更新。如果是,您也可以使用它。这就是我所拥有的:)

    public void addLast(Object inData)
    {
        Node node = new Node();
        node.next = null;
        node.data = inData;
        node.previous = tail;
        if (head == null) 
        { 
            head = node; 
        }
        if (tail != null)
        {
            tail.next = node;
        }
        tail = node;
    }

I hope this is clearer.我希望这更清楚。

One of the things I think you're missing is that anytime you set one nodes Next property, you should also set the corresponding next node's Previous property.我认为您缺少的一件事是,每当您设置一个节点的Next属性时,您还应该设置相应的下一个节点的Previous属性。 Just doing that may help with the list navigation.这样做可能有助于列表导航。

Otherwise, it can be helpful to break down the tasks into more discreet methods, so there's not too much going on in one method.否则,将任务分解为更谨慎的方法会很有帮助,因此一种方法不会发生太多事情。

One thing that may be helpful, for example, is to add a method that returns a node at a specific index.例如,可能有用的一件事是添加一个返回特定索引处的节点的方法。 This allows us to easily grab a node and set it to the new Head , which means our Rotate method doesn't need a loop - it just gets the node at the appropriate index and sets that node as the new head.这使我们可以轻松地抓取一个节点并将其设置为新的Head ,这意味着我们的Rotate方法不需要循环 - 它只是获取适当索引处的节点并将该节点设置为新的头。

Note that setting a node as a new Head node should also be broken out into a new method, since there's a fair amount involved there as well (a new head means a new tail, and lots of Previous and Next properties to think about).请注意,将节点设置为新的 Head 节点也应该分解为一个新方法,因为其中也涉及到相当多的内容(新的头意味着新的尾,并且需要考虑许多PreviousNext属性)。

Hopefully this implementation based on your code is instructive.希望这个基于您的代码的实现具有指导意义。 Please let me know if something doesn't make sense:如果有什么不明白的,请告诉我:

public class Node
{
    public object Data { get; set; }
    public Node Next { get; set; }
    public Node Previous { get; set; }

    public Node(object data)
    {
        Data = data;
    }

    public override string ToString()
    {
        return Data.ToString();
    }
}

public class LinkedList 
{
    public Node Head { get; private set; }
    public Node Tail { get; private set; }
    public int Count
    {
        get
        {
            var count = 0;
            for (var n = Head; n != null; n = n.Next, count++) ;
            return count;
        }
    }

    private void AddFirst(object data)
    {
        var node = new Node(data) {Next = Head?.Next};
        if (Head != null) { Head.Previous = node;}
        if (Tail == null) Tail = node;
        Head = node;
    }

    public void Add(object data)
    {
        if (Head == null)
        {
            AddFirst(data);
        }
        else
        {
            var node = new Node(data) {Previous = Tail?.Previous};
            if (Tail != null) Tail.Next = node;
            node.Previous = Tail;
            Tail = node;
        }
    }

    private Node ItemAt(int index)
    {
        var item = Head;
        while (index-- > 0) item = item.Next;
        return item;
    }

    private void SetNewHead(int indexOfNewHead)
    {
        var newHead = ItemAt(indexOfNewHead);
        var newTail = newHead.Previous;
        var oldHead = Head;
        var oldTail = Tail;

        newHead.Previous = null;
        newTail.Next = null;
        oldTail.Next = oldHead;
        oldHead.Previous = oldTail;

        Head = newHead;
        Tail = newTail;
    }

    /// <summary>
    /// Rotates the Tail to the Head the specified number of times
    /// </summary>
    /// <param name="rotations">
    /// The number of times to rotate the Tail to the Head
    /// A negative number rotates the Head to the Tail
    /// </param>
    public void Rotate(int rotations)
    {
        var count = Count;
        rotations = rotations % count;
        if (rotations == 0) return;

        // Find the index of the new head based on the number of rotations
        // If rotations is positive, then the index is the count minus rotations
        // If rotations is negative, then the index is 'rotations * -1' (or -rotations) 
        var newHeadIndex = rotations > 0 ? count - rotations : -rotations;

        // Now that we know the index of the new head, we just set it as the head
        SetNewHead(newHeadIndex);
    }

    public List<Node> ToList()
    {
        var nodes = new List<Node>();
        for (var node = Head; node != null; node = node.Next)
        {
            nodes.Add(node);
        }
        return nodes;
    }

    public override string ToString()
    {
        return Count == 0 ? "{no items}" : "'" + string.Join("' <-> '", ToList()) + "'";
    }
}

And here's a sample program that lets you enter some data and then rotate the list:这是一个示例程序,可让您输入一些数据然后旋转列表:

public static void Main(string[] args)
{
    var linkedList = new LinkedList();

    while (true)
    {
        var data = GetStringFromUser("Enter data to add, or 'exit' to stop: ");
        if (data.Equals("exit", StringComparison.OrdinalIgnoreCase))
            break;
        linkedList.Add(new Node(data));
    }

    Console.WriteLine("\nLinked list items:");
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine(linkedList);
    Console.ResetColor();

    while (true)
    {
        var rotations = GetIntFromUser("\nEnter number of rotations, or 42 to stop: ");
        if (rotations == 42) break;
        linkedList.Rotate(rotations);
        Console.WriteLine($"\nLinked list items after {rotations} rotations:");
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine(linkedList);
        Console.ResetColor();
    }
}

The code above uses the following helper methods:上面的代码使用了以下辅助方法:

public static string GetStringFromUser(string prompt)
{
    Console.Write(prompt);
    return Console.ReadLine();
}

public static int GetIntFromUser(string prompt, Func<double, bool> validator = null)
{
    bool isValid = true;
    int result;

    do
    {
        if (!isValid)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("Invalid input, please try again.");
            Console.ResetColor();
        }
        else isValid = false;

        Console.Write(prompt);
    } while (!int.TryParse(Console.ReadLine(), out result) &&
                (validator == null || !validator.Invoke(result)));

    return result;
}

Sample Output样品 Output

在此处输入图像描述

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

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