正在查找链接列表的中间位置



我正试图找到一个单链表的中间部分。这直接来自这个leetcode问题。

我知道如何使用列表来解决问题,但我想知道为什么我的解决方案不能具体工作。

这是ListNode类

public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

这是我的源代码

public class middle_linked_list {

public static void main(String args[]){
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);

System.out.println(middleElement(head).val);
}
public static ListNode middleElement(ListNode head){
int size = 0;
float counter = 0;
float middle = 0;
ListNode mid = head;

while(head != null)
{
++size;
head = head.next;
}
if(size % 2 == 0){
middle = size/2f;
}else{
middle = Math.round(size/2f);
}


while(mid != null){

if(counter == middle)
{
System.out.println(mid.val);
return mid;

}
System.out.println(mid.val);
++counter;
mid = mid.next;
}

return null;
}
}

我的方法

  1. 循环浏览链表以查找链表的大小
  2. 声明一个名为middle的浮点变量
  3. 如果列表大小为奇数,则我们四舍五入到最接近的整数,如果偶数,则我们什么都不做
  4. 如果计数器等于中间元素,那么我们返回中间元素

有人能向我解释为什么我的代码不工作吗

它适用于以下示例[1,2,3,4]和[1,2,3,3,4,5,6](基本上适用于所有偶数列表大小(,但不适用于1,2,3,4,56,7

干杯,非常感谢

您说过您的代码不起作用,但事实并非如此,它起作用了,只是没有如预期的那样,请尝试在未来更加清楚地了解问题。

不管怎样,只要用1而不是0初始化计数器,就可以开始了。

--编辑--

正如我所说,它在我的电脑上运行得很好,这就是将两个浮点数字与==运算符进行比较的问题。它可能适用于某些系统或JRE,但不适用于其他系统,据我所知,它与Java无关(Javascript的行为完全相同(,它与每个不同系统中浮点数字小数部分的二进制表示有关,这是一个高级且非常低级别的主题,我们作为开发人员,不需要深入研究,我们只需要让它存在并相应地处理它。对于您的代码,不需要使用浮点数,使用整数可以解决问题,并使解决方案适用于任何系统。

如果你想了解更多,请查看链接:

https://howtodoinjava.com/java-examples/correctly-compare-float-double/

作为Java的良好实践,我随意更改了您代码中的其他一些内容,请参阅评论:

class ListNode {
//For the sake of encapsulation always keep class variables/attributes
//as private and provide get/set methods as needed to access/update 
//private values
private int val;
private ListNode next;

public ListNode() {
}
public ListNode(int val) {
this.val = val;
}
//getters and setters
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
public ListNode getNext() {
return next;
}
public void setNext(ListNode next) {
this.next = next;
}
/* this constructor is mostly useless, you don't know who next is
* before instantiating it, and if you instantiate next at the same
* time as the current node then what will you do about next of next?
* And what about next of next of next and so on? See the problem?   
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}*/
}
//As a convention always use CamelCase for Java names, this
//will also require you to rename the file to MiddleLinkedList.java  
public final class MiddleLinkedList {

public static void main(String[] args) {
/* make the instantiating dynamic, instead of fixed 
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);
*/

//dynamically instantiating n nodes: 
int val = 1;
int n = 7; //total list size
ListNode head = new ListNode(val); 
ListNode node = head;
val++;
for (; val <= n; val++) {
node.setNext(new ListNode(val)); //set next node
//"node" variable becomes next for the next loop iteration
node = node.getNext(); 
}

System.out.println("middle found: " + middleElement(head).getVal());
}
public static ListNode middleElement(final ListNode head) {
//As a good practice it's better to declare parameters as final, 
//that means you won't be able to reassign the head parameter
int size = 0;
//Don't use float or double when you're going to compare values, 
//if you need to compare float numbers don't use ==, a different 
//technique is required.

//Changing variables to int:
int counter = 1; 
int middle = 0;
ListNode mid = head;
while (mid != null) {
//I usually favor post-increment (size++) over pre-increment 
//(++size), but these only become a issue when you assign the
//increment or mix it with other operations, example: 
//(x = y++) is not the same as (x = ++y) 
//just as (x + y++) is not the same as (x + ++y) 
size++;
//we can't reassign head, since we changed it to final, so we 
//need to work with a different variable:
//head = head.getNext();
mid = mid.getNext(); 
}

/* this whole block can be replaced by a single line, see the 
* next statement
if (size % 2 == 0) {
middle = size / 2f;
} else {
middle = Math.round(size / 2f);
}
*/

//the division between two integers is always truncated, not 
//rounded, truncating a number means any decimal value will 
//be discarded, example: 1.999, will still be 1. 
//the (size % 2) part will add the rest, 0 if even size, 1 if odd
middle = (size / 2) + (size % 2);
//again we set mid to the first element to iterate and find 
//the middle one  
mid = head;

while (mid != null) {
//comparing int or long with == is safe and predicted, don't 
//use == to compare float or double 
if (counter == middle) {
System.out.println("the middle value is: "
+ mid.getVal());
return mid;
}
System.out.println("not the middle value: "
+ mid.getVal());
//again, I recommend sticking to post-increment, just because
//is what most people do, these increments can be confusing 
//and the source of some annoying bugs
counter++;
mid = mid.getNext();
}
return null;
}
}

相关内容

  • 没有找到相关文章

最新更新