









Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Community
Ask the community for help and clear up your study doubts
Discover the best universities in your country according to Docsity users
Free resources
Download our free guides on studying techniques, anxiety management strategies, and thesis advice from Docsity tutors
The concept of a circular sorted linked list, its advantages over regular linked lists, and provides the implementation of search, insert, and delete operations. It also discusses the differences between circular sorted linked list and double linked list.
Typology: Lecture notes
1 / 17
This page cannot be seen from the preview
Don't miss anything!
info
info
info
list
info
info
info
list
info
list
List
ArrayList LinkedList
UnsortedArrayList SortedArrayList UnsortedLinkedList SortedLinkedList CircularSortedLinkedList
info
info
info
info
prevLoc list 일반적인 경우 prevLoc.next = loc.next;
info
10
info
info
info
40
loc list
loc
prevLoc
list.next = list.next.next; 또는 list.next = loc.next;
info
info
info
info
prevLoc list
prevLoc.next = loc.next; list = prevLoc;
info
10
list
loc
list = null;
prevLoc
loc
public boolean delete(Object item) throws ListUnderflowException{ if(isEmpty()) throw new ListUnderflowException(“…”); Comparable x = (Comparable)item; ListNode loc = list.next; ListNode prevLoc = null; for(int i=0;i<size;i++){ int compResult = x.compareTo(loc.info); if(compResult==0){ // 삭제할 노드가 존재하는 경우 if(prevLoc==null){ // 첫 노드를 삭제하는 경우 if(loc == loc.next) list = null; // 첫 노드가 유일 노드인 경우 else list.next = loc.next; } else{ prevLoc.next = loc.next; if(loc==list) list = prevLoc; // 마지막 노드를 삭제하는 경우 } size--; return true; } else if(compResult<0) return false; else{ prevLoc = loc; loc = loc.next; } } // for return false; } // CircularSortedList::delete
if(loc == loc.next) 대신에 if(size==1)를 사용할 수 있음
첫 노드와 마지막 노드를 모두 접근하기가 용이하다는 순환 연결 구조의 특성을 이용하여
보다 효율적으로 delete 메소드를 구현할 수 있다. 즉, 첫 노드와 마지막 노드와 비교하여
첫 노드보다 작은 경우와 첫 노드와 큰 경우에 대해서는 리스트 전체를 검색하여 삭제할 노
드가 있는지 찾는 과정을 생략할 수 있다.
public boolean delete(Object item) throws ListUnderflowException{ if(isEmpty()) throw new ListUnderflowException(“…”); Comparable x = (Comparable)item; if(x.compareTo(list.next.info)<0||x.compareTo(list.info)>0){ return false; } // 나머지 부분은 동일
} // CircularSortedList::delete
이용한 delete 메소드
public void insert(Object item){ Comparable x = (Comparable)item; ListNode newNode = new ListNode(); newNode.info = item; newNode.next = null; ListNode loc = (list==null)? null: list.next; ListNode prevLoc = null; for(int i=0;i<size;i++){ // 삽입할 위치 찾기 if(x.compareTo(loc.info)<0) break; else{ prevLoc = loc; loc = loc.next; } } // for if(prevLoc==null){ // 리스트 맨 앞에 삽입되는 경우 // 리스트가 비어있는 경우 if(list==null){ list = newNode; newNode.next = newNode; } else{ newNode.next = loc; list.next = newNode; } } else{ newNode.next = loc; prevLoc.next = newNode; // 리스트의 맨 마지막에 삽입되는 경우 if(prevLoc == list) list = newNode; } size++; } // CircularSortedList::insert
위 슬라이드에 있는 삽입 연산은 기존 정렬 연결 리스트와 동일한 방법으로 구현한 것이다.
먼저 삽입할 위치를 찾은 다음, 삽입할 위치에 따라 필요한 각 종 연결을 변경하는 방식이
다. 다음 슬라이드에 있는 삽입 연산은 순환 연결 리스트의 특성을 활용하고 있다. 즉, 새
요소를 추가할 때 그 요소를 리스트의 첫 요소와 마지막 요소와 비교하여 첫 요소보다 작거
나 마지막 요소보다 클 경우에는 이것을 먼저 처리하여 준다. 두 경우는 정렬된 순환 연결
구조의 특성 상 같은 위치에 삽입되는 형태가 된다.
public void insert(Object item){ Comparable x = (Comparable)item; ListNode newNode = new ListNode(); newNode.info = item; newNode.next = null; size++; if(list==null){ list = newNode; newNode.next = newNode; return; } // 리스트가 비어 있는 경우 if(x.compareTo(list.next.info)<0||x.compareTo(list.info)>0){ newNode.next = list.next; list.next = newNode; if(x.compareTo(list.info)>0) list = newNode; // 맨 끝에 삽입되는 경우 return; } // 삽입하고자 하는 노드가 첫 노드보다 작거나 마지막 노드보다 큰 경우 // 첫 노드와 비교할 필요 없음 ListNode loc = list.next.next; ListNode prevLoc = list.next; for(int i=0;i<size;i++){ if(x.compareTo(loc.info)<0){ newNode.next = loc; prevLoc.next = newNode; return; } else{ prevLoc = loc; loc = loc.next; } } // for } // CircularSortedList::insert
이용한 insert 메소드
CircularSortedLinkedList의 장단점
순환 정렬 연결 리스트의 장점을 기존 정렬 연결 리스트와 비교하여 보자. 연산의 성능 측
면에서 보면 향상된 것이 거의 없다. 그러나 순환 정렬 연결 리스트는 첫 노드뿐만 아니라
마지막 노드에 대한 접근이 용이하므로 다음과 같은 서비스는 기존 정렬 연결 리스트보다
우수하다.
첫째, 가장 큰 값의 추출
둘째, 리스트에 저장된 값들 사이에 있는 값인지 알 필요가 있는 경우
셋째, 정렬된 데이터를 연속해서 삽입하는 경우
마지막 서비스에 경우에는 삽입 연산이 순환 연결 리스트의 특성을 활용하고 있어야 한다.
이런 측면에서 보았을 때 일반 정렬 연결 리스트에서 마지막 노드를 가리키는 포인터를 하
나 더 유지하는 방법을 생각해 볼 수 있다. 오히려 이 방법이 순환 연결 리스트에 비해 우
수할 수 있다.
public abstract class DoubleLinkedList implements List{ protected class ListNode{ public Object info; public ListNode back; public ListNode next; } protected class ListIterator{ … } protected ListNode list = null; protected int size = 0; public DoubleLinkedList() {} public abstract boolean search(Object item) throws ListUnderflowException; public abstract void insert(Object item); public abstract boolean delete(Object item) throws ListUnderflowException; public abstract Object retrieve(Object item) throws ListUnderflowException; public boolean isFull(){ return false; } public boolean isEmpty(){ return (list == null); } public void clear{ list = null; } public int size(){ return size; } public Iterator iterator() { return new ListIterator(list); } } // DoubleLinkedList class
DoubleLinkedList에서 노드를 나타내는 클래스의 이름은 ListNode이고, 반복자 클래스의 이
름은 ListIterator이다. 즉, LinkedList가 사용하는 이름과 동일한 이름을 사용한다. 하지만 내
부 클래스의 이름이므로 이렇게 같은 이름을 사용하여도 문제가 되지 않는다.
protected class ListIterator{ public ListNode cursor; public int traverseCount = 0; public ListIterator(ListNode node){ cursor = node; } // ListIterator(ListNode) public boolean hasBack(){ return (traverseCount>0); } public boolean hasNext(){ return (traverseCount<size); } public Object back(){ Object tmp = cursor.info; cursor = cursor.back; traverseCount--; return tmp; } // back public Object next(){ Object tmp = cursor.info; cursor = cursor.next; traverseCount++; return tmp; } // next public void remove(){ throw new UnsupportedOperationException(); } // remove }
이중 연결 리스트에서 반복자 클래스에는 기존 연결 리스트에는 없는 back과 hasBack 메소
드가 추가로 구현되어야 한다. 즉, 주어진 노드로부터 그것의 선행 노드를 방문할 수 있는
메소드를 제공해주어야 한다.
SortedDoubleLinkedList의 Insert
info
list info
info
info
loc
newNode.back = prevLoc; newNode.next = loc; prevLoc.next = newNode; loc.back = newNode;
info
prevLoc
newNode.next = loc; loc.back = newNode; list = newNode;
loc
info
newNode.back = prevLoc; prevLoc.next = newNode;
prevLoc
이중 정렬 연결 리스트에서 삽입 연산은 일반 정렬 연결 리스트의 삽입과 마찬가지로 크게
네 가지 경우를 고려해야 한다. 위 슬라이드에서 이 중 리스트가 빈 경우에 삽입하는 경우
를 제외한 나머지 세 가지 경우에 대해 연결을 변경하는 방법을 설명하고 있다.
public void insert(Object item){ Comparable x = (Comparable)item; ListNode newNode = new ListNode(); newNode.info = item; newNode.back = null; newNode.next = null; ListNode loc = list; ListNode prevLoc = null; for(int i=0;i<size;i++){ // 삽입할 위치를 찾는다. if(x.compareTo(loc.info)<0) break; else{ prevLoc = loc; loc = loc.next; } } // for if(prevLoc==null){ // 리스트 맨 앞에 삽입되는 경우 list = newNode; newNode.next = loc; if(list!=null) loc.back = newNode; // 빈 리스트가 아닌 경우 } else{ newNode.back = prevLoc; newNode.next = loc; prevLoc.next = newNode; if(loc!=null) loc.back = newNode; // 맨 마지막에 삽입되는 경우가 아니면 } size++; } // SortedDoubleLinkedList::insert
if(prevLoc==null)이 참이면 새 요소를 리스트의 첫 노드로 삽입하는 경우이다. 이 경우는 다
시 리스트가 빈 경우와 그렇지 않은 경우로 나누어진다. 반대로 조건이 거짓이면 새 요소를
리스트 중간 또는 끝에 삽입하는 경우이다. 리스트 중간에 삽입되는 경우에는 새 요소가 선
행 및 후속 요소를 모두 가지게 되지만 리스트 마지막에 삽입되는 경우에는 선행요소만 가
지게 된다.
public boolean delete(Object item) throws ListUnderflowException{ if(isEmpty()) throw new ListUnderflowException("…"); Comparable x = (Comparable)item; ListNode loc = list; List prevLoc = null; for(int i=0;i<size;i++){ int compResult = x.compareTo(loc.info); if(compResult==0){ // 삭제할 노드가 존재하는 경우 if(prevLoc==null){ // 첫 노드를 삭제하는 경우 if(loc.next==null) list = null; // 삭제할 노드가 유일 노드인 경우 else{ loc.next.back = null; list = loc.next; } } else{ prevLoc.next = loc.next; if(loc.next != null) loc.next.back = prevLoc; // 마지막 노드가 아닌 경우 } return true; } else if(compResult<0) return false; else{ prevLoc = loc; loc = loc.next; } } // for return false; }
색인 info next
0 David 2
1 null 5
2 John 4
3 Peter 6
4 Mary 3
5 null END
6 Robert END
list 0
class ArrayLinkedList{ public static final int DEF_MAX_CAPACITY = 50; public static final int END = -1; private class ListNode{ public Object info; public int next; } private int list = END; private ListNode[] nodes; private int size = 0; private int free = 0; … }
free 1 size 5
따라서 null 대신에 -1을 이용하여 리스트의 끝을 나타낸다.
배열을 이용한 연결구조의 구현 – 계속
info
David
info
John
info
Mary
info
Peter
list info
Robert
free null null
info
David
info
John
info
Peter
list info
Robert
free null null null
Mary의 삭제
보다 자세하게 구현 원리를 살펴보면 배열을 이용한 연결구조는 내부적으로 두 개의 리스트
를 유지한다. 하나는 요소들이 저장되어 있는 유효한 노드들을 연결해 놓은 리스트이고, 다
른 하나는 요소들이 저장되어 있지 않은 빈 노드를 연결해 놓은 리스트이다. 만약 새 요소
를 추가해야 하면 빈 노드들의 리스트에서 하나의 노드를 선택하여 이 노드에 새 요소를 대
입하고 이 노드를 유효한 노드들의 리스트에 포함한다. 반대로 기존 요소를 삭제해야 하면
그 노드를 유효한 노드들의 리스트에서 제거하고 빈 노드들의 리스트로 옮긴다.
배열을 이용한 연결구조의 구현 – 계속
David John Peter Mary Robert
배열을 이용한 연결 리스트는 일반 연결 리스트와 달리 매번 삽입할 때마다 공간 할당이 이
루어지지 않는다는 장점을 지니고 있다. 하지만 배열의 본질적인 특성 때문에 삽입 연산에
서 공간이 부족한 경우를 고려해야 한다.
색인 info next
0 john END
1 null 2
2 null 3
3 null 4
4 null 5
5 null 6
6 null END
list 0 free 1 size 1
insert(Robert);
색인 info next
0 john 1
1 Robert END
2 null 3
3 null 4
4 null 5
5 null 6
6 null END
list 0 free 2 size 2
int tmp = nodes[free].next; nodes[free].info = item; nodes[free].next = END; nodes[prevLoc].next = free; free = tmp;
loc == END
list 0 free 2 size 2
insert(mary);
색인 info next
0 john 2
1 Robert END
2 mary 1
3 null 4
4 null 5
5 null 6
6 null END
list 0 free 3 size 3
int tmp = nodes[free].next; nodes[free].info = item; nodes[free].next = loc; nodes[prevLoc].next = free; free = tmp;
색인 info next
0 john 1
1 Robert END
2 null 3
3 null 4
4 null 5
5 null 6
6 null END
list 0 free 3 size 3
insert(Bob);
색인 info next
0 john 2
1 Robert END
2 mary 1
3 Bob 0
4 null 5
5 null 6
6 null END
list 3 free 4 size 4
int tmp = nodes[free].next; nodes[free].info = item; nodes[free].next; = loc; list = free; free = tmp;
색인 info next
0 john 2
1 Robert END
2 mary 1
3 null 4
4 null 5
5 null 6
6 null END
prevLoc == END
list 3 free 4 size 4
delete(Mary);
색인 info next
0 John 1
1 Robert END
2 null 4
3 Bob 0
4 null 5
5 null 6
6 null END
list 3 free 2 size 3
nodes[prevLoc].next = nodes[loc].next; nodes[loc].info = null; nodes[loc].next; = free; free = loc;
색인 info next
0 John 2
1 Robert END
2 Mary 1
3 Bob 0
4 null 5
5 null 6
6 null END