본문 바로가기
학과공부/자료구조

Doubly Linked List와 Iterator

by 유시은 2020. 10. 26.
개요

노드의 sequence를 담은 자료구조.

 

더 일반화 된 List ADT를 구현할 수 있다.

 

 

DLL의 성질

각 노드는 이전 노드와 다음 노드에 대해 양방향으로 연결한다.

 

두 더미 노드 trailer, header를 활용하면 구현에 용이하다.

 

 

Node

SLL에 추가로 이전 노드의 주소를 가진다.

 

아래는 앞으로 사용할 노드의 예시이다.

 

struct Node {
    int data;
    Node* next;
    Node* prev;
}

 

Doubly Linked List

SLL보다 일반적인 함수 구현에 유리하다.

 

예를 들면, 다음과 같은 ADT를 구성할 수 있다.

 

struct DLL {
    Node* head;
    Node* tail;
    Iter it;
    
    void insert(Node* target, int e);
    void erase(Node* target);
}

 

Iterator

DLL에 대해 더 알아보기 전 iterator가 무엇인지 대강 알 필요가 있다.

 

정확한 내용은 여기에서 보자.

 

iterator는 position에 대한 ADT이고, "iterating over a collection of elements" 같은 일을 할 수 있다.

 

어떤 자료구조 V 가 iteratable 하다면, 다음과 같이 iterator it 를 이용해 모든 element에 접근할 수 있다.

 

for (it = V.begin(); it != V.end(); it = V.next())

 

여기서 { begin, end, next }는 Array-based implementation에선 { 0, n, i + 1 }, Linked List-based implementation에선 { header, trailer, next }이다.

 

앞으로 iterator를 줄여서 it으로 부르기로 하자.

 

 

Insertion

insert(e); it이 가리키는 노드 p 앞에 원소 e를 삽입하자.

 

다음과 같은 순서로 const time에 할 수 있다.

 

새 노드 N 할당 > N의 element 지정 > N의 prev, next가 각각 p의 이전 노드, p를 가리키게 함 > p의 이전 노드의 next, p의 prev가 N을 가리키게 함

 

아래는 구현 예시이다.

 

void insert(int e) {
    Node* newNode = new Node();
    Node *u = it.p->prev, *v = it.p; // 각각 p의 이전 노드, p
    newNode->data = e;
    newNode->prev = u; newNode->next = v;
    u->next = newNode; v->prev = newNode;
}

 

Deletion

delete(); it이 가리키는 노드 p를 삭제하자.

 

다음과 같은 순서로 const time에 할 수 있다.

 

p 이전 노드의 next, p 다음 노드의 prev가 각각 서로를 가리키게 함 > p 삭제

 

아래는 구현 예시이다.

 

void erase() {
    Node *u = it.p->prev, *v = it.p->next;
    delete it.p;
    u->next = v; v->prev = u;
    it.p = v;
}

 

Implementation

아래는 이론에서 배운 내용을 구현한 코드이다.

 

#include <bits/stdc++.h>
using namespace std;

/*

# Linked list-based implementation is shown below

# insert(e)		O(1)
# erase()		O(1)
# insert2(p, e)		O(n)
# size()		O(1)
# empty()		O(1)
# print()		O(n)

*/

struct Node {
	int data;
	Node* next;
	Node* prev;

	Node(int e) {
		data = e;
		next = nullptr;
		prev = nullptr;
	}
};
struct Iter {
	Node* p;
	Iter() { p = nullptr; }
	Iter(Node* ptr) { p = ptr; }
	int& operator *() {
		return p->data;
	}
	Iter& operator++() {
		p = p->next;
		return *this;
	}
	Iter& operator--() {
		p = p->prev;
		return *this;
	}
};

struct DLL {
	Node* head;
	Node* tail;
	Iter it;
	int sz;

	DLL() {
		head = new Node(0);
		tail = new Node(0);
		head->next = tail;
		tail->prev = head;
		it.p = tail;
		sz = 0;
	}
	~DLL() {

	}
	int size() {
		return sz;
	}
	bool empty() {
		return (size() == 0);
	}
	void insert(int e) {
		Node* newNode = new Node(e);
		Node* u = it.p->prev;
		Node* v = it.p;
		u->next = newNode; newNode->prev = u;
		newNode->next = v; v->prev = newNode;
		sz++;
	}
	void insert2(int p, int e) {
		Node* newNode = new Node(e);
		Iter i(head->next);
		for (; p-- > 0; ++i) if (!i.p->next) return;
		Node* u = i.p->prev;
		Node* v = i.p;
		u->next = newNode; newNode->prev = u;
		newNode->next = v; v->prev = newNode;
		sz++;
	}
	bool erase() {
		if (empty()) return false;
		Node* u = it.p->prev;
		Node* v = it.p->next;
		delete it.p;
		u->next = v; v->prev = u;
		it.p = v;
		sz--;
		return true;
	}
	void print() {
		if (empty()) {
			cout << "Empty\n"; return;
		}
		for (Iter i(head->next); i.p != tail; ++i) {
			cout << *i << " ";
		}
		cout << "\n";
	}
	void reversePrint() {
		if (empty()) {
			cout << "Empty\n"; return;
		}
		for (Iter i(tail->prev); i.p != head; --i) {
			cout << *i << " ";
		}
		cout << "\n";
	}

};

int main() {
	DLL A;
	int TEST; cin >> TEST; while (TEST--) {
		string oper; int p, q; cin >> oper;
		if (oper == "insert") {
			cin >> p; A.insert(p);
		}
		else if (oper == "insert2") {
			cin >> p >> q; A.insert2(p, q);
		}
		else if (oper == "erase") {
			cout << (A.erase() ? "" : "Empty\n");
		}
		else if (oper == "begin") {
			A.it.p = A.head->next;
		}
		else if (oper == "end") {
			A.it.p = A.tail;
		}
		else if (oper == "++") {
			++A.it;
		}
		else if (oper == "--") {
			--A.it;
		}
		else if (oper == "print") {
			A.print();
		}
		else if (oper == "reversePrint") {
			A.reversePrint();
		}
		else if (oper == "size") {
			cout << A.size() << "\n";
		}
	}
}

'학과공부 > 자료구조' 카테고리의 다른 글

Priority Queue  (0) 2020.12.03
Queue  (0) 2020.10.26
Stack  (0) 2020.10.26
Singly Linked List  (0) 2020.10.26
Array  (0) 2020.10.25

댓글