자료구조 with Python : Stack(스택)

스택(Stack)은 마지막에 들어온 데이터가 가장 먼저 나가게 되는 후입선출(LIFO)의 자료구조이다. 스택도 결국에는 리스트의 특별한 케이스일 뿐이다. 입력과 출력이 한 쪽 끝단에서만 이루어진다.


스택의 구조

스택은 가장 위의 데이터를 알리는 top, 스택에 데이터를 삽입하는 push, top의 데이터를 내보내는 pop함수가 기본적인 구성이다. 이 외에도 peak나 is_empty를 구현하기도 하지만 이건 부수적인 것일 뿐이다.

Push(item)

push는 아이템을 스택에 삽입하는 함수이다. top은 1 증가시키고 top이 가리키는 위치에 아이템을 저장한다.

Pop()

pop은 아이템을 스택에서 꺼내는 함수이다. 단순 참조가 아니라 스택에서 아예 나오게 되는 것이다. top이 가리키는 위치의 아이템을 꺼낸 후 top을 1 감소시킨다.

두 함수 모두 시간 복잡도는 O(1)이고 스택은 원하는 아이템을 찾을 때는 top에서 부터 차례대로 찾아야해서 random 접근이 불가능하다.


스택의 예시

스택을 쉽게 설명하기 위해서 스택은 상자, 데이터는 상자와 너비가 같은 책이라고 예시를 든다 (책은 항상 눕혀서 상자에 넣는다). Top은 상자의 위에서 확인하는 것이라 생각한다.

스택이라는 상자에 처음 위에서 바라보면 상자의 밑바닥을 확인할 수 있다. 스택에 처음에는 자료구조라는 책을 넣는다. 상자를 위에서 봤을 때 우리는 자료구조가 있다는 것을 확인할 수 있다. 그 다음 운영체제 책을 넣고 컴퓨터 구조 책을 넣는다. 이 때 상자의 위에서 볼 수 있는 것은 컴퓨터 구조이다. Stack의 Top이 가리키는 것이 컴퓨터 구조라는 의미이다.

상자에서 우리가 꺼낼 수 있는 책은 마지막에 넣은 컴퓨터 구조이고 다른 책을 넣을 수 있는 공간 역시 컴퓨터 구조 위이다. 우리는 상자에서 컴퓨터구조, 운영체제, 자료구조 순으로 꺼낼 수 있으며 위에서 봤을 때 상자의 밑바닥이 보이면 책을 꺼내는 것이 불가능해진다.

빈 상자와 넣을 책이 3권일 때
자료구조 책을 상자에 넣었을 때
모든 책을 다 넣은 상태

상자에 자료구조가 있는 지 확인하려면 컴퓨터 구조 책부터 순서대로 꺼내가면서 확인을 해야한다.


Stack의 구현

이론적인 Stack (list자료형의 append(), pop() 사용하지 않음)

주소에 의한 참조가 가능하다는 조건에서 만들기 위해 dictionary 자료형을 사용했습니다. del 함수는 사전 자료형에서 시간복잡도가 1입니다.

class Stack:
    def __init__(self):     # 스택의 정의
        self.stack = dict()
        self.top = -1

    def push(self, data):   
        self.top += 1 
        self.stack[self.top] = data

    def pop(self):          
        if self.is_empty(): # 스택이 비었으면 pop이 불가능
            return "Stack is Empty"
        tmp = self.stack[self.top]
        del self.stack[self.top]
        self.top -= 1       

        return tmp

    def size(self):
        return self.top+1

    def is_empty(self):     # stack이 비어있는지 확인
        if self.top == -1:
            return True
        else:
            return False

    def peak(self):         # top이 가리키는 값
        if not self.is_empty():
            return self.stack[self.top]
        else:
            return "Stack is Empty"

    def __repr__(self):
        return repr(self.stack)

확인 코드

