: 원소들을 저장할 때 그 다음 원소가 있는 위치를 포함시키는 방식으로 저장


임의의 위치에 원소 추가/제거 구현
#include <iostream>
using namespace std;
const int MX = 1000005;
int dat[MX], pre[MX], nxt[MX];
int unused = 1; // 메모리 주소
void insert(int addr, int num){ // addr 뒤에 원소를 추가
dat[unused] = num;
pre[unused] = addr;
nxt[unused] = nxt[addr];
if(nxt[addr] != -1) pre[nxt[addr]] = unused; // 리스트의 마지막에 원소를 추가할 떄 예외처리 해줘야 함
nxt[addr] = unused;
unused++;
}
void erase(int addr){
nxt[pre[addr]] = nxt[addr];
if(nxt[addr] != -1) pre[nxt[addr]] = pre[addr]; // 리스트의 마지막 원소 제거할 때 예외처리 해줘야 함
}
void traverse(){
int cur = nxt[0];
while(cur != -1){
cout << dat[cur] << ' ';
cur = nxt[cur];
}
cout << "\n\n";
}
주의
1. erase은 제거한 다음 위치의 원소를 반환함
2. insert(cur, data)은 cur앞에 추가함 => dummy node가 마지막에 있음

i) STL 풀이
list의 dummy node가 마지막에 있음을 확인
#include <iostream>
#include <list>
using namespace std;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
list<char> l;
string s;
int m;
char cmd;
cin >> s >> m;
for(char c:s) {
l.push_back(c);
}
auto iter = l.end();
for(int i=0; i<m; i++) {
cin >> cmd;
if(cmd == 'P') {
char a;
cin >> a;
l.insert(iter, a); // iter앞에 원소를 추가함
}
else if(cmd == 'L') {
if(iter != l.begin()) iter--;
}
else if(cmd == 'D') {
if(iter != l.end()) iter++;
}
else {
if(iter != l.begin()) {
iter--;
iter = l.erase(iter);
}
}
}
for(auto e:l) { // 연결리스트 출력
cout << e;
}
}
ii) 직접 연결리스트 구현하여 풀이
list의 dummy node가 처음에 있음을 확인
#include <iostream>
using namespace std;
const int MX = 1000005;
char dat[MX];
int pre[MX];
int nxt[MX];
int unused = 1;
void insert(int addr, int num) { // addr뒤에 원소를 추가함 => dummy node가 맨 앞에 있음
dat[unused] = num;
pre[unused] = addr;
nxt[unused] = nxt[addr];
if(nxt[addr] != -1) pre[nxt[addr]] = unused;
nxt[addr] = unused;
unused++;
}
void erase(int addr) {
nxt[pre[addr]] = nxt[addr];
if(nxt[addr] != -1) pre[nxt[addr]] = pre[addr];
}
void traverse() {
int cur = nxt[0];
while(cur != -1) {
cout << dat[cur];
cur = nxt[cur];
}
cout << "\n";
}
int main() {
ios::sync_with_stdio(0);
cin.fill(0);
fill(pre, pre+MX, -1);
fill(nxt, nxt+MX, -1);
string s;
int m;
cin >> s >> m;
int cur = 0;
for(auto c : s) {
insert(cur, c);
cur++;
}
while(m--) {
char op;
cin >> op;
if(op == 'P') {
char add;
cin >> add;
insert(cur, add);
cur = nxt[cur];
}
else if(op == 'L') {
if(pre[cur] != -1) cur = pre[cur];
}
else if(op == 'D') {
if(nxt[cur] != -1) cur = nxt[cur];
}
else {
if(cur != 0) {
erase(cur);
cur = pre[cur];
}
}
}
traverse();
}

=> 동일한 노드가 나올때 까지 계속 다음 노드로 가면 된다. 공간복잡도(1), 시간복잡도(N)

=> 일단 두 시작점 각각에 대해 끝까지 진행시켜서 각각의 길이를 구한 뒤 다시 두 시작점으로 돌아와서 더 긴쪽을 차이만큼 앞으로 먼저 이동시킨 후, 두 시작점이 만날 때 까지 동시에 한 칸씩 이동시킴. 공간복잡도 O(1), 시간복잡,도 O(A+B)

=> Floyd's cycle-finding algorithm, 공간복잡도 O(1), 시간복잡도 O(N)