Нужна помощь с циклическим связанным списком в Java!

да, это один из моих домашних проектов - реализовать круговой связанный список на основе односвязного списка. Это довольно просто, и код легко читается. Все мои атрибуты общедоступны, чтобы избежать геттеров и сеттеров и частного бизнеса. Для целей этого проекта public будет достаточно.

Я инициализировал свой счетчик nItems (количество элементов в списке) и заголовок ссылки прямо в поле атрибута, но я изменю его позже, инициализировав внутри конструктора.

Мой метод step() вообще не работает. Мой компилятор просто зависает на мгновение, а затем ничего не появляется. Вот как должен работать метод step(), если я вызову его 4 раза:

List: 40 80 30 20 10 70 50 
List: 80 30 20 10 70 50 40 
List: 30 20 10 70 50 40 80 
List: 20 10 70 50 40 80 30 

Метод Find() работает нормально, пока искомое значение находится внутри связанного списка. Если нет, то это будет продолжаться вечно. Если это мой список, вот что происходит с методом find(), если вы ищете значение, которого там нет (я отлаживал его шаг за шагом):

70 60 50 40 30 20 10 10 10 10 10 10 10 10...and 10 forever

Причина: если ключевого значения, которое мы ищем, нет, оно никогда не выйдет из цикла while, следовательно, постоянно повторяется current = current.next.