stack = Stack()
stack.push("자료구조")
print("top : {}, peak : {}, stack : {}".format(stack.top, stack.peak(), stack))
stack.push("운영체제")
print("top : {}, peak : {}, stack : {}".format(stack.top, stack.peak(), stack))
stack.push("컴퓨터구조")
print("top : {}, peak : {}, stack : {}".format(stack.top, stack.peak(), stack))
print("pop : {}".format(stack.pop()))
print("top : {}, peak : {}, stack : {}".format(stack.top, stack.peak(), stack))
print("pop : {}".format(stack.pop()))
print("top : {}, peak : {}, stack : {}".format(stack.top, stack.peak(), stack))
stack.push("알고리즘")
print("top : {}, peak : {}, stack : {}".format(stack.top, stack.peak(), stack))
print("pop : {}".format(stack.pop()))
print("top : {}, peak : {}, stack : {}".format(stack.top, stack.peak(), stack))
print("pop : {}".format(stack.pop()))
print("top : {}, peak : {}, stack : {}".format(stack.top, stack.peak(), stack))

결과


위의 코드는 이론적인 부분을 확인하기 위한 코드로 실제 파이썬에서는 list 자료형의 popappend를 이용하여 구현하는 것이 쉽습니다.

Stack 객체 구현 (list자료형 pop(), append() 사용 )

class Stack:
    def __init__(self):
        self.stack = []
        self.top = -1
    def push(self, data):
        self.stack.append(data)
        self.top += 1
    def pop(self):
        if self.is_empty():
            return "Stack is Empty"
        self.top -= 1
        return self.stack.pop()

    def size(self):
        return len(self.stack)

    def is_empty(self):
        if not self.stack:
            return True
        else:
            return False

    def peak(self):
        if not self.is_empty():
            return self.stack[-1]
        else:
            return "Stack is Empty"

    def __repr__(self):
        return repr(self.stack)

확인 코드 결과


파이썬에서 스택을 굳이 직접 구현해야하는가?

파이썬의 list자료형은 위의 예제에서 봤듯이 pop()함수가 사용가능하고 push대신 append() 함수를 사용하면 스택처럼 리스트의 사용이 가능하다. 두 함수 모두 시간 복잡도는 O(1)이기 때문에 스택에서의 구현과 동일하다. top 또한 len - 1로, peak 또한 list[-1] 로 구현이 가능한 만큼 제공되는 함수를 사용하는 것이 유리하다고 생각한다.

찾는 item이 있는지 확인하는 부분이 리스트는 앞에서 확인하지만 스택은 뒤에서부터 확인한다는 점이 조금 다르긴 할 것이다.

Mars를 이용한 계산기 프로그램(괄호 연산 가능)

괄호 계산을 위해서 공부한 내용은 후위 표기법이었다. 중위 표기법은 *와 /가 +와 - 보다 더 우선순위가 높은 규칙을 따르기 때문에 우선 순위를 높이기 위해 괄호를 사용하지만 후위 표기법은 연산자의 위치에 따른 계산을 하기 때문에 구현하기가 더 쉬울 것이라 생각했다.


후위 표기법 변환 방법

