알고리즘 2주차
단순 연결리스트
- 데이터 삽입, 삭제가 유연하게 이루어지고 크기가 정해져 있지 않다.
- 구현은 노드를 이용하고 노드끼리 연결을 시켜 구현 한 것이다.
- 노드에는 데이터를 저장할 변수와 다음 노드와 연결 시켜주는 변수가 존재한다.
// 예제 코드
struct Node
{
int Data;
Node* Next;
}
노드 생성
노드를 동적 할당하여 생성하고 그 노드를 반환해준다.
// 예제 코드
void LinkedList::Push(T data)
{
Node* tmp = CreateNode(data);
if (Empty())
{
head = tmp;
tail = head;
}
else
{
tail->Next = tmp;
tail = tmp;
}
size++;
}
노드 탐색
연결 리스트는 배열과 다르게 인덱스로 바로 접근하지 못하고 순차 탐색을 진행해야 한다.
// 예제 코드
LinkedList::Node* LinkedList::GetNode(int idx)
{
Node* current = head;
int count = 0;
while (count < idx)
{
current = current->Next;
count += 1;
}
return current;
}
노드 삽입
새로운 노드를 헤드일 경우의 삽입과 중간 위치의 삽입을 구분한다.
// 예제 코드
void LinkedList::Insert(int index, T data)
{
int count = 0;
Node* current = head;
Node* newNode = CreateNode(data);
Node* currentParent = NULL;
// 헤드일 경우
if (index == 0)
{
// 새로운 노드를 head 노드에 연결시켜준다.
newNode->Next = current;
// 헤드 노드에 새로운 노드로 넘겨준다.
head = newNode;
size++;
return;
}
// 중간일 경우
while (count < index)
{
currentParent = current; // index의 바로 앞 노드
current = current->Next; // index에 위치한 노드
count++;
}
currentParent->Next = newNode;
newNode->Next = current;
size++;
}
노드 삭제
삭제노드가 헤드일 때, 테일일 때, 중간에 위치해 있을 때를 구분한다.
void Remove(int index)
{
Node* remove = GetNode(index);
// 헤드를 삭제해야하기 떄문에 헤드를 다음으로 넘겨준다.
if (head == remove)
{
head = head->Next;
delete remove;
}
else
{
if (tail == remove)
{
Node* cur = head;
// 테일 노드의 전까지 탐색 노드를 이동시킨다.
while (cur->Next != tail) // tail 바로 전에 멈춤
{
cur = cur->Next;
}
// 테일 노드를 테일 노드의 전 노드로 넘겨주기
tail = cur;
tail->Next = NULL;
delete remove;
}
else
{
Node* cur = head;
// 삭제 노드 전까지 탐색 노드를 이동시키기
while (cur->Next != remove) // 삭제 노드 바로 전에 멈춤
{
cur = cur->Next;
}
//삭제 노드 전의 연결을 삭제 노드의 다음 노드에 연결시킨다.
cur->Next = remove->Next;
delete remove;
}
}
size--;
}
이중 연결리스트
- 단순 연결 리스트와 다르게 자신의 앞 노드를 연결시켜주는 변수가 존재한다.
- 자신의 뒤 노드와도 연결 되어 있기에 양방향 탐색이 가능해진다.
노드 추가
단순 연결리스트와 차이점은 양방향으로 연결시켜주는 과정이 필요하다.
void Push(T data)
{
Node* newNode = CreateNode(data);
if(Empty())
{
head = newNode;
tail = head;
}
else
{
// 현재 테일이 가르키고 있는 노드의 다음 노드로 연결한다.
tail->Next = newNode;
// 새로 추가한 노드의 앞 노드를 현재 테일이 가르키고 있는 노드로 한다.
newNode->Prev = tail;
// 새로 추가한 노드를 테일 노드로 가르킨다.
tail = newNode;
}
size++;
}
노드 삽입
마찬가지로 양방향으로 연결시켜주는 과정이 필요하다.
void Insert(int index, T data)
{
Node* current = GetNode(index);
Node* nNode = CreateNode(data);
if (current == head)
{
nNode->Next = head;
head->Prev = nNode;
head = nNode;
}
else
{
current->Prev->Next = nNode;
nNode->Prev = current->Prev;
nNode->Next = current;
current->Prev = nNode;
}
size++;
}
노드 삭제
삭제노드가 헤드일 때, 테일일 때, 중간에 위치해 있을 때를 구분한다.
void Remove(int index)
{
Node* remove = GetNode(index);
if (head == remove)
{
head = head->Next;
head->Prev = NULL;
delete remove;
}
else
{
if (remove == tail)
{
tail = tail->Prev;
tail->Next = NULL;
delete remove;
}
else
{
remove->Prev->Next = remove->Next;
remove->Next->Prev = remove->Prev;
delete remove;
}
}
size--;
}
STL
list
-
시퀀스 컨테이너의 일종으로 순서를 유지하는 구조이다.
-
이중 연결 리스트로 구현되어 있다.
-
노드 기반 컨테이너이다.
-
원소를 접근할때 [],at 접근이 불가능하다
-
반복자(iterator)를 사용해 데이터에 접근, 조작이 가능하다.
-
사용하려면
- 헤더파일을 include 시켜야한다.
- 삽입과 삭제가 자주 발생하는 경우에 사용하는 것이 적합하다.
- 요소에 접근하거나 탐색이 자주 발생하는 경우에는 적합하지 않다.
생성자 종류와 선언
list<int> li;
list<float> li2(10);
list<char> li3(10, 'a');
list<char> li4(li3);
list<char> li5(li4.begin(), li4.end());
li.push_back(3);
li.push_back(4);
li.push_back(6);
li.emplace_back(5);
// 비주얼 어시스턴스
for (auto it : li) // 편리하기 한데 확실할 때만 사용
{
cout << it << endl;
}
for (list<int>::iterator iter = li.begin(); iter != li.end(); iter++)
{
cout << *iter << endl;
}
//결과값
3
4
6
5
3
4
6
5
맴버 함수 모음
vector
-
시퀀스 컨테이너의 일종으로 배열과 비슷하고 동적 배열 기반의 컨테이너이며 크기가 자동으로 조정된다.
-
Random Access Iterator를 지원하는 배열기반 컨테이너이다. 그렇기에 배열처럼 [] 인덱스 연산을 통해 데이터에 접근이 가능하다.
-
요소들은 메모리에 연속적으로 저장되기에 메모리 중간에 삽입,삭제가 일어나게되면 그 위치부터 모든 배열을 뒤로 미루거나 앞으로 당겨서 메모리를 재할당하는 문제가 생긴다.
-
사용하려면 < vector > 헤더파일을 include 시켜야한다.
-
리스트와 다르게 인덱스 연산이 가능하기에 요소에 대한 접근이 자주 일어나는 경우에 효율적이다.
생성자 종류와 선언
vector<int> v;
vector<float> v1(10);
vector<char> v2(10, 'a');
vector<char> v3(v2);
vector<char> v4(v3.begin(), v3.end());
vector<char> v4(v3.begin() + 5, v3.end() - 4); // 이런 식으로도 접근 가능
// 예시 코드
vector<int> v1;
v1.reserve(10); // 공간 만들어 줌
v1.emplace_back(3);
v1.emplace_back(4);
v1.emplace_back(6);
cout << v1[0] << endl;
cout << v1.capacity() << endl; // 다시 크기 줄여줌
cout << v1.size() << endl;
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << endl;
}
// 결과값
3
10
3
3
4
6
맴버 함수 모음
댓글남기기