while(current.dData != key) {
current = current.next;

Мой метод удаления говорит, что он удалил значение 60, как я и хотел, но вот что я получаю:

Deleted link with key 60
70 60 40 30 20 10       // lie! it deletes 50 instead of 60

Также обратите внимание на мои методы display() и insert(). Они выглядят хорошо для меня, но я могу ошибаться, и это может быть источником всех проблем, которые у меня возникают с методами find() и delete().

Огромное спасибо заранее!!!

class Link {
    public int dData;
    public Link next;

    public Link(int dd) {
        dData = dd;
    }

    public void displayLink() {
        System.out.print(dData + " ");
    }
}

class CircList {
    public Link head = null;
    int nItems = 0;

    public boolean isEmpty() {
        return (nItems == 0);
    }
    // INSERT
    public void insert(int key) { 

        Link current = new Link(key);
        if(isEmpty())
            head = current;

        current.next = head;
        head = current;
        nItems++;
    }
    // STEP
    public void step() {
        Link current = head;
        do {
            current = current.next;
        } while(current != head);
    }
    // FIND
    public Link find (int key) {
        Link current = head;
        while(current.dData != key) {
            current = current.next;
        }
        return current;
    }
     // DELETE
    public Link delete(int key) {
    Link current = head;
    while(current.dData != key) {
        current = current.next;
    }
    if(current == head)
        head = head.next;
    else {
        current.next = current.next.next;
        nItems--;
    }
    return current;
}
    // DISPLAY
    public void displayList() {
        Link current = head; // start at beginning
        int counter = nItems;
        while(true) {
            if(counter != 0) {
                current.displayLink();
                current = current.next; // move to next link
                counter--;
            }
            else 
                break;
        }
    }
}

class CircListApp {
    public static void main(String[] args) {
    Link f, d;
    CircList theList = new CircList();


    theList.insert(10);      // insert items
    theList.insert(20);
    theList.insert(30);
    theList.insert(40);
    theList.insert(50);
    theList.insert(60);
    theList.insert(70);

    //System.out.println(theList.nItems + " ");
    theList.displayList();              // display list

    System.out.println("");

    f = theList.find(30);               // find item
    if( f != null)
       System.out.println("Found link with key " + f.dData);
    else
       System.out.println("Can't find link with key 30");

//    theList.step();

//
//    System.out.println("Inserting link with key 80");
//    theList.insert(80);
//    theList.displayList();              // display list
//
    d = theList.delete(60);             // delete item

    if( d != null )
       System.out.println("Deleted link with key " + d.dData);
    else
       System.out.println("Can't delete link with key 60");
    theList.displayList();              // display list
//
//    f = theList.find(99);               // find item
//    if( f != null)
//       System.out.println("Found link with key " + f.dData);
//    else
//       System.out.println("Can't find link with key 99" );
//    theList.displayList();              // display list
//
//    d = theList.delete(13);             // delete item
//    if( d != null )
//       System.out.println("Deleted link with key " + d.dData);
//    else
//       System.out.println("Can't delete link with key 13");
//    theList.displayList();              // display list
//
//    System.out.println("Stepping through list");
//    for(int j=0; j<theList.getSize; j++)
//       {
//       theList.step();
//       theList.displayList();
//       }
//
//    System.out.println("Will delete and step one by one");
//    while(theList.isEmpty() == false)
//       {
//       theList.delete();
//       theList.step();
//       theList.displayList();
//       }
    }  // end main()

}

person Sahat Yalkabov    schedule 16.11.2010    source источник
comment
Чтобы исправить Find(), посмотрите на Step(), чтобы понять, как остановиться.   -  person Stu    schedule 16.11.2010
comment
Я понимаю, что мне нужно использовать цикл do-while? Но это все равно ничего не изменит. Я чувствую, что мне не хватает другого условия в выражении while или мне нужно ввести какой-то счетчик, например. в то время как (nItems !0) nItems--;   -  person Sahat Yalkabov    schedule 16.11.2010
comment
На самом деле, вам не нужен счетчик! Вы можете просто использовать current == head в качестве проверки, если вы пробежали весь список.   -  person Lagerbaer    schedule 16.11.2010
comment
Тег домашнего задания в настоящее время не рекомендуется. meta.stackexchange.com /вопросы/10811/   -  person Woot4Moo    schedule 16.11.2010
comment
Из этой ветки не ясно, есть ли консенсус по тегу. Я нахожу это полезным...   -  person DNA    schedule 13.03.2012


Ответы (1)


К вашему «шаговому» методу: вы создаете локальную ссылку с именем current, которая изначально указывает на голову. После

current = current.next

он ссылается на преемника главы. И на следующем шаге он ссылается на преемника этого и так далее. Но это локальная ссылка, поэтому вы ничего не меняете в списке.

То, что вам нужно сделать, как я понял из желаемого результата, так же просто, как

if( head != null && head.next != null )
    head = head.next

Далее: Для вашего метода поиска: Что ж, из вашего условия цикла совершенно очевидно, что он будет работать вечно, если ключа нет в списке, потому что это ваше единственное условие нарушения. Вы должны придумать механизм, который заставит его останавливаться после просмотра каждого элемента в списке. Подсказка: посмотрите, что вы сделали в своей версии метода step().

К вашему методу удаления: первая часть (частично) в порядке (у нее та же проблема с бесконечным циклом, что и у вашего метода поиска). Что вы делаете, так это перебираете список, пока текущие данные не сравняются с ключом. Это нормально.

Но теперь current — это ссылка на элемент, который вы хотите удалить. Но что вы делаете, так это устанавливаете current.next в current.next.next, что означает, что вы удаляете преемника текущего вместо самого текущего! В вашем цикле, где вы ищете ключ, вы должны отслеживать предшественника, чтобы вы могли изменить предшественницу.следующий на текущий.следующий, что вы действительно хотите сделать.

И затем, конечно, вы должны проверить, удаляете ли вы заголовок, и если это так, вы должны установить его либо предшественником, либо преемником.

Наконец, я вижу проблему с вашим методом insert()! Я не понимаю, как это может создать круговой связанный список, потому что вы позволяете вновь вставленному элементу указывать на голову и делаете его новой головой, но ничего не указывает на него. То есть вы создаете только односвязный список? Вы вставляете новый элемент «перед» головкой ( current.next = head ), но тогда вы также должны иметь прежний предшественник head теперь, указывающий на новый элемент, текущий!

person Lagerbaer    schedule 16.11.2010
comment
С двумя вызовами step() я получаю такой результат: 60 50 40 30 20 10 10 50 40 30 20 10 10 10. Вы уверены, что условие правильное? Iirc, нам вообще не нужно беспокоиться о NULL в циклических связанных списках. И прямо сейчас current никогда не использовался после того, как я инициализировал Link current = head; - person Sahat Yalkabov; 16.11.2010
comment
Не уверен, что понимаю, что вы имеете в виду. Цель пошагового метода состоит в том, чтобы переместить голову на один шаг дальше по кругу, поэтому вам в основном нужно только head = head.next, но, поскольку ваш список может быть пустым, я бы проверил head == null. Конечно, вы можете опустить head.next == null, это правда. - person Lagerbaer; 16.11.2010
comment
Лаг, ты прав. Но есть большая проблема, вы видите эти конечные 10-ки? Их там быть не должно, вместо этого на этом месте должна быть старая голова. Связанный список должен оставаться прежним: у меня есть 10, 20, 30, 40, 50, 60, 70, поэтому на каждом этапе я должен иметь эти значения. - person Sahat Yalkabov; 16.11.2010
comment
Просто для уточнения: скажем, ваш первоначальный список 10, 20, 30, 40, 50, 60, 70. Затем вы дважды вызываете step(), и это должно привести к тому, что ваш список станет 30, 40, 50, 60, 70, 10, 20. Это правильно? В этом случае я почти уверен, что метод step() должен содержать только head = head.next и ничего больше. - person Lagerbaer; 16.11.2010
comment
Это правильно, но это вывод только с head = head.next. 1) 60 50 40 30 20 10 10 2) 50 40 30 20 10 10 10 3) 40 30 20 10 10 10 10 . Может быть, это мой метод вставки (), который вызывает это? - person Sahat Yalkabov; 16.11.2010
comment
В вашем методе вставки также есть ошибка, см. Мой (отредактированный) ответ. - person Lagerbaer; 16.11.2010