후위표기법으로 바꾸는 규칙은 다음과 같다.
1. 수(operand)는 무조건 배열에 삽입
2. 여는 괄호 (가 나오면 무조건 스택에 push
3. 계산의 우선 순위는 *, / >>> +, - >>> ( 이다.
4. 연산자 스택이 비어있으면 연산자를 무조건 스택에 push
5. 연산자 스택에 있는 연산자가 우선순위가 더 높거나 같으면 스택에 있는 연산자를 pop해서 후위표기법 배열에 삽입하고 현재 연산자를 스택에 push. 현재 연산자의 우선순위가 더 높은 경우에는 연산자를 push만 한다.
6. 닫는 괄호 ')'가 나오면 '('를 만날 때까지 연산자를 pop해서 배열에 삽입
7. 수식이 종료되면 연산자 스택에 있는 모든 연산자를 pop해서 배열에 삽입


후위 표기법 변환 예시

수식 : 12 / ( 3 + 3 ) - 2

 

 

 

 

 

 

 

 

 

Code

 

변수 정의

    .data
sol:    .asciiz "= "
exp:    .word 0:100
size:    .word 100
st_op: .space 100        #연산자 스택
st_ans:    .space 100        #계산 스택
ar_pos:    .word 0:20        #후위 표기법 배열
error:    .asciiz "error"
nan:    .asciiz "Not a Number => operand2 of '/' must not be ZERO"

    .globl main
    .text

문제를 풀기 위해 사용된 대략적인 변수라고 할 수 있다. 컴퓨터 구조나 운영체제에서 배웠지만 프로그램 실행에 필요한 변수들은 모두 스택에 저장이 된다.

main 함수

main:
    la $a0 exp        #입력을 받아 $a0에 저장
    la $a1 size

    li $v0 8
    syscall

    la $s0 st_op        # $s0 = 연산자 스택의 주소
    li $s1 0        # 연산자 스택의 탑
    la $s2 st_ans        # $s2 = 계산과정 스택의 주소
    li $s3 0        # 계산과정 스택의 탑
    la $s4 ar_pos        #후위표기법을 위한 배열
    li $s5 0        #배열의 사이즈 측정
    jal convert
    jal operate
    jal print

    li $v0 10        #프로그램 종료
    syscall

프로그램의 메인함수이다. $v0에 8을 입력하고 system call을 하면 입력을 받는다.
그 이후에는 $s0, $s2, $s4에 연산자 스택, 계산과정 스택, 후위 표기법 저장을 위한 배열로 각각 정의한다.

후위 표기법 변환

convert:            #중위 표기법을 후위 표기법으로 변환
    addi $sp $sp -4    
    sw $ra 0($sp)

    li $t0 0        # $t0 = 입력값의 주소를 읽기 위해 더해주는 값을 저장하는 레지스터
    li $t2 0        # $t2 = 숫자 입력값이 있는지 알아보기 위한 값을 저장하는 레지스터
    li $t3 0        # $t3 = 입력된 수의 임시 저장 레지스터
    li $t9 10        # $t9 = 입력값의 자릿수를 만들어 주기 위한 값을 저장하는 레지스터

$t0는 수식이 저장된 배열의 포인터이다.
$t2는 연산자 전에 숫자 입력값이 있었는지 확인하는 플래그이다.
$t3은 여러 자리의 수를 만들기 위해 임시로 수를 저장하는 값이다.
$t9는 자릿수가 증가할 때마다 10을 곱해주기 위해서 사용된다.

load_input:            #입력값을 load
    add $t1 $t0 $a0
    lb $t1 0($t1)        # $t1 = 입력된 값을 한바이트씩 받아오는 레지스터
    addi $t0 $t0 1

    beq $t1 10 _ret_convert    # enter를 만나면 변환 종료  10 = \n
    beq $t1 '(' bracket    # 괄호를 만나면 bracket으로 이동
    beq $t1 '*' muldiv    # *나 /를 만나면 muldiv로 이동
    beq $t1 '/' muldiv
    beq $t1 '+' addsub    # +나 -를 만나면 addsub로 이동
    beq $t1 '-' addsub
    beq $t1 ')' close    #괄호가 닫히면 close로 이동

    blt $t1 47 error_print    # 숫자 또는 사칙연산이 아닌 경우
    bgt $t1 58 error_print

    addi $t1 $t1 -48    # 숫자를 정수형으로 고치기 위해 빼줌
    mul $t3 $t3 $t9        # '0'의 아스키 코드 값 = 48
    add $t3 $t1 $t3
    addi $t2 $t2 1        # $t2에 1을 더한다.

    j load_input        #load_input 반복

문자열을 순회하면서 입력 값에 따라 각각의 함수로 분기한다.

error_print:            # error를 출력하고 프로그램을 종료한다.

    la $a0 error
    li $v0 4
    syscall

    li $v0 10
    syscall
_ret_convert:    
    jal operand        # 숫자가 남아 있으면 숫자를 먼저 배열에 넣고
    jal pop_all        # 남은 연산자 모두를 pop해서 배열에 넣어준다.
    lw $ra 0($sp)
    addi $sp $sp 4

    jr $ra            # main으로 돌아간다.

입력 문자가 \\n인 경우 마무리 작업을 한다.

operand:
    bgt $t2 0 push_int    # $t2가 0보다 크다는 $t3에 숫자가 있다는 것을 의미한다.
                # 숫자가 있으면 정수를 배열에 넣어준다.
    jr $ra
push_int:        
    sll $t4 $s5 2        # 배열 사이즈에 4를 곱한 후 배열 주소에 더해
    add $t4 $s4 $t4        # 정수를 저장한다.
    sw $t3 0($t4)

    addi $s5 $s5 1
    li $t2 0        # 입력된 수가 없어진다는 것을 의미한다.
    li $t3 0        # 입력된 수를 초기화
    jr $ra            # oprand로 돌아가지 않고 각각의 함수로 돌아간다.
                # $ra의 값은 oprand 함수에 있는 $ra값과 같다.
                # 즉 $ra는 operand를 불러온 jal이 있는 주소 + 4 이다.

각각의 연산전에 수가 나왔다면 수를 먼저 후위 표기법 배열에 넣어준다.

bracket:            # 괄호는 무조건 push한다.
    jal operand

    j push
muldiv:                # muldiv는 스택의 탑에 저장된 연산자가 *나 /이면
                # 이전 것을 pop하고 자기 자신을 집어넣는다.
    jal operand

    beq $s1 0 push        # stack에 아무것도 없으면 push한다.

    lw $t5 0($s0)
    beq $t5 '+' push
    beq $t5 '-' push
    beq $t5 '(' push

    jal pop            # 이 경우는 이전 탑에 *나 /가 있던 경우이다.

    j muldiv

addsub:
    jal operand

    beq $s1 0 push        # stack에 아무것도 없으면 push한다.

    lw $t5 0($s0)
    beq $t5 '(' push    # (를 만나면 스택에 아무것도 없을 때와 같이 실행한다.

    jal pop            # 앞의 연산자들을 pop한다.

    j addsub
close:                # 괄호가 닫히면 '('를 만날 때 까지 pop한다.
    jal operand

    lw $t5 0($s0)
    beq $t5 '(' pop_bracket

    jal pop

    j close

push:                # 연산자를 스택의 탑에 넣는다.
    addi $s1 $s1 1
    addi $s0 $s0 4
    sw $t1  0($s0)

    j load_input

pop:                # 탑에 있는 연산자를 스택에서 꺼내 배열에 넣는다.
    lw $t5 0($s0)
    addi $s0 $s0 -4
    addi $s1 $s1 -1

    sll $t4 $s5 2
    add $t4 $s4 $t4
    mul $t5 $t5 -1        # 이 때 정수값들과 비교하기 위해 -를 곱해서 넣어준다.
    sw $t5 0($t4)

    addi $s5 $s5 1        # 배열의 크기 증가

    jr $ra
pop_bracket:            # '('는 후위 표기법의 배열에 필요 없으므로
                # 스택의 포인터만 낮춰준다. 
    addi $s0 $s0 -4

    addi $s1 $s1 -1
    j load_input

pop_all:            # 입력값을 모두 읽었으면 남아 있는 모든 연산자를 pop한다.
    addi $sp $sp -4
    sw $ra 0($sp)
    jal pop
    lw $ra 0($sp)
    addi $sp $sp 4
    bgtz $s1 pop_all    # 연산자 스택의 탑이 0보다 크면 다시 pop을 한다.

    jr $ra

후위 표기법 계산

operate:
    addi $sp $sp -4
    sw $ra 0($sp)

    li $t0 0        # 배열의 사이즈 만큼만 읽기 위한 count        

Loop:    
    seq $t6 $s3 1        # 스택에 값이 하나가 있고
    seq $t7 $t0 $s5        # count가 배열의 사이즈와 같으면 연산종료 
    and $t8 $t6 $t7
    beq $t8 1 _ret_operate
    beq $t7 1 error_print    # count가 배열의 사이즈와 같은데 스택의 탑이 1이 아니면 오류
                # 이 오류는 연산자 뒤에 바로 연산자가 올 때
                # 혹은 숫자 다음에 바로 '(' 나 ')' 가 올때 적용
    sll $t1 $t0 2        # count * 4
    add $t1 $s4 $t1        
    lw $t1 0($t1)
    addi $t0 $t0 1        # count++

    beq $t1 -45 op_sub    # '-' = 45
    beq $t1 -43 op_add    # '+' = 43
    beq $t1 -42 op_mul    # '*' = 42
    beq $t1 -47 op_div    # '/' = 47

    jal push_number        # 연산자가 아니라면 숫자를 push해준다.

    j Loop
push_number:
    addi $s2 $s2 4        # 스택에 한칸을 만들어 숫자를 저장
    sw $t1 0($s2)
    addi $s3 $s3 1        # Top Of Stack ++

    jr $ra

op_add:                
    lw $t2 0($s2)        # 탑에 있는 값을 pop해서 opernad 2로 설정
    addi $s2 $s2 -4        # Top of Stack --
    addi $s3 $s3 -1    
    lw $t3 0($s2)        # 다시 탑에 있는 값을 pop 해서 oprand 1로 설정
                # 이 주소에 다시 저장해야 되기 때문에 Top of Stack --를 안함
    add $t4 $t3 $t2        # operand 1 + opernad 2
    sw $t4 0($s2)        # 스택의 탑에 값을 저장

    j Loop
op_sub:
    lw $t2 0($s2)        # 탑에 있는 값을 pop해서 opernad 2로 설정
    addi $s2 $s2 -4        # Top of Stack --
    addi $s3 $s3 -1        
    lw $t3 0($s2)        # 다시 탑에 있는 값을 pop 해서 oprand 1로 설정
                # 이 주소에 다시 저장해야 되기 때문에 Top of Stack --를 안함

    sub $t4 $t3 $t2        # operand 1 - operand 2
    sw $t4 0($s2)        # 스택의 탑에 저장

    j Loop
op_mul:                
    lw $t2 0($s2)        # 탑에 있는 값을 pop해서 opernad 2로 설정
    addi $s2 $s2 -4        # Top of Stack --
    addi $s3 $s3 -1
    lw $t3 0($s2)        # 다시 탑에 있는 값을 pop 해서 oprand 1로 설정
                # 이 주소에 다시 저장해야 되기 때문에 Top of Stack --를 안함

    mul $t4 $t3 $t2        # operand 1 * opernad 2
    sw $t4 0($s2)        # 스택의 탑에 저장

    j Loop
op_div:
    lw $t2 0($s2)        # 탑에 있는 값을 pop해서 opernad 2로 설정
    addi $s2 $s2 -4        # Top of Stack --
    addi $s3 $s3 -1
    lw $t3 0($s2)        # 다시 탑에 있는 값을 pop 해서 oprand 1로 설정
                # 이 주소에 다시 저장해야 되기 때문에 Top of Stack --를 안함

    beqz $t2 NaN_print    # 분모가 0이 되면 오류
    div $t4 $t3 $t2        # operand 1 / operand 2
                # 단 여기서 나머지는 계산되지 않음
    sw $t4 0($s2)        # 스택의 탑에 저장

    j Loop

NaN_print:
    la $a0 nan        # 오류메시지 출력
    li $v0 4
    syscall

    li $v0 10        # 프로그램 종료
    syscall
_ret_operate:            # main 으로 돌아감

    lw $ra 0($sp)
    addi $sp $sp 4

    jr $ra

print:                # 마지막 계산된 값을 print
    la $a0 sol
    li $v0 4
    syscall

    lw $a0 0($s2)
    li $v0 1
    syscall

    jr $ra

예외 처리

1. 괄호를 제외한 연산자 2개가 연속되는 경우
2. 연산자의 수가 초과되는 경우    ex. "5+4*" 
3. 곱셈을 생략하는 경우    ex. 5(3+2)
4. 숫자나 연산자가 아닌 다른 문자가 수식에 있는 경우
5. 나눗셈을 할 때 분모가 0인 경우

프로그램의 한계점

1. 정수 계산기이다.
    나눗셈의 결과값은 정수가 된다. 예를 들어 15/4는 3.75가 아니라 3으로 계산된다.
2. 음수는 입력을 받을 때 (0-5)와 같은 형태를 취해야 한다.

 

프로그램을 짜면서 int() 같은 함수에도 감사함이 느껴졌다. 괄호 연산 또한 고급 언어에서는 기본적으로 가능하기 때문에 구현이 복잡할 거라 생각하지 못했다. Mars를 이용해 디버깅을 하면서 컴퓨터 구조 시간에 배웠던 것 처럼 데이터가 스택에 저장되어 어떻게 사용이 되고 레지스터를 이용해서 데이터를 저장하는 등의 이론적인 부분에 이해도가 높아지는 기분이었다.

내가 이 코드를 작성할 때는 오직 신과 나만이 그것이 무엇을 하는 코드인지 알았다 하지만 지금은... 오직 신만이 안다

 

[Python] 자료형 - (3) 리스트

리스트는 길게 이어진 상자라고 생각하면 된다. 우리는 리스트 안에 숫자, 문자열, 새롭게 정의한 객체 등 다양한 자료형을 넣을 수 있는 상자이다.

리스트의 생성

a = []
b = list()
c = [1, 2, 3]
d = ["Hello", "World"]
e = [1, 2, "Hello", "World"]
f = [[1, 2], ["Hello", "World"]]

ab리스트는 빈 리스트를 생성해주는 것이다. e 리스트 처럼 상자마다 다른 자료형을 삽입할 수도 있고 f 리스트처럼 리스트를 삽입할 수도 있다.

리스트의 사용

리스트에 보관된 데이터를 어떻게 사용할 것인가

인덱싱

리스트 명[위치값]의 형태로 리스트 안의 원소에 접근이 가능하다. 이것을 인덱싱이라 한다. 리스트는 0번째 칸부터 저장이 되는 것을 주의해야 한다.

데이터 10 20 30 40
인덱스 0 1 2 3

 

a = [10, 20, 30, 40]
print(a[0])
print(a[3])
print(a[-1])
print(a[4])

인덱스 값으로 음수값을 주면 뒤에서부터 원소를 접근한다. 리스트의 크기는 4이지만 리스트의 마지막 번호는 3이기 때문에 a[4]를 사용하면 에러가 난다. 리스트의 범위를 벗어난 접근에 대한 에러다.

슬라이싱

리스트는 꼭 원소를 하나씩 접근할 필요가 없다. 내가 필요한 부분만 잘라서 리스트를 사용하고 싶을 때는 슬라이싱을 사용한다. 리스트를 토막낸다고 생각하면 된다.
기본적인 형태는 리스트 명[시작 인덱스: 끝나는 인덱스 + 1] 과 같이 사용된다. 시작 인덱스와 마지막 인덱스는 생략이 가능하고 그런 경우 끝에서 시작 또는 끝에서 끝남을 의미한다.

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = a[:5]
c = a[5:]
d = a[2:7]
print(a)
print(b)
print(c)
print(d)

사용을 할 때는 : 뒤의 값 전까지 슬라이싱을 하는 것을 명심해야 한다.

리스트의 연산

리스트 역시 문자열처럼 리스트끼리 더하기와 곱하기 연산이 가능하다.

a = ['a', 'b', 'c']
b = ['d', 'e', 'f']
print(a + b)
print(a * 3)

수정, 삭제

a = [1, 2, 3]
a[2] = 4
print(a)

리스트는 직접적으로 값을 바꿀 수 있는 mutable 자료형이다.

a = [1, 2, 3]
del a[1]
print(a)

del 함수는 파이썬의 기본 함수로 객체를 삭제하는 함수이다.

'프로그래밍 > Python' 카테고리의 다른 글

[Python] 소수 판별 알고리즘  (0) 2021.10.11
[Python] 리스트 함수 정리  (0) 2021.09.19
[Python] 자료형 - (2) 문자열  (0) 2021.09.14
[Python] 자료형 - (1) 숫자형  (0) 2021.09.14
[Python] 순열과 조합 itertools  (0) 2021.07.18

문자열이란

문자열(String)이란 문자를 나열해 놓은 것을 의미한다. 문자는 a, b, c 같은 알파벳과, 가나다 같은 한글, 1,2,3 같은 숫자,!@#같은 특수문자 등 유니코드 내에 문자를 의미한다.

"Hello World"
"123456789"
"010-1234-5678"
"!@#$"

문자열의 표현

파이썬에서는 문자열을 쌍따옴표"로도 나타낼 수 있지만 작은 따옴표'로 나타낼 수도 있다.

str1 = "abc"
str2 = 'abc'
print(True if str1 == str2 else False)

위 예제의 print함수는 두 문자열이 같으면 True를 다르면 False를 출력하는 함수입니다. 두 문자열은 그 내부적으로는 서로 같습니다. 파이썬 내부에서는 기본적으로 문자열을 작은 따옴표로 묶여 있는 것으로 표시된다.

위의 방법 외에도 여러 줄의 문자열을 위해서 여러 줄의 문자열을 한 번에 나타내는 방법이 있다.
큰 따옴표나 작은 따옴표를 3개를 사용해서 나타낸다.
첫번째 줄

str3 = """첫 번째 줄
두 번째 줄
세 번째 줄
"""
print(str3)


이스케이프 문자

이스케이프 문자란 줄바꿈, 띄워쓰기 등 여러 기능을 위해 미리 정해놓은 문자 집합이다..
가장 자주 볼 수 있는 문자는 \n, \t, \\이 있다.

str4 = "첫번째\n두번째\n세번째"
str5 = "1\t2\t3\t4"
str6 = "8\t9\t10\t11"
print(str4)
print(str5)
print(str6)

코드 설명 코드 설명
\n 문자열 안에서 줄을 바꿀 때 사용 \r 캐리지 리턴(줄 바꿈 문자, 현재 커서를 가장 앞으로 이동)
\t 문자열 사이에 탭 간격을 줄 때 사용 \f 폼 피드(줄 바꿈 문자, 현재 커서를 다음 줄로 이동)
\\ 문자 \를 그대로 표현할 때 사용 \a 벨 소리(출력할 때 소리가 나게함)
\' 작은 따옴표를 표현할 때 사용 \b 백 스페이스
\" 큰 따옴표를 표현할 때 사용 \0 널문자

문자열의 연산

문자열 더하기(Concatenation)

문자열은 문자열끼리 더하기가 가능하다. 문자열의 덧셈은 각 요소를 더하는 것이 아니라 문자열 뒤에 문자열을 추가한다고 생각하면 된다.

str1 = "Hello"
str2 = " World"
str3 = str1 + str2
print(str3)

문자열 곱셈(반복)

문자열의 곱셈은 곱하는 수만큼의 반복을 의미한다.

str1 = 'Hello '
str2 = str1 * 3
print(str2)

 

2 * 3 = 2 + 2 + 2 인 것을 생각해보면 문자열의 곱셈이 의미하는 것을 알 수 있다. str2 = str1 + str1 + str1이므로 "Hello "라는 문자열을 3번 이어붙인 것이다.

 

 

문자열의 기본 함수에 대해서는 다음에 포스팅하겠습니다.

'프로그래밍 > Python' 카테고리의 다른 글

[Python] 소수 판별 알고리즘  (0) 2021.10.11
[Python] 리스트 함수 정리  (0) 2021.09.19
[Python] 자료형 - (3) 리스트  (0) 2021.09.14
[Python] 자료형 - (1) 숫자형  (0) 2021.09.14
[Python] 순열과 조합 itertools  (0) 2021.07.18

 

[파이썬] 자료형 - (1) 숫자형

숫자형은 우리가 사용하는 숫자(number)를 나타내는 자료형입니다.
예를 들어 1234나 -1234 같은 정수형과 12.34 같은 실수형이 대표적인 표현 방법이며 2진수, 8진수, 16진수로 나타낸 수도 수를 표현하는 방법입니다.


정수형

정수형은 우리가 가장 잘 아는 양의 정수, 음의 정수, 0을 뜻하는 자료형입니다.

a = 123
b = -178
c = 0

위에서 a, b, c 모두 정수를 의미합니다.


진법

파이썬에서 기본 제공되는 진법 표기는 2진수, 8진수, 16진수가 있습니다.

base_2 = 0b1111
base_8 = 0o0017
base_16 = 0x000F
base_10 = 15

print(base_2, type(base_2))
print(base_8, type(base_8))
print(base_16, type(base_16))
print(base_10, type(base_10))

위의 모든 값들은 print()함수에 넣게 되면 정수 값인 15를 출력하고 type() 함수의 출력을 보면 모두 int로 출력됩니다. 눈으로 보기에는 다른 수 같지만 컴퓨터의 입장에서는 모두 같은 수이기 때문입니다.

<출력 결과>


실수형

실수형은 소수점이 포함된 숫자를 의미합니다.

f1 = .1
f2 = 0.1
f3 = -3.14
f4 = 1.23e4

f1처럼 소수점 앞의 0은 생략이 가능합니다. 1.23e4지수 표현 방식이라고 합니다. $$ 1.23 * 10^4 $$을 의미하고 소문자 e, 대문자 E 모두 사용이 가능합니다. 알고리즘 문제를 풀면서 무제한 값을 설정할 때 1e9와 같은 수를 많이 쓰기도 합니다.

 

 

 

'프로그래밍 > Python' 카테고리의 다른 글

[Python] 소수 판별 알고리즘  (0) 2021.10.11
[Python] 리스트 함수 정리  (0) 2021.09.19
[Python] 자료형 - (3) 리스트  (0) 2021.09.14
[Python] 자료형 - (2) 문자열  (0) 2021.09.14
[Python] 순열과 조합 itertools  (0) 2021.07.18

+ Recent posts