LinkedList(2) - ADT와 구현
1 . ADT
- 단순하게 데이터가 한쪽 방향으로 저장되고, 시작과 끝이 분명한 LinkedList를 구현해 보도록 하자.
- 더미노드 기반으로 head만 존재한다.
- ADT는 배열기반 연결리스트와 크게 차이가 없다. (정렬 추가)
void Listinit(List * plist) > 리스트 초기화
void LInsert(List* plist, Ldata data) >리스트에 데이터를 추가
int LFirst(List* plist, Ldata* data) > 리스트에 저장된 데이터 참조를 위함
int LNext(List* plist, Ldata* data) > 리스트 저장된 데이터 참조
Ldata Lremove(List* plist) >리스트에 저장된 데이터 삭제
int Lcount(List* plist) >리스트 길이 return
void SetSortRule(List * plist, int (*comp)(Ldata d1, Ldata d2)) > 정렬을 위해
*한 쪽방향으로만 데이터를 추가할 것이므로, tail은 필요없고, dummy노드를 두는 이유는 삭제 및 조회의 과정을 일관된 형태로 구성하기 위함이다.
2. 추가,삭제,조회의 과정 살펴보기
> 더미노드로 linkedList를 구현하면 다음 그림과 같다.
2.1 추가
새 노드를 추가하면, newnode의 next가 기존의 노드를 가리키도록 하고, dummy노드인 head의 next가 new node를 가리키도록 이어주면 된다.
2.2 삭제
삭제할 노드를 찾고, 그 전의 노드의 next를 후의 노드에 연결한 뒤 노드를 삭제하는 과정을 거친다.
3. 구현
dummy Linked List.h
dummy Linked List .c
dummy Linked List main.c
>LSInsert와 SetSortRule함수
외부에서 주어진 정렬기준 함수를 SetSortRule에 전달하고, 이를 comp에 저장해서, 이를 근거로 LSInsert를 작동시킨다.
void LSInsert(List* plist, Ldata data){
Node* newnode = (Node*)malloc(sizeof(Node));
Node* pred = plist->head;
newnode->data =data;
while(pred->next != NULL && plist->comp(data,plist->next->data) != 0)
pred =pred->next;
}
newnode->next = pred->next;
pred->next = newnode;
(plist->size)++;
}
> pred는 head부터 시작해서 (pred왼쪽에는 데이터를 추가할 수 없으므로 맨 끝에 위치한 dummy부터 시작)
while문의 조건을 확인하며 옆으로 한칸 한칸 움직인다.
(pred->next == null (끝 의미), plist->comp(data,pred->next->data) == 0 임의로 정한 정렬 기준에 부합)
> 정렬기준이 되는 함수는 main에서 정의해서 list를 초기화한 뒤에 넣어준다.
class LinkedListD<T> {
Node<T> head = new Node<>();
Node<T> cur = new Node<>();
Node<T> before = new Node<>();
int size=0;
boolean sort;
Comparator comp;
private class Node<T> { //LinkedListD가 생성되면 이에 맞춰 알아서 결정됨
private T data;
private Node next;
}
void NInsert(T n){
Node<T> newnode = new Node<>();
newnode.data = n;
newnode.next = head.next;
head.next=newnode;
this.size ++;
}
void SInsert(T n){
Node<T> newnode = new Node<>();
newnode.data = n;
Node<T> pred = head;
while(pred.next != null && comp.compare(n,pred.next.data) != 0){
pred = pred.next;
}
newnode.next = pred.next;
pred.next = newnode;
this.size++;
}
void Insert(T n){
if(sort == true){
SInsert(n);
}else NInsert(n);
}
boolean LFirst(){
if(head.next == null) {
System.out.print("조회할 데이터 없음");
return false;
}
cur = head.next;
before=head;
return true;
}
boolean Lnext(){
if(cur.next == null){
return false;
}
before = cur;
cur = cur.next;
return true;
}
T peek(){
return cur.data;
}
void setSort(){
this.sort = true;
this.comp = new Desending<T>();
}
void setSort(Comparator<T> comp){
this.sort = true;
this.comp = comp;
}
int size(){return this.size;}
T Lremove(){
T Rdata = cur.data;
before.next = cur.next;
cur = before;
return Rdata;
}
//기본 정렬 기준
class Desending<T> implements Comparator<T> {
@Override
public int compare(T o1, T o2) {
if (o1 instanceof Number && o2 instanceof Number) {
int ob1 = (Integer) o1;
int ob2 = (Integer) o2;
if (ob1 > ob2) return 0;
else return 1;
} else if (o1 instanceof String && o2 instanceof String) {
return ((String) o1).compareTo((String) o2) * -1;
}
return 0;
}
}
}
참고자료: 윤성우 열혈자료구조