메뉴 건너뛰기

JAVA Linked List(링크드 리스트)

Eugene 2021.02.09 15:12 조회 수 : 792

package com.popgene.datastructure;

 

/**

 * LinkedList의 노드

 * @author eugene

 *

 */

 

public class Node {

    /**

    * data는 노드의 값

    * next는 다음 노드

    */

 

    private Object data;

    private Node next;

 

    /**

    * 최초 노드는 생설 될 때 다음 노드가 존재하지 않는다.

    * @param input 변수 값을 입력하면 data에 입력

    */

 

    public Node(Object input) {

        this.data = input; 

        this.next = null; 

    }

 

    /*

    * 노드의 값을 출력하는 메쏘드.

    */

    public String toString() {

        return String.valueOf(this.data);

    }

 

    public void setData(Object data) {

        this.data = data; 

    }

 

    public Object getData() {

        return this.data;

    }

 

    public void setNext(Node next) {

        this.next = next;

    }

 

    public Node getNext() {

        return this.next;

    }

}

 

 

package com.popgene.datastructure;

 

/**

 * Linked List

 * @author eugene

 *

 */

public class LinkedList {

/**

* head는 첫 노드(헤드)

* tail은 마지막 노드(테일)

* size는 이 LinkedList의 크기

*/

    private Node head;

    private Node tail;

    private int size = 0;

    

    /**

     * LinkedList의 맨 앞에 노드 추가

     * @param input 추가될 노드의 값

     * 현재의 헤드를 신규노드의 다음 노드로 설정 후,

     * LinkedList의 헤드를 신규 노드로 설정

     * 헤드 노드를 생성했는데, 헤드노드의 다음 노드가 존재하지 않는다면(head.getNext() == null),

     * 헤드와 테일은 동일하다.

     * 신규노드 추가 후 LinkedList의 크기를 1 증가시켜준다.

     */

    public void addFirst(Object input)  {

        Node newNode = new Node(input);

        newNode.setNext(head);

        head = newNode;

        size++;

        if (head.getNext() == null) {

            tail = head;

        }

    }

    

    /**

     * LinkedList의 끝에 노드 추가

     * @param input

     * LinkedList의 크기가 0일 경우에는 addFirst를 통하여 노드 추가

     * 신규 노드 생성 후 테일의 다음 노드를 신규노드로 설정 한 뒤

     * 테일을 생성한 노드로 대체

     */

    public void addLast(Object input)   {   

        Node newNode = new Node(input);

        if(size == 0)   {

            addFirst(input);    

        }

        else {

            tail.setNext(newNode);

            tail = newNode;

            size++;

        }

    }

    

    /**

     * 주어진 index의 위치의 노드를 조회

     * @param index

     * @return Node

     * 헤드 노드부터 시작하여, index 전위치까지의 다음노드를 조회하는 방법으로 index위치의 노드를 조회

     */

    Node node(int index)    {

        Node x = head;

        for (int i = 0; i < index; i++)

            x = x.getNext();

        return x;

    }

    

    /**

     * 특정위치에 노드 추가

     * @param k

     * @param input

     * k위치에 input값의 노드를 추가

     * 0번째에 추가면 addFirst 호출

     * temp1 - node 메쏘드로 k - 1 위치의 노드를 조회, 삽입할 위치 바로 전 노드

     * temp2 - temp1의 다음 노드를 가져옴

     * temp1과 temp2 사이에 삽입

     * 신규 노드를 생성하고 temp1의 다음 노드로 설정하고 신규노드의 다음 노드를 temp2로 설정

     * LinkedList의 크기 증가

     * 만약 신규노드의 다음이 없을 때, 신규노드를 테일로 설정

     */

    public void add(int k, Object input) {

        if (k==0)    {

            addFirst(input);

        }

        else {

            Node temp1 = node(k-1);

            Node temp2 = temp1.getNext();

            Node newNode = new Node(input);

            temp1.setNext(newNode);

            newNode.setNext(temp2);

            size++;

            

            if (newNode.getNext() == null) {

                tail = newNode;

            }

        }

    }

    

    /**

     * LinkedList의 모든 원소를 헤드부터 테일까지 순차적으로 출력

     */

    public String toString() {

        if (head==null) {

            return "[]";

        }

        

        Node temp = head;

        String str = "[";

        

        while (temp.getNext() != null) {

            str += temp.getData() + ",";

            temp = temp.getNext();

        }

        

        str += temp.getData();

        return str+"]";

    }

    

    /**

     * 헤드 노드 삭제

     * @return Object

     * temp에 head를 넣고 head에 temp의 다음 노드를 넣은 후, returnData의 기존 헤드 노드의 값 보관

     * temp 노드(기존 헤드 노드) null을 넣어 삭제, 기존 헤드 노드 값(returnData) 반환

     * size 1 감소

     */ 

    public Object removeFirst()     {   

        Node temp = head;

        head = temp.getNext();

        

        Object returnData = temp.getData();

        temp = null;

        size--;

        return returnData;

    }

    

    /**

     * k번째 노드 삭제

     * @param k

     * @return Object

     * k가 0 즉 헤드 노드 삭제 시 removeFirst() 호출

     * temp에 삭제할 전 노드를 node() 메쏘드로 조회하여 넣고,

     * todoDeleted에 삭제할 노드를 넣는다.

     * temp의 다음 노드를 현재 노드 다음 노드로 수정한다.

     * returnData에 삭제될 노드의 값을 넣는다.

     * 삭제될 노드가 테일일경우 테일을 삭제될 노드의 전 노드로 바꾼다.

     * 삭제될 노드(todoDeleted)를 null로 만들어 삭제한 후, LinkedList의 크기를 1 줄인다.

     * 삭제된 노드의 값을 반환한다.

     */

