알고리즘/알고리즘 공부
2. 연결리스트 문제 해법
Heony
2021. 12. 8. 14:28
▶ 중복 없애기
정렬되어 있지 않은 연결리스트가 주어졌을 때 이 리스트에서 중복되는 원소를 제거하는 코드를 작성하라.
필자는 Node 클래스를 따로 제작하여 이 문제를 풀기로 했다.
class Node {
int data;
Node next = null;
Node(int d) {
data = d;
}
//node 추가
void append(int d) {
Node end = new Node(d);
Node n = this;
while(n.next != null) {
n = n.next;
}
n.next = end;
}
}
다음은 중복을 없애기 위해 node 클래스 안에 원소들을 추적하여 없애는 방법을 선택했다.
prev는 앞서 설명했던 것 처럼 단방향일때 해당 지워야 하는 원소값을 찾을 경우 이전 노드와 다음 노드를 연결시키기만 해주면 된다.
void deleteDups(Node n) {
// HashSet 제작, set은 중복을 없앨 수 있다.
Set s = new HashSet();
// prev는 삭제해야 할 노드를 찾았을 때 이전 노드와 다음 노드를 이어주기 위한 변수이다.
Node prev = null;
// 다음 노드가 null이 아니면 실행
while(n.next != null) {
// s안에 n의 데이터가 포함되어 있는지 여부 파악
// 데이터가 포함되어 있을 경우 해당 값은 중복이므로 삭제시킬 수 있음(건너뛸 수 있음)
// 데이터가 포함되어 있지 않을 경우 해당 값은 이전에 나오지 않은 값이므로 set에 저장
if(s.contains(n.data)) {
//이전과 다음을 이어줌으로써 중간 노드를 없앰
prev.next = n.next;
} else {
s.add(n.data);
prev = n;
}
n = n.next;
}
}
▶ 뒤에서 k번째 원소 구하기
단방향 연결리스트가 주어졌을 때 뒤에서 k번째 원소를 찾는 알고리즘을 구현하라.
연결리스트의 길이를 아는 경우 맨 마지막 원소에서 k번째 원소는 length - k번째 원소가 되므로 단순히 연결리스트를 순회해서 이 원소를 찾으면 된다. 하지만 우리가 하는 것은 '연결리스트의 길이'를 모르는 경우이다.
책에서는 재귀적 방법으로 풀었지만, 내가 하는 방법을 우선적으로 소개하고, 책에서 자온 재귀적 방법을 소개하도록 하겠다.
int kThFromBehind(int k) {
// head에 대한 객체를 저장한다.
Node head = this;
// n은 앞으로 k번째를 찾기 위해 값이 계속 변경될 객체이다.
Node n = head;
// count는 length와 같은 의미로 설계했다.
int count = 0;
// n이 null이 아닐 경우 노드의 연결형태로 계속 이어나가면서 count를 증가시킨다.
while(n != null) {
count++;
n = n.next;
}
// 총 count에서 k만큼, 즉 뒤에서 k만큼 까지를 head에서부터 이동시킨다.
for(int i = 0; i < count - k; i++) {
head = head.next;
}
// head가 가리키고 있는 data를 반환한다.
// 여기서 head는 실제 head가 아닌 뒤에서 k만큼 이동한 값이다.
return head.data;
}
책에서 나온 재귀적 방법을 소개한다.
int printkThToLast(LinkedListNode head, int k) {
// head가 null이면 return한다.
if(head == null) {
return 0;
}
// 재귀적 방법을 사용했다.
// head의 다음 값과 k값을 넘기고 맨 마지막 호출되는 return 값은 0이다.
// 계속 1씩 증가시키면서 결국 k와 같게 될 때 호출되고 index를 반환함으로써
// if구문과 상관없게 만든다.
int index = printKthToLast(head.next, k) + 1;
if(index == k) {
System.out.println(k + "th to last node is " + head.data);
}
return index;
}
728x90