computer_science/data_structure
[자료구조] 02. 선형 리스트 (배열)
렁치
2026. 7. 17. 12:30
선형 리스트는 원소들이 순서를 가지고 1:1 관계로 나열된 자료구조다. 배열로 구현한 선형 리스트는 메모리에 원소가 연속으로 저장되므로 인덱스 접근이 빠르다.
1. 배열 리스트의 특징
| 항목 | 내용 |
|---|---|
| 저장 방식 | 연속된 메모리 공간에 저장 |
| 접근 | iArray[iIndex]로 O(1) 접근 |
| 삽입 | 삽입 위치 뒤쪽 원소들을 한 칸씩 뒤로 이동 |
| 삭제 | 삭제 위치 뒤쪽 원소들을 한 칸씩 앞으로 이동 |
| 단점 | 크기를 미리 정해야 하고 중간 삽입/삭제가 느림 |
배열 리스트의 핵심은 논리적 순서와 물리적 저장 순서가 같다는 점이다. 그래서 0번, 1번, 2번처럼 바로 접근할 수 있지만, 중간에 값을 넣거나 빼면 뒤쪽 원소들이 움직여야 한다.
2. 삽입 연산
예를 들어 {10, 20, 30, 40}의 1번 위치에 15를 넣으려면, 기존 20, 30, 40을 오른쪽으로 한 칸씩 밀어야 한다.
| 단계 | 배열 상태 |
|---|---|
| 시작 | 10 20 30 40 |
| 40 이동 | 10 20 30 40 40 |
| 30 이동 | 10 20 30 30 40 |
| 20 이동 | 10 20 20 30 40 |
| 15 삽입 | 10 15 20 30 40 |
삽입은 뒤쪽 값부터 움직여야 한다. 앞에서부터 움직이면 아직 복사하지 않은 값을 덮어쓸 수 있다.
#include <stdio.h>
#define MAX_SIZE 100
int insertValue(int iArray[], int iCount, int iPosition, int iValue)
{
int iMoveIndex;
if (iCount >= MAX_SIZE)
{
printf("overflow\n");
return iCount;
}
if (iPosition < 0 || iPosition > iCount)
{
printf("wrong position\n");
return iCount;
}
iMoveIndex = iCount;
while (iPosition < iMoveIndex)
{
iArray[iMoveIndex] = iArray[iMoveIndex - 1];
iMoveIndex = iMoveIndex - 1;
}
iArray[iPosition] = iValue;
iCount = iCount + 1;
return iCount;
}
3. 삭제 연산
삭제는 삽입과 반대로 뒤쪽 원소를 앞으로 당긴다. {10, 15, 20, 30, 40}에서 1번 위치의 15를 삭제하면 20, 30, 40이 왼쪽으로 한 칸씩 이동한다.
int deleteValue(int iArray[], int iCount, int iPosition)
{
int iMoveIndex;
if (iPosition < 0 || iPosition >= iCount)
{
printf("wrong position\n");
return iCount;
}
iMoveIndex = iPosition;
while (iMoveIndex < iCount - 1)
{
iArray[iMoveIndex] = iArray[iMoveIndex + 1];
iMoveIndex = iMoveIndex + 1;
}
iCount = iCount - 1;
return iCount;
}
4. 출력 함수
자료구조 예제는 연산 후 상태를 확인하는 출력 함수가 있으면 디버깅하기 쉽다.
void printArrayList(int iArray[], int iCount)
{
int iIndex;
for (iIndex = 0; iIndex < iCount; iIndex++)
{
printf("%d ", iArray[iIndex]);
}
printf("\n");
}
5. C++ 구현 예제: vector
C에서는 배열 크기와 현재 개수 iCount를 직접 관리해야 한다. C++에서는 vector가 내부 배열 크기를 자동으로 관리해 준다. 그래도 중간 삽입과 삭제 때 뒤쪽 원소가 이동한다는 원리는 같다.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vNumbers;
int iIndex;
vNumbers.push_back(10);
vNumbers.push_back(20);
vNumbers.push_back(30);
vNumbers.push_back(40);
vNumbers.insert(vNumbers.begin() + 1, 15);
vNumbers.erase(vNumbers.begin() + 3);
for (iIndex = 0; iIndex < (int)vNumbers.size(); iIndex++)
{
cout << vNumbers[iIndex] << " ";
}
cout << endl;
return 0;
}
vector는 인덱스 접근이 빠르다는 점에서 배열 리스트와 같은 성격을 가진다. 다만 insert, erase를 중간에서 사용하면 C 구현처럼 뒤쪽 원소가 이동하므로 O(n) 비용이 든다.
6. 정리
- 배열 리스트는 인덱스 접근이 빠르다.
- 중간 삽입은 뒤에서 앞으로 밀어야 한다.
- 중간 삭제는 앞에서 뒤로 당겨야 한다.
- 삽입/삭제의 최악 시간복잡도는 O(n)이다.
- C 구현에서는 배열 크기와 현재 원소 개수
iCount를 반드시 따로 관리한다.