[Python]BMS(Building_Management_System)
BMS : 건물 관리 시스템
- 즉, 우리가 만드는건 데이터를 관리하기 위한 데이터 관리 시스템 느낌이라고 보면 된다.
1. Computer Class
- 아래에서 인스턴스 생성을 위함(데이터 생성을 이 클래스 형식으로 생성할거임.)
class Computer:
def __init__(self, title, price, rating, date, link):
self.title = title # 문자열 (제목)
self.price = price # 정수 (가격)
self.rating = rating # 부동소수형 float (별점)
self.date = date # 문자열 (도착 날짜)
self.link = link # 문자열 (링크)
self.next = None # 과제 2를 위한 연결리스트
def __repr__(self):
return f"COMPUTER [title: {self.title}, price:{self.price}, rating: {self.rating}, date: {self.date}, link: {self.link}]"
C1 = Computer("삼성전자 플러스2 퓨어 화이트 노트북 NT550XDZ-AD2AW (펜티엄골드-7505), WIN미포함, RAM 8GB + SDD 256GB"
, 593000, 4.5, "2021-03-19", "https://www.coupang.com/np/search?component=&q=%EB%85%B8%ED%8A%B8%EB%B6%81&channel=user")
2. BMS Class
- BMS로 객체 생성시 generate_db() 함수를 통해 ItemDB, UserDB클래스의 객체도 생성하고, self로 가지는 흐름.
- search(검색), sort(정렬), delete(삭제), print_…(출력)로 구성
# BMS ADT
class BMS:
def __init__(self, db_size): # 초기 값 사이즈 받아서
self.db_size = db_size # self로 사용할 수 있게 저장 하고
self.generate_db() # 데이터 베이스 함수 실행!!
self.cursor_user_db = 0 # 사용자 DB에 대한 커서
self.cursor_item_db = None # 아이템 DB에 대한 커서
def generate_db(self): # 데이터 생성!!
self.items = ItemDB(self.db_size[0]) # 링크드 리스트로 구성
self.users = UserDB(self.db_size[1]) # 2D 배열(2차원)로 구성
def search(self, keyword): # keyword값 검색해주는 함수
results = []
# 연결리스트 부분
currNode = self.items.polyHead
while currNode is not None:
if currNode.title == keyword:
results.append(currNode)
currNode = currNode.next
# 2D 리스트 부분
for i in range(len(self.users.data)): # 리스트 끝까지 반복
if self.users.data[i][0] == keyword:
results.append(self.users.data[i]) # results에 추가!
return results # 연결리스트와 2d리스트에서 찾은 search값 리스트로 반환
def sort(self, order_by): # 정렬해주는 함수 => n행3열중 2열에 age있음
n=len(self.users.data)
if (order_by == 'asc'): # 오름차순 일시
for i in range( n - 1 ) : # 크기가 n인 리스트이면 (n-1)번 반복
for j in range( n - 1 - i ) :
if self.users.data[j][1] > self.users.data[j + 1][1] : # 현재 위치의 값과 (현재 위치+1)인 값 비교
tmp = self.users.data[j] # swap!!!
self.users.data[j] = self.users.data[j + 1]
self.users.data[j + 1] = tmp
elif (order_by == 'desc'): # 내림차순 일시
for i in range( n - 1 ) : # 크기가 n인 리스트이면 (n-1)번 반복
for j in range( n - 1 - i ) :
if self.users.data[j][1] < self.users.data[j + 1][1] : # 현재 위치의 값과 (현재 위치+1)인 값 비교
tmp = self.users.data[j] # swap!!!
self.users.data[j] = self.users.data[j + 1]
self.users.data[j + 1] = tmp
else: # 오름차순, 내림차순 둘다 아니기 때문에 false 리턴
return False
def delete(self, keyword): # 삭제하는 함수 => 하나의 특정 컬럼 입력 받고 해당 레코드 전부 삭제
results = [] # 삭제부분 배열로 보여주기
# 연결리스트 부분
prevNode = None
currNode = self.items.polyHead
while currNode is not None:
if(currNode.title == keyword):
if currNode is self.items.polyHead: # 처음에 값 있을 때
results.append(currNode) # 삭제부분 return하기위해 추가!
self.items.polyHead = currNode.next
self.items.size -= 1
else: # 다른경우에 값 있을 때
results.append(currNode)
prevNode.next = currNode.next # 값 없애기
self.items.size -= 1
prevNode = currNode
currNode = currNode.next
# 2D 리스트 부분
for i in range(len(self.users.data)): # 리스트 끝까지 반복
if self.users.data[i][0] == keyword:
results.append(self.users.data.pop(i)) # 리스트 해당 행 삭제
self.users.data += [[0,0,0]] # 배열 크기 유지하기 위해(중요!!)
self.users.size -= 1 # 배열 사이즈 1 감소
continue
return results
def print_item_db(self, limit):
i = 0
p = limit
curNode = self.items.polyHead
while i < p and curNode is not None:
print(curNode)
i += 1
curNode = curNode.next
def print_user_db(self, limit):
for i in range(limit):
print(self.users.data[i])
def get_users(self, nums): # 과제3 위해 추가!!
start = self.cursor_user_db
end = start + nums
if start > len(self.users.data):
start = 0
results = self.users.data[start:end]
self.cursor_user_db = end
return results
def get_items(self, nums): # 과제3 위해 추가!!
results, i = [], 0
# 아이템 DB의 커서 세팅
if self.cursor_item_db is None: # None이라면
CurNode = self.items.polyHead # head노드로 초기화!
else:
CurNode = self.cursor_item_db
while i < nums and CurNode is not None:
results.append(CurNode) # 리스트에 append!
i+=1
CurNode = CurNode.next
self.cursor_item_db = CurNode
return results
3. ItemDB 및 UserDB Class
- 실제로 랜덤으로 데이터들을 생성할 부분
# ItemDB 클래스 : 연결리스트로 구현 -> Computer Class 사용함
# UserDB 클래스 : 2차원 배열로 구현 -> 그냥 임의의 형식으로 데이터 구성
import numpy as np # 수치계산 라이브러리
!pip install names
import names # 다운받은 names 라이브러리 임포트
import random
import string
class ItemDB: # BMS 조작 통해서 데이터 개수 입력 받음.
def __init__(self, nums):
self.polyHead = None
self.polyTail = None
self.size = 0
self.nums = nums
self.generate_db()
def generate_db(self): # ItemDB 생성하는 함수
monthly_days = np.arange(0,30) # 0~29 배열
base_date = np.datetime64('2021-03-01') # datetime64라는 numpy라이브러리에 잇는 클래스 사용
for i in range(self.nums):
# 컴퓨터 이름
random_title = names.get_first_name(gender='female')
# 컴퓨터 가격
random_price = random.randint(490000,2000000)
# 컴퓨터 평점
random_grade = round(random.uniform(1,10),2)
# 컴퓨터 도착 예정 날짜
random_date = base_date + np.random.choice(monthly_days) # 랜덤으로 날짜 반환
# 해당 링크
random_link = "http://www." + ''.join(random.choice(string.ascii_lowercase) for i in range(10)) + ".com" # 아스키코드 소문자 랜덤 10자 작성
# 인스턴스 생성
computer = Computer(random_title,random_price, random_grade, random_date, random_link)
# 링크드 리스트 데이터 추가
if self.polyHead is None:
self.polyHead = computer
else: # 한개 이상이 있는 경우
self.polyTail.next = computer
self.polyTail = computer
self.size += 1
class UserDB:
def __init__(self, nums):
self.data = []
self.nums = nums
self.size = 0
self.generate_db()
def generate_db(self):
for i in range(self.nums): # 3열에 nums행
random_name = names.get_first_name(gender='female')
random_age = random.randint(1,1000)
random_favorite = ''.join(random.choice(string.ascii_lowercase) for i in range(5))
self.data += [[random_name, random_age, random_favorite]]
self.size += 1
4. 프로그램 테스트
# 요구사항 1, 2
bms = BMS([50000,10000]) # 5만개,1만개 생성, 테스트 경우, 사이즈를 줄인뒤 실행
bms.print_item_db(10) # 아이템 DB 출력 10개
bms.print_user_db(10) # 사용자 DB 출력 10개
''' 출력
COMPUTER [title: Dorothy, price:1209935, rating: 6.08, date: 2021-03-17, link: http://www.kbzeadnkvu.com]
COMPUTER [title: Stella, price:1489798, rating: 7.83, date: 2021-03-27, link: http://www.oeheamcuhm.com]
... 생략
['Billie', 54, 'lmife']
['Nicole', 76, 'ssbis']
... 생략
'''
# 검색 및 삭제할 키워드
keyword = bms.users.data[0][0]
print(keyword)
'''
Billie
'''
# 요구사항 3
results = bms.search(keyword)
tmp_items = []
tmp_users = []
for result in results:
if isinstance(result, Computer): # items인지 users인지 검사
tmp_items.append(result)
else:
tmp_users.append(result)
print(results)
print("검색된 아이템의 수(item): {n_item} 검색된 아이템의 수(user): {n_user}".format(n_item=len(tmp_items), n_user=len(tmp_users)))
'''
[COMPUTER [title: Billie, price:1284472, rating: 5.58, date: 2021-03-12, link: http://www.jgnvgillzj.com], COMPUTER [title: Billie, price:1774479, rating: 3.38, date: 2021-03-14, link: http://www.jeemxrcgqf.com],
['Billie', 54, 'lmife'], ['Billie', 721, 'eoohl'], ['Billie', 760, 'qcves'], ['Billie', 435, 'jjdum'], ['Billie', 794, 'cyojf'], ['Billie', 593, 'ysgje'], ['Billie', 168, 'nuclq'], ['Billie', 7, 'wedsg'], ['Billie', 869, 'mnkci']]
... 생략
검색된 아이템의 수(item): 30 검색된 아이템의 수(user): 9
'''
# 요구사항 4
# 사용자DB를 정렬하고 ASC 순으로 정렬되었는지를 확인
bms.sort('asc')
bms.print_user_db(10) # 사용자 DB 출력 10개
'''
['Olga', 1, 'ernie']
['Sandra', 1, 'rwpjo']
['Gladys', 1, 'gxzzr']
['Otilia', 1, 'ekrfu']
['Bernadine', 1, 'wshre']
['Shannon', 1, 'vbhux']
['Erma', 1, 'zqjlq']
['Jeanette', 1, 'ycelv']
['Eva', 1, 'kctix']
['Tiffany', 2, 'ehcjk']
'''
# 요구사항 5
# 다시 검색하면 관련데이터는 삭제되었기 때문에 자료가 없어야함
bms.delete(keyword)
print("수정된 ItemDB의 크기: {n_item_db} 수정된 UserDB의 크기: {n_user_db}".format(n_item_db=bms.items.size, n_user_db=bms.users.size))
results = bms.search(keyword)
print(f"{keyword}를 사용자, 아이템DB에서 다시 검색한 결과: {len(results)}")
'''
수정된 ItemDB의 크기: 49970 수정된 UserDB의 크기: 9991
Billie를 사용자, 아이템DB에서 다시 검색한 결과: 0
'''
5. 복잡도
- 주관적이므로 틀릴 수 있음
# BMS 내 search, sort, delete 메소드
"""
T: O(N+M) = O(N) -> Linear time
search : 검색 메소드
"""
"""
T: O(N^2) -> Quadratic time
sort : 정렬 메소드
"""
"""
T: O(N^2) -> Quadratic time
delete : 삭제 메소드
=> 연결리스트는 O(N)이지만 2차원 리스트는 pop(i)때문에 O(N^2)이 나온다고 생각
"""
댓글남기기