在 Java(Finding/Deleting 个节点)中实现链表
Implementing a linked list in Java (Finding/Deleting Nodes)
我一直在编写一些代码来实现 java 中的(编辑:单向)链表。我的主要问题是在查找和删除节点时出现的,也就是说,使用 Find(data) 告诉用户列表中是否存在节点; Delete(data) 实际上是在找到节点后从列表中删除该节点(如果找不到该节点,则不执行任何操作)。 Find(data) 和 Delete(data) 使用相同的 if-else 逻辑,所以现在我只是将 Find 方法中的代码复制到 delete 方法中,并在 delete 方法中使用适当的指针指向 "hop over" 已删除的节点。
我想知道是否有更有效的方法。我想到了在删除块中使用布尔值,例如:
public void Delete(data)
{
if Find(data)
{
//code to delete node
}
}
但是因为当前节点可能位于头部、尾部或中间某处,您仍然需要循环逻辑来检查您所在的位置,以便您可以设置适当的引用。例如,如果用户要删除尾部的节点,则前一个节点的下一个节点将被设置为空。但是,在中间,您必须 运行 一个 while 循环来遍历列表,即
while (iter.NextNode !=null)
{
if (iter.NextNode.data == data)
{
iter.NextNode = iter.NextNode.NextNode;
System.out.println(data + " was found in the list and removed"
break;
}
else if (iter.NextNode.NextNode == null && iter.NextNode.data == data)
{//this is kinda weird. I couldn't use an else block, because either
//the code would never exit the loop, or it would keep running
iter.NextNode = null;
System.out.println(data + " was found in the list and removed. ");
break;
}
iter = iter.NextNode;
if (node.NextNode == null && node.data != data)
{//i guess I could have just put this if statement inside
//the else block
System.out.println(data + " was not found in the list.");
break;
}
}
上面的代码块处理了这两种情况。
下面的代码块是我的 Find(data) 方法:
public void Find(int data)
{
Node node = head;
if (head == null)
{
System.out.println("No nodes found. ");
}
else if (node.NextNode==null)
{
if (node.data == data)
{
System.out.println( data + " was found in the list.");
}
else
{
System.out.println("That value was not found in the list.");
}
}
else
{
while (node.NextNode !=null)
{
if (node.data == data)
{
System.out.println(data + " was found in the list.");
break;
}
else if (node.NextNode.NextNode == null && node.NextNode.data == data)
{
System.out.println(data + " was found in the list.");
break;
}
else
{
node = node.NextNode;
}
if (node.NextNode == null && node.data != data)
{
System.out.println(data + " was not found in the list.");
break;
}
}
}
}
如果问题不清楚:有没有办法在删除块中使用我的 Find(data) 方法,并删除所有逻辑?
感谢您的指导。非常感谢!
由于您的 Find() 方法 returns 什么都没有,您不能在 Delete() 方法中使用它。
要集中 Find() 和 Delete() 的代码,请创建另一个私有方法 - getPreviousNode(int data),其中 returns 所需节点的前一个节点。
private Node getPreviousNode(int data) {
Node iter = head;
while (iter.NextNode != null) {
if (iter.NextNode.data == data) {
return iter;
}
iter.nextNode = iter.nextNode.nextNode;
}
return null;
}
在 Find() 和 Delete() 方法中调用此方法。
void Find(int data) {
// Code to handle head & tail conditions
Node prevNode = getPreviousNode(data);
if (prevNode != null) {
System.out.println("Found");
}
...
}
void Delete(int data) {
// Code to handle head & tail conditions
Node prevNode = getPreviousNode(data);
if (prevNode != null) {
Node node = prevNode.nextNode;
prevNode.nextNode = node.nextNode;
node.nextNode = null;
System.out.println("Found & Deleted");
}
...
}
回复您的评论:
只写 "prevNode.nextNode = prevNode.NextNode.NextNode" 是不够的。
考虑以下链表:
A[data = 1 | nextNode = b] --> B[data = 4 | nextNode = c] --> C[data = 55 | nextNode = null]
其中,
A、B、C:节点
a, b, c : 分别引用节点 A, B 和 C。
B:要删除的节点
现在考虑删除节点的代码:
Node prevNode = getPreviousNode(data);
prevNode = a; // "a" is a reference to Node A returned by getPreviousNode(4)
if (prevNode != null)
node = prevNode.nextNode;
node = b; // prevNode.nextNode is 'b'
prevNode.nextNode = node.nextNode;
prev.NextNode = c; // node.nextNode is 'c'
现在 LinkedList 是:
A[data = 1 | nextNode = c] B[data = 4 | nextNode = c] --> C[data = 55 | nextNode = null]
现在节点 A 将节点 C 引用为下一个节点。因此节点 B 与 LinkedList 解除链接
但没有完全从 LinkedList 中删除,因为节点 B 仍然引用节点 C
作为下一个节点。因此,您必须删除此引用才能从 LinkedList 中完全删除节点 B。
所以下面的语句是必要的
node.nextNode = null;
现在 LinkedList 是:
A[data = 1 | nextNode = c] --> C[data = 55 | nextNode = null]
B[data = 4 | nextNode = null] is removed from LinkedList.
您可以按照@SanjayChavan 的建议分享findPrevious
,但是当您练习编写链表代码时,您会发现它已经很干净了,分享findPrevious
并没有使它变得更好:
boolean Delete(int data)
{
Node prev = null, node = null;
for (node = head; node!=null; node=(prev=node).nextNode)
{
if (node.data == data)
{
if (prev!=null)
prev.nextNode = node.nextNode;
else
head = node.nextNode;
node.nextNode = null;
return true;
}
}
return false;
}
Node Find(int data)
{
for (Node node = head; node != null; node = node.nextNode)
{
if (node.data==data)
return node;
}
return null;
}
一旦 Sanjay 的代码被修复以便它可以找到并删除 head
节点,它将比这更长更复杂。
public static ListNode search( List list, int target )
{
ListNode cursor = list.getFirst( );
while( cursor != null )
{
if( cursor.getInfo( ) == target )
return cursor;
cursor = cursor.getLink( );
}
return cursor;
}
public void remove( int element )
{
ListNode cursor;
ListNode target = search( this, element );
if( isEmpty( ) )
System.out.println( "There are no elements in this list." );
if( target == null )
System.out.println( element+" is not in this list." );
else
{
if( head.getInfo( ) == element )
{
if( head.getLink( ) == null )
head = null;
else if( head == tail )
tail = null;
else
head = head.getLink( );
}
else if( tail.getInfo( ) == element )
{
for( cursor = head; cursor.getLink( ).getInfo( ) != element; cursor = cursor.getLink( ) )
{ }
cursor.setLink( null );
tail = cursor;
}
else
{
for( cursor = head; cursor.getLink( ).getInfo( ) != element; cursor = cursor.getLink( ) )
{ }
cursor.setLink( cursor.getLink( ).getLink( ) );
}
}
}
我一直在编写一些代码来实现 java 中的(编辑:单向)链表。我的主要问题是在查找和删除节点时出现的,也就是说,使用 Find(data) 告诉用户列表中是否存在节点; Delete(data) 实际上是在找到节点后从列表中删除该节点(如果找不到该节点,则不执行任何操作)。 Find(data) 和 Delete(data) 使用相同的 if-else 逻辑,所以现在我只是将 Find 方法中的代码复制到 delete 方法中,并在 delete 方法中使用适当的指针指向 "hop over" 已删除的节点。
我想知道是否有更有效的方法。我想到了在删除块中使用布尔值,例如:
public void Delete(data)
{
if Find(data)
{
//code to delete node
}
}
但是因为当前节点可能位于头部、尾部或中间某处,您仍然需要循环逻辑来检查您所在的位置,以便您可以设置适当的引用。例如,如果用户要删除尾部的节点,则前一个节点的下一个节点将被设置为空。但是,在中间,您必须 运行 一个 while 循环来遍历列表,即
while (iter.NextNode !=null)
{
if (iter.NextNode.data == data)
{
iter.NextNode = iter.NextNode.NextNode;
System.out.println(data + " was found in the list and removed"
break;
}
else if (iter.NextNode.NextNode == null && iter.NextNode.data == data)
{//this is kinda weird. I couldn't use an else block, because either
//the code would never exit the loop, or it would keep running
iter.NextNode = null;
System.out.println(data + " was found in the list and removed. ");
break;
}
iter = iter.NextNode;
if (node.NextNode == null && node.data != data)
{//i guess I could have just put this if statement inside
//the else block
System.out.println(data + " was not found in the list.");
break;
}
}
上面的代码块处理了这两种情况。
下面的代码块是我的 Find(data) 方法:
public void Find(int data)
{
Node node = head;
if (head == null)
{
System.out.println("No nodes found. ");
}
else if (node.NextNode==null)
{
if (node.data == data)
{
System.out.println( data + " was found in the list.");
}
else
{
System.out.println("That value was not found in the list.");
}
}
else
{
while (node.NextNode !=null)
{
if (node.data == data)
{
System.out.println(data + " was found in the list.");
break;
}
else if (node.NextNode.NextNode == null && node.NextNode.data == data)
{
System.out.println(data + " was found in the list.");
break;
}
else
{
node = node.NextNode;
}
if (node.NextNode == null && node.data != data)
{
System.out.println(data + " was not found in the list.");
break;
}
}
}
}
如果问题不清楚:有没有办法在删除块中使用我的 Find(data) 方法,并删除所有逻辑?
感谢您的指导。非常感谢!
由于您的 Find() 方法 returns 什么都没有,您不能在 Delete() 方法中使用它。 要集中 Find() 和 Delete() 的代码,请创建另一个私有方法 - getPreviousNode(int data),其中 returns 所需节点的前一个节点。
private Node getPreviousNode(int data) {
Node iter = head;
while (iter.NextNode != null) {
if (iter.NextNode.data == data) {
return iter;
}
iter.nextNode = iter.nextNode.nextNode;
}
return null;
}
在 Find() 和 Delete() 方法中调用此方法。
void Find(int data) {
// Code to handle head & tail conditions
Node prevNode = getPreviousNode(data);
if (prevNode != null) {
System.out.println("Found");
}
...
}
void Delete(int data) {
// Code to handle head & tail conditions
Node prevNode = getPreviousNode(data);
if (prevNode != null) {
Node node = prevNode.nextNode;
prevNode.nextNode = node.nextNode;
node.nextNode = null;
System.out.println("Found & Deleted");
}
...
}
回复您的评论:
只写 "prevNode.nextNode = prevNode.NextNode.NextNode" 是不够的。
考虑以下链表:
A[data = 1 | nextNode = b] --> B[data = 4 | nextNode = c] --> C[data = 55 | nextNode = null]
其中,
A、B、C:节点
a, b, c : 分别引用节点 A, B 和 C。
B:要删除的节点
现在考虑删除节点的代码:
Node prevNode = getPreviousNode(data);
prevNode = a; // "a" is a reference to Node A returned by getPreviousNode(4)
if (prevNode != null)
node = prevNode.nextNode;
node = b; // prevNode.nextNode is 'b'
prevNode.nextNode = node.nextNode;
prev.NextNode = c; // node.nextNode is 'c'
现在 LinkedList 是:
A[data = 1 | nextNode = c] B[data = 4 | nextNode = c] --> C[data = 55 | nextNode = null]
现在节点 A 将节点 C 引用为下一个节点。因此节点 B 与 LinkedList 解除链接 但没有完全从 LinkedList 中删除,因为节点 B 仍然引用节点 C 作为下一个节点。因此,您必须删除此引用才能从 LinkedList 中完全删除节点 B。
所以下面的语句是必要的
node.nextNode = null;
现在 LinkedList 是:
A[data = 1 | nextNode = c] --> C[data = 55 | nextNode = null]
B[data = 4 | nextNode = null] is removed from LinkedList.
您可以按照@SanjayChavan 的建议分享findPrevious
,但是当您练习编写链表代码时,您会发现它已经很干净了,分享findPrevious
并没有使它变得更好:
boolean Delete(int data)
{
Node prev = null, node = null;
for (node = head; node!=null; node=(prev=node).nextNode)
{
if (node.data == data)
{
if (prev!=null)
prev.nextNode = node.nextNode;
else
head = node.nextNode;
node.nextNode = null;
return true;
}
}
return false;
}
Node Find(int data)
{
for (Node node = head; node != null; node = node.nextNode)
{
if (node.data==data)
return node;
}
return null;
}
一旦 Sanjay 的代码被修复以便它可以找到并删除 head
节点,它将比这更长更复杂。
public static ListNode search( List list, int target )
{
ListNode cursor = list.getFirst( );
while( cursor != null )
{
if( cursor.getInfo( ) == target )
return cursor;
cursor = cursor.getLink( );
}
return cursor;
}
public void remove( int element )
{
ListNode cursor;
ListNode target = search( this, element );
if( isEmpty( ) )
System.out.println( "There are no elements in this list." );
if( target == null )
System.out.println( element+" is not in this list." );
else
{
if( head.getInfo( ) == element )
{
if( head.getLink( ) == null )
head = null;
else if( head == tail )
tail = null;
else
head = head.getLink( );
}
else if( tail.getInfo( ) == element )
{
for( cursor = head; cursor.getLink( ).getInfo( ) != element; cursor = cursor.getLink( ) )
{ }
cursor.setLink( null );
tail = cursor;
}
else
{
for( cursor = head; cursor.getLink( ).getInfo( ) != element; cursor = cursor.getLink( ) )
{ }
cursor.setLink( cursor.getLink( ).getLink( ) );
}
}
}