[英]Rotate Doubly Linked List
我正在尝试顺时针和逆时针旋转双向链表。 但是我的代码只输出列表的一部分。 我知道如果有 0 或 1 个元素,列表不应旋转。 如果值大于 1,我想向右旋转。另外,如果值小于 0,我想向左旋转。我不确定我的列表做错了什么。 逻辑非常混乱。 由于 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);
}
编辑:在阅读任何评论之前,我尝试过重写我的代码。 它仍然可以成功轮换列表。
是的,这很艰难,我也遇到过很多同样的问题。 有帮助的一件事是重命名一些变量,以便让我清楚地知道发生了什么。
在旋转 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;
}
(这假设您在 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;
}
我希望这更清楚。
我认为您缺少的一件事是,每当您设置一个节点的Next
属性时,您还应该设置相应的下一个节点的Previous
属性。 这样做可能有助于列表导航。
否则,将任务分解为更谨慎的方法会很有帮助,因此一种方法不会发生太多事情。
例如,可能有用的一件事是添加一个返回特定索引处的节点的方法。 这使我们可以轻松地抓取一个节点并将其设置为新的Head
,这意味着我们的Rotate
方法不需要循环 - 它只是获取适当索引处的节点并将该节点设置为新的头。
请注意,将节点设置为新的 Head 节点也应该分解为一个新方法,因为其中也涉及到相当多的内容(新的头意味着新的尾,并且需要考虑许多Previous
和Next
属性)。
希望这个基于您的代码的实现具有指导意义。 如果有什么不明白的,请告诉我:
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()) + "'";
}
}
这是一个示例程序,可让您输入一些数据然后旋转列表:
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();
}
}
上面的代码使用了以下辅助方法:
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;
}
样品 Output
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.