[Cracking the coding interview] 연결리스트
연결리스트의 문제는 가장 기초적인 것으로 연결리스트를 구현할수 있는가? 부터 시작해야합니다.
class Node {
Node next = null;
int data;
public Node(ind d){
data = d;
}
void appendToTail(int d){
Node end = new Node(d);
Node n = this;
while(n.next != null) {
n = n.next;
}
n.next = end;
}
}
기본 구현은 이러하다. 그리고 면접시 연결리스트에 대한 질문을 받을 때에는, 단방향 연결리스트인지, 양방향 연결리스트인지 확실히 해야한다.
단방향 연결리스트에서의 노드 삭제
연결리스트에서 노드를 삭제하는 연산은 직관적이다. 노드 n이 주어지면, 그 이전 노드 prev를 찾아 prev.next를 n.next와 같도록 설정한다.
리스트가 양방향 연결 리스트인 경우에는 n.next가 가리키는 노드를 갱신하여 n.next.prev가 n.prev와 같도록 설정해야 한다.
유의할점은
- Null포인터 검사를 반드시해야하고,
- 필요하다면 head와 tail포인터를 갱신해야 한다는 점이다.
Node deleteNode(Node head, int d){
Node n = head;
if(n.data == d) {
return head.next;
// head가 변경됨.
}
while(n.next != null) {
if (n.next.data == d) {
n.next = n.next.next;
return head;
}
n = n.next;
}
return head;
}
Runner 기법
“Runner”기법은 연결 리스트 문제에서 많이 활용 된다. 연결 리스트를 순회할 때 두개의 포인터를 동시에 사용
재귀 문제
재귀 호출 깊이가 n이 될 경우, 해당 재귀 알고리즘이 적어도 O(n)만큼의 공간을 필요로 할 것임은 기억하자. 모든 재귀 알고리즘은 반복적인 형태로도 구현될 수 있긴 허지만, 한층 복잡해진다.