내용
데이터를 한 줄로 순차적으로 표현한 형태 --> 선형 리스트 , 연결 리스트 , 원형 연결 리스트 , 스택 , 큐
오버헤드 발생 : 리스크가 큰 데이터일 때 , 무언가를 삽입 혹은 삭제하는 과정에서 많은 일이 발생
카톡 온 순서대로 데이터를 선형 리스트로 표현
## 함수 선언부
def add_data(friend): # katok 배열에 friend 추가
katok.append(None) #배열 맨 뒤에 빈칸 추가
kLen = len(katok)
katok[kLen-1] = friend # (배열 길이 - 1) 위치에 데이터 삽입
def insert_data(position , friend): #katok 배열 내 원하는 position에 friend 추가
katok.append(None)
kLen = len(katok) #position에 friend가 들어가도록 배열을 한칸씩 이동해줘야함
for i in range(kLen-1 , position , -1):
katok[i] = katok[i-1]
katok[i-1] = None #옮긴 변수는 None으로 빈칸으로 만들어줌
katok[position] = friend
def delete_data(position):
katok[position] = None #빈칸으로 처리
kLen = len(katok)
for i in range(position+1, kLen , 1): #삭제한 position 뒤부터니까 position+1
katok[i-1]=katok[i]
katok[i]=None
del(katok[kLen-1]) #칸 자체를 삭제
## 전역 변수부
katok = []
select = -1
## 메인 코드 부분
if __name__ =='__main__':
while(select!=4):
select = int(input('선택하세요(1:추가 , 2:삽입 , 3:삭제 , 4:종료) -->'))
if select == 1:
data= input("추가할 데이터 -->")
add_data(data)
print(katok)
elif select ==2:
pos = int(input('삽입할 위치 -->'))
data = input('추가할 데이터 -->')
insert_data(pos,data)
print(katok)
elif select ==3 :
pos = int(input('삭제할 위치 -->'))
delete_data(pos)
print(katok)
elif select ==4:
print(katok)
exit
else:
print('1~4 중 하나를 입력하세요.')
continue
노드는 데이터와 링크로 구성된 항목이다.
head : 가장 앞의 노드의 값(주소값)을 가지고 있다.
current : 현재 작업하고 있는 노드의 값을 가지고 있다.
pre : 현재 작업 중인 노드의 앞 노드값을 가지고 있다.
단순 연결 리스트를 통한 데이터 추가/삽입/삭제
## 함수
class Node() :
def __init__(self):
self.data = None
self.link = None
## 전역
## 메인
node1 = Node()
node1.data = 'A'
node2 = Node()
node2.data = 'B'
node1.link = node2 #node1의 link는 node를 가리킴
node3 = Node()
node3.data = 'C'
node2.link = node3
node4 = Node()
node4.data = 'D'
node3.link = node4
node5 = Node()
node5.data = 'E'
node4.link = node5
# 다른 예시
# print(node1.data , end= ' ')
# print(node1.link.data , end = ' ')
# print(node1.link.link.data , end = ' ')
# print(node1.link.link.link.data , end = ' ')
# print(node1.link.link.link.link.data , end = ' ')
# 중간에 데이터 삽입
newNode = Node()
newNode.data = '홍길동'
newNode.link = node2.link
node2.link = newNode
# 중간 데이터 삭제
node2.link = node3.link
del(node3)
# link가 None이면 출력 그만 , 계속 연결해서 출력하는 방법
current = node1
print(current.data , end= ' ')
while current.link != None:
current = current.link # 계속 그 다음 노드로 이동
print(current.data, end=' ')
단순 연결 리스트를 통한 데이터 추가/삽입/삭제 (함수 이용)
## 함수
class Node() :
def __init__(self):
self.data = None
self.link = None
def printNodes(start): #출력하는 함수
current = start
print(current.data , end = ' ')
while current.link != None:
current = current.link
print(current.dat , end = ' ')
print()
# head 변경 : 첫 번째 노드 삽입
def insertNode(findData , insertData):
global memory , head , current , pre
# 첫번째 노드 앞에 삽입할 경우
if findData == head.data:
node = Node()
node.data = insertData
node.link = head
head = node
return
# 두번째 노드 이후 삽입 (중간 노드 삽입)
current = head # 첫번째부터 변경시작을 위해 변수 선언
while current.link != None:
pre = current #current가 다음 link로 가기 전에 pre에 저장
current = current.link
if current.data == findData:
node = Node()
node.data = insertData
node.link = current #node는 current에 연결
pre.link = node #pre는 node에 연결
return
# findData가 없는 경우 맨 뒤에 삽입
node = Node()
node.data = insertData
current.link = node
return
# 노드 삭제하기
def deleteNode(deleteData):
global memory , head , current , pre
# 첫 노드 삭제 시
if deleteData == head.data :
current = head
head = head.link #head 다음 변수를 head로 지정
del(current)
return
# 두 번째 이후 노드 삭제 시
current = head
while current.link!=None:
pre = current
current = current.link
if current.data == deleteData:
pre.link = current.link
del(current)
return
# 노드 검색하기
def findNode(findData):
global memory , head , current , pre
current = head
if current.data == findData:
return current
while current.link!=None:
current = current.link
if current.data == findData:
return current
return Node() # 못 찾았을 경우 빈 노드 return
## 전역
memory = []
head , current , pre = None , None , None , None
dataArray = ['홍길동' , '이순신' , '사오정' , '손오공' , '강감찬']
## 메인
node = Node()
node.data = dataArray[0]
head = node # 첫 번째 변수를 head로 지정
memory.append(node) # 홍길동
for data in dataArray[1:] : # ['이순신' , '사오정' , '손오공' , '강감찬']
pre = node
node = Node() #새로운 node class를 생성하기 전에 pre 라는 변수에 저장
node.data = data
pre.link = node
memory.append(node)
스택의 간단 구현
## 함수
## 전역
SIZE = 5
stack = [None for _ in range(SIZE)]
top = -1 #초기값
## 메인
# PUSH
top+=1
stack[top] = '커피'
top+=1
stack[top] = '녹차'
top+=1
stack[top] = '꿀물'
print(stack)
# POP
data = stack[top]
stack[top] = None
top-=1
print(stack)
data = stack[top]
stack[top] = None
top-=1
print(stack)
data = stack[top]
stack[top] = None
top-=1
print(stack)
스택 구현(함수 이용)
## 함수
def isStackFull(): #stack이 꽉차있는지 확인하는 함수
global SIZE , stack , top
if (top-1)>=SIZE: #꽉 찬 경우
return True
else :
return False
def push(data):
global SIZE , stack , top
if isStackFull() : #True일 경우(꽉 찬 경우)
print('스택이 꽉 찼습니다.')
return # 꽉 찬 경우 그냥 return
top+=1
stack[top]=data #stack의 top 부분에 data 삽입
def isStackEmpty():
global SIZE , stack , top
if (top<=-1):
return True
else:
return False
def pop():
global SIZE , stack , top
if isStackEmpty:
print('스택이 비었습니다.')
return None #일관성을 위해 None을 씀
data = stack[top]
stack[top] = None
top-=1
return data
def peek():#검색 기능
global SIZE , stack , top
if isStackEmpty:
print('스택이 비었습니다.')
return None
return stack[top]
## 전역
SIZE = 5
stack = [None for _ in range(SIZE)]
top = -1 # 초기값
## 메인
push('커피1')
push('커피2')
print(stack)
print('다음 예정' , peek())
retrData = pop()
print('pop()-->' , retrData)
큐의 간단 구현
#front와 rear가 같으면 que가 비어있다고 봄
## 함수
## 전역
SIZE = 5
queue = [None for _ in range(SIZE)]
front = rear = -1 #초깃값으로 -1을 설정
## 메인
# eqQueue : 데이터 삽입 : 꼬리를 한칸 증가시키고, 꼬리 자리에 데이터삽입
rear +=1
queue[rear]='화사' #rear ==0
rear +=1
queue[rear]='솔라' # rear == 1
rear +=1
queue[rear]='문별' # rear == 2
print('출구<---' , queue , '<---입구')
#deQueue : 데이터 추출 : 머리를 하나 증가시키고 머리에 있는 애를 내보낸다.
front+=1
data = queue[front] # front == 0
queue[front] = None
print('손님 : ' , data)
front+=1
data = queue[front] # front == 1
queue[front] = None
print('손님 : ' , data)
front+=1
data = queue[front] # front == 2
queue[front] = None
print('손님 : ' , data)
print('출구<---' , queue , '<---입구')
큐 구현(함수 이용)
## 함수
def isQueueFull() : #queue가 꽉 차 있는가?
global SIZE, queue, front, rear
if (rear == SIZE-1) : #rear 가 queue의 SIZE -1이면 꽉 차 있다.
return True
else :
return False
def enQueue(data) :
global SIZE, queue, front, rear
if (isQueueFull()) :
print('큐 꽉!')
return
rear += 1 # rear값 1 증가
queue[rear] = data
def isQueueEmpty() :
global SIZE, queue, front, rear
if (front == rear) : #front와 rear 값이 같으면 비어있다.
return True
else :
return False
def deQueue() :
global SIZE, queue, front, rear
if (isQueueEmpty()) :
print('큐 텅~')
return None
front += 1 # front값을 1 증가
data = queue[front]
queue[front] = None
return data
def peek() :
global SIZE, queue, front, rear
if (isQueueEmpty()):
print('큐 텅~')
return None
return queue[front+1]
## 전역
SIZE = 5
queue = [ None for _ in range(SIZE)]
front = rear = -1
## 메인
enQueue('화사')
enQueue('솔라')
# enQueue('문별')
# enQueue('선미')
# enQueue('재남')
# print('출구<---', queue , '<--입구')
# enQueue('아이유')
# print('출구<---', queue , '<--입구')
print('출구<---', queue , '<--입구')
print('밥 손님:', deQueue())
print('다음 손님... 준비 : ', peek())
print('밥 손님:', deQueue())
print('출구<---', queue , '<--입구')
print('밥 손님:', deQueue())
큐의 기능 통합 버전
=> 다음과 같이 front , rear의 위치를 이동하는 경우 오버헤드가 발생한다.
## rear = SIZE-1 의 경우 큐가 꽉 찼다고 가정했었다.
## 그러나 (rear = SIZE-1) and (front!=-1) 의 경우 앞쪽에 여유가 있어도 큐가 꽉 찼다고 표현된다.
## 1. front+1 위치부터 rear 위치까지 왼쪽으로 한 칸씩 이동시킨다.
## 2. front 값에서 1을 뺀다.
## 3. rear 값에서 1을 뺀다.
def isQueueFull() :
global SIZE, queue, front, rear
if (rear!=SIZE-1):
return False
elif (rear ==SIZE-1) and (front == -1): ##진짜 꽉찬경우
return True
else:
for i in range(front,+1,SIZE):
queue[i-1]=queue[i]
queue[i]=None
front-=1
rear -=1
return False
def isQueueEmpty() :
global SIZE, queue, front, rear
if (front == rear) :
return True
else :
return False
def isQueueFull() :
global SIZE, queue, front, rear
if ( (rear+1) % SIZE == front) :
return True
else :
return False
def enQueue(data) :
global SIZE, queue, front, rear
if (isQueueFull()) :
print('큐 꽉!')
return
rear = (rear + 1) % SIZE
queue[rear] = data
def deQueue() :
global SIZE, queue, front, rear
if (isQueueEmpty()) :
print('큐 텅~')
return None
front= (front+1) % SIZE
data = queue[front]
queue[front] = None
return data
def peek() :
global SIZE, queue, front, rear
if (isQueueEmpty()):
print('큐 텅~')
return None
return queue[(front+1) % SIZE]
## 전역
SIZE = 5
queue = [ None for _ in range(SIZE)]
front = rear = 0
## 메인
enQueue('길동')
enQueue('세종')
enQueue('순신')
enQueue('민호')
enQueue('파이썬')
print('출구<---', queue , '<--입구')
print('밥 손님:', deQueue())
print('밥 손님:', deQueue())
print('출구<---', queue , '<--입구')
enQueue('넘파이')
print('출구<---', queue , '<--입구')
enQueue('판다스')
print('출구<---', queue , '<--입구')
하나의 데이터 뒤에 여러 데이터가 이어지는 형태 -> 트리 , 그래프
회사 사장을 필두로 그 아래 직책이 구성되어 있는 조직표
컴퓨터의 상위 폴더 안에 하위 폴더가 계속 이어지는 구조
나무를 거꾸로 뒤집어 놓은 형태와 비슷해 Tree라고 부름
이진 트리(*)를 가장 많이 사용한다.
맨 위의 노드 : root
하위 노드를 갖는 노드 : 부모 노드
하위 노드 : 자식 노드
연결 선 : 에지
자식의 개수 : 차수
차수가 0인 노드 : 리프 노드 (자식이 없는 마지막 노드)
모든 노드의 자식이 최대 2개인 트리를 이진 트리라고 부른다. (자식이 2개 이하로 구성)
루트 입장에서 좌측 자식의 트리를 왼쪽 서브트리, 우측 자식의 트리를 오른쪽 서브트리라 부른다.
번호를 메길 땐 위에서 왼쪽으로 숫자를 메김. 자리가 비어있어도 번호는 가져간다.
포화 이진 트리 : 꽉 찬 이진 트리
완전 이진 트리 : 조금 비어있지만, 번호는 빈 번호가 없어야 한다.
일반 이진 트리 : 조금 비어있고, 빈 번호도 존재하는 트리
평향 이진 트리 : 좌측 혹은 우측으로만 에지가 뻗어있는 트리
이진 트리의 기본 구조
## 함수
class TreeNode() :
def __init__(self):
self.left = None
self.data = None
self.right = None
## 전역
## 메인
node1 = TreeNode()
node1.data = '화사'
node2 = TreeNode()
node2.data = '솔라'
node1.left = node2
node3 = TreeNode()
node3.data = '문별'
node1.right = node3
node4 = TreeNode()
node4.data = '휘인'
node2.left = node4
node5 = TreeNode()
node5.data = '쯔위'
node2.right = node5
node6 = TreeNode()
node6.data = '선미'
node3.left = node6
print(node1.data)
print(node1.left.data , node1.right.data)
print(node1.left.left.data , node1.left.right.data , node1.right.left.data)
이진 트리 구현(함수 이용 + 검색 기능)
## 함수
class TreeNode() :
def __init__(self):
self.left = None
self.data = None
self.right = None
## 전역변수
memory = []
root = None
nameAry = ['블랙핑크' , '레드벨벳' , '마마무' , '에이핑크' , '걸스데이' , '트와이스']
## 메인
# 첫 노드 생성(=루트 노드)
node = TreeNode()
node.data = nameAry[0] # 블랙핑크를 node.data로 설정
root = node #root를 node로 설정
memory.append(node) # 빈 메모리에 node를 삽입
for name in nameAry[1:] : #['레드벨벳' , '마마무' , '에이핑크' , '걸스데이' , '트와이스']
node = TreeNode()
node.data = name #node.data에 nameAry의 원소를 하나씩 삽입
current = root #시작점 current
while True: #depth가 엄청 깊은것을 감안해서 while문 사용
if name < current.data : #루트 보다 크기가 작을 경우
if current.left ==None: #좌측 노드가 비어 있을 경우 좌측 노드에 삽입
current.left = node
break
current = current.left # current를 current.left의 주소로 변환
else: # 우측 노드가 비어 있을 경우 우측 노드에 삽입
if current.right == None: #우측 노드가 비어 있을 경우 우측 노드에 삽입
current.right = node
break
current = current.right # current를 current.right의 주소로 변환
memory.append(node)
print('이진 탐색 트리 완료')
# 이진탐색 트리에서 데이터 검색
findData = '마마무'
current = root
while True : #언제 끝날지 불명확할때 while True를 사용
if current.data == findData:
print(findData , '찾았습니다')
break
elif current.data > findData:
if current.left == None : #값이 없을 경우
print(findData, '이 트리에 없음')
break
current=current.left
else :
if current.right ==None:
print(findData, '이 트리에 없음')
break
current = current.right
무방향 그래프의 간단 구현
=> 무방향 그래프의 인접 행렬은 대각선을 기준으로 서로 대칭된다.
## 함수
class Graph() :
def __init__(self,size):
self.SIZE = size
self.graph = [ [0 for _ in range(size)] for _ in range(size)]
## 전역
G = None
## 메인
G = Graph(4)
G.graph[0][1] = 1; G.graph[0][2] = 1; G.graph[0][3] = 1
G.graph[1][0] = 1; G.graph[1][2] = 1;
G.graph[2][0] = 1; G.graph[2][1] = 1; G.graph[2][3] = 1
G.graph[3][0] = 1; G.graph[3][2] = 1
for row in range(4):
for col in range(4):
print(G.graph[row][col] , end=' ')
print()
종류에 따라 가지런히 놓여 있는 것처럼 데이터가 나열되어 있는 것이다.
중요 알고리즘 중 하나인 정렬은 자료들을 일정한 순서대로 나열한 것
선택 정렬(*)
삽입 정렬
버블 정렬
퀵 정렬 : 빠르게 정렬하지만 구현이 어렵다.
최솟값 찾기
# 최솟값 찾기
import random
## 함수
def findMinIndex(ary):
minIdx = 0
for i in range(1,len(ary)):
if (ary[minIdx]>ary[i]):
minIdx = i
return minIdx
## 전역
testAry = [random.randint(0,99) for _ in range(20)]
## 메인
print(testAry)
minPos = findMinIndex(testAry)
print('최솟값-->', testAry[minPos])
선택 정렬의 기본 구현 (빈 리스트에 추가하기)
## 선택 정렬 1(완전) #빈 배열 만들기
import random
## 함수
def findMinIndex(ary):
minIdx = 0
for i in range(1,len(ary)):
if (ary[minIdx]>ary[i]):
minIdx = i
return minIdx
## 전역
before = [ random.randint(100,200) for _ in range(10)]
after = [] #빈방으로 준비
## 메인
print('정렬 전 -->' , before)
for _ in range(len(before)):
minPos = findMinIndex(before)
after.append(before[minPos]) #빈 리스트인 after에 작은 값부터 추가 후 before에서 삭제
del (before[minPos])
print('정렬 후 -->' , after)
선택 정렬의 개선된 구현 (하나의 배열에서 처리)
## 선택 정렬 2(완전) # 하나의 배열에서 처리
import random
## 함수
def selectionSort(ary):
n = len(ary) #ary의 길이
for cy in range(0, n-1):
minIdx = cy
for i in range(cy+1, n):
if (ary[minIdx] > ary[i]):
minIdx = i
ary[cy], ary[minIdx] = ary[minIdx] , ary[cy] # 위의 두번째 for문의 if문의 결과로 최소값을 찾을경우 값을 변경
return ary
## 전역
dataAry = [ random.randint(100,200) for _ in range(10)]
## 메인
print('정렬 전 -->' , dataAry)
dataAry = selectionSort(dataAry)
print('정렬 후 -->' , dataAry)
## 순차 검색
import random
## 함수
def seqSearch(ary, fData) :
pos = -1
size = len(ary)
for i in range(0, size, 1) :
if (ary[i] == fData) :
pos = i
break
return pos #동일한 값을 찾지 못하면 -1을 반환
## 전역
SIZE = 10
dataAry = [ random.randint(1, 99) for _ in range(SIZE)]
findData = dataAry[random.randint(0,SIZE-1)]
## 메인
print('배열-->', dataAry)
positon = seqSearch(dataAry, findData)
if positon == -1 :
print(findData, '값이 없습니다.')
else :
print(findData, '가 ', positon, ' 에 있음')
## 이진 검색
import random
# 함수 선언부
def binSearch(ary, fData) :
pos = -1
start = 0
end = len(ary)-1
while (start <= end) :
mid = (start + end) // 2 # 정수로 표시
if fData == ary[mid] :
return mid
elif fData > ary[mid] :
start = mid + 1 #왼쪽 반을 버림
else :
end = mid -1 # 오른쪽 반을 버림
return pos # start>=end가 될때까지 반복문 내에서 리턴을 하지 못했다면 초기 pos 값인 -1을 반환
## 전역
SIZE = 10
dataAry = [ random.randint(1, 99) for _ in range(SIZE)]
findData = dataAry[random.randint(0,SIZE-1)]
dataAry.sort()
## 메인
print('배열-->', dataAry)
positon = binSearch(dataAry, findData)
if positon == -1 :
print(findData, '값이 없습니다.')
else :
print(findData, '가 ', positon, ' 에 있음') #반환된 mid가 position으로 출력됨
## 함수
def openBox(): #count수 만큼 종이 상자 열기
global count
print("종이 상자 열기~~~")
count -=1
if count ==0 :
print('** 반지 넣기 **') #count가 0이 되면 반지 넣기
return
openBox()
print('종이 상자 닫기') #호출된 openBox 함수마다 종이상자 닫기를 실행하고 함수 종료
return
## 전역
count = 10
## 메인
openBox()
## 정해진 숫자부터 1까지 더하기
def addNumber(num):
if num<=1:
return 1
return num+addNumber(num-1)
## 팩토리얼 재귀함수
def factorial(number):
if number <=1 :
return 1
return number * factorial(number-1)
## 카운트다운 함수
def countDown(num):
if num==0:
print('발사')
else:
print(num)
countDown(num-1)
## 1씩 증가하면서 별 출력
def printStar(num):
global i
if i >= num:
return 0
print('★' * i)
i += 1
return printStar(num)
## 구구단 함수
def gugu(dan, num):
print(f'{dan} X {num} = {dan*num}')
if num <9:
gugu(dan,num+1)
for dan in range(2,10):
print(f'##{dan}단##')
gugu(dan,1)
## x의 n승 함수
def pow(x, n): # x의 n승 값 반환
if n == 0:
return 1
return x * pow(x, n-1)
## array의 n부터 끝까지 합
def arySum(arr, n):
if len(arr) == n:
return 0
return arr[n] + arySum(arr, n+1)
주어진 배열에 대해
ARRAY_LENGTH = 5 # 배열의 행과 열 크기(고정)
def replaceData(numData): # numData 2차원 정수 배열
retData = [] # 조건에 따라서 전처리된 2차원 배열
########### 여기부터 코딩 (1) ---------------->
retData = numData[:]
for i in range(ARRAY_LENGTH) : #ARRAY_LENGTH 가 5
for k in range(ARRAY_LENGTH):
if retData[i][k]<0:
retData[i][k] = 0
if retData[i][k]>100:
retData[i][k] = retData[i][k] % 100
########### <-------------- 여기까지 코딩 (1)
return retData
# 2x2 크기의 배열의 최대합을 구한다.
def getMaxSum(numData): # 요구 사항에 맞춰 처리된 2차원 정수 배열
maxSum = 0 # 최대합
########### 여기부터 코딩 (2) ---------------->
for i in range(ARRAY_LENGTH-1):
for k in range(ARRAY_LENGTH-1):
hap = numData[i][k]+numData[i][k+1]+numData[i+1][k]+numData[i+1][k+1]
if hap > maxSum:
maxSum = hap
########### <-------------- 여기까지 코딩 (2)
return maxSum
## 전역 변수 선언 부분
numData =[] # 5x5 배열
ARRAY_LENGTH = 5 # 배열의 행과 열 크기(고정)
def main() :
global numData
loadData() # 2차원 배열 읽어오기
## 원본 출력
print(' ----- 초기 배열 -----')
printData()
# 1. 데이터 치환 작업
numData = replaceData(numData)
print(' ----- 치환 후 배열 -----')
printData()
# 2. 최대 합 구하기.(2x2 크기)
maxSum = getMaxSum(numData)
print('최대 영역의 합: %d' % maxSum)
## 함수 선언 부분
def loadData() : # 데이터 불러오기
global numData
###########
# 제공 데이터 세트 1
# 5x5 숫자 배열.
###########
numData = \
[
[ 5, 7, -5, 100, 73 ],
[ 35, 23, 4, 190, 33 ],
[ 49, 85, 662, 39, 81 ],
[ 124, -59, 86, 46, 52 ],
[ 27, 7, 8, 33, -56 ]
]
def printData() :
for i in range(0, ARRAY_LENGTH) :
for k in range(0, ARRAY_LENGTH) :
try :
print("%5d" % numData[i][k], end='')
except :
pass
print()
print('--------------------------------------')
## 메인 함수 호출 ##
if __name__ == "__main__" :
main()