    public Object remove(int k)     {

        if(k == 0)

            return removeFirst();

        Node temp = node(k-1);

        Node todoDeleted = temp.getNext();

        temp.setNext(temp.getNext().getNext());

        Object returnData = todoDeleted.getData();

        

        if (todoDeleted == tail) {

            tail = temp;

        }

        

        todoDeleted = null;

        size--;

        return returnData;

    }

    

    /**

     * 마지막 노드 삭제

     * @return Object

     * LinkedList 크기(size)에서 하나 전 위치로 remove() 메쏘드를 호출하여 삭제

     */

    public Object removeLast() {

        return remove(size-1);

    }

    

    /**

     * LinkedList 크기 반환

     * @return int

     */

    public int size()   {

        return size;

    }

    

    /**

     * k번째 노드 값 반환

     * @param k

     * @return Object

     */

    public Object get(int k)    {

        Node temp = node(k);

        return temp.getData();

    }

    

    /**

     * 값을 가지고 Node의 위치를 조회

     * @param data

     * @return int

     */

    public int indexOf(Object data)     {

        Node temp = head;

        int index = 0;

        while (temp.getData() != data)   {

            temp = temp.getNext();

            index++;

            if (temp == null)

                return -1;

        }

        

        return index;

    }

    

    /**

     * 반복

     * @return

     */

    public ListIterator listIterator()  {

        return new ListIterator(head);

    }

}

 

 

package com.popgene.datastructure;

 

public class ListIterator {

    /**

    * lastReturned: 이 ListIterator를 통해서 해당 LinkedList의 어느 노드까지 갔는 지를 나타내는 최근(마지막) 조회한 노드

    * nextLink: lastReturned의 다음 노드, 즉 조회될 노드

    * nextIndex: 조회될 노드의 위치

    */

 

    private Node lastReturned;

    private Node nextLink; 

    private int nextIndex;

 

    /**

    * @param head

    * ListIterator 생성 시 아직 조회 된 노드가 없으므로 lastReturned는 존재하지 않고

    * 최초로 조회될 노드는 헤드 노드가 됨

    */

 

    ListIterator(Node head) {

        nextLink = head;

        nextIndex = 0;

    }

 

 

 

    /**

    * 다음 노드 조회

    * @return Object

    * 조회가 진행되면, lastReturned는 nextLink가 되고

    * nextLink는 그 다음 노드가 된다.

    * nextIndex 1 증가

    * 조회된 lastReturned의 값을 반환

    */

 

    public Object next() { 

        lastReturned = nextLink;

        nextLink = nextLink.getNext();

        nextIndex++;

 

        return lastReturned.getData();

    }

 

    /**

    * LinkedList의 크기가 다음 위치 보다 작다면, 벗어 난 것이므로 다음 노드가 존재하지 않는다.

    * @param linkedListsize

    * @return boolean

    */

 

    public boolean hasNext(int linkedListsize) {

        return nextIndex < linkedListsize;

    }

 

    /**

    * 추가

    * @param input

    * @param head

    * @return boolean

    * 새로운 노드를 생성하여, 마지막으로 조회된 노드(lastReturned)가 존재하지 않으면, 헤드에 새로운 노드를 넣고

    * 새로운 노드의 다음 노드는 이 ListIterator의 현재 노드(nextLink)로 설정한다.

    * lastReturned가 존재하면, lastReturned의 뒤에 새로운 노드를 추가하고, 다음 조회할 노드가 새로운 노드의 다음노드가 된다.

    * 위 두가지 경우를 모두 거친 후 lastReturned를 새로운 노드로 설정하면, 새로운 노드 삽입이 끝난다.

    * nextIndex를 1 증가

    */

 

    public boolean add(Object input, Node head) {

        Node newNode = new Node(input);

 

        if (lastReturned == null) {

            head = newNode;

            newNode.setNext(nextLink);

        }

        else {

            lastReturned.setNext(newNode);

            newNode.setNext(nextLink);

        }

 

        lastReturned = newNode;

 

        nextIndex++;

 

        return true;

    }

 

    /**

    * 삭제

    * @param ll

    * ListIterator의 마지막으로 노드를 제거한다.

    * 

    */

 

    public void remove(LinkedList ll) {

        if (nextIndex == 0) {

            throw new IllegalStateException();

        }

 

        ll.remove(nextIndex-1);

 

        nextIndex--;

    }

}

 

 

package com.popgene.datastructure;

 

public class LinkedListApp {

    public static void main(String[] args) {

        LinkedList numbers = new LinkedList();

        numbers.addFirst(1);

        numbers.addFirst(0);

        numbers.addLast(10);

        numbers.addLast(15);

        numbers.addLast(20);

        numbers.add(0,40);

 

        System.out.println("1:" + numbers);

 

        numbers.remove(2);

 

        System.out.println("2:" + numbers);

 

        ListIterator li = numbers.listIterator();

 

        Node ll = new Node(0);

 

        while (li.hasNext(numbers.size())) {

            if ((int)li.next() == 1)

                li.remove(numbers);

        }

 

        System.out.println("3:" + numbers);

 

        li.add(3, ll);

 

        System.out.println("4:" + numbers);

    }

}

 

 

이 프로그램에는 3개의 객체가 있다.

Node와 Node로 구성된 LinkeList, 그리고 LinkedList를 반복탐색하는 ListIterator.

설명은 주석으로 대체한다.

 

by 한국교통대 김지훈