데이터 구조 와 알고리즘 (Golang 구현) (13) 흔 한 데이터 구조 - 가 변 긴 배열

46285 단어
가 변 긴 배열
배열 의 크기 가 고정 되 어 있 기 때문에 데이터 요소 가 매우 많 을 때 고정된 배열 은 이렇게 많은 값 을 저장 할 수 없 기 때문에 가 변 긴 배열 이 나 타 났 다. 이것 도 데이터 구조 이다.Golang 언어 에서 가 변 긴 배열 은 언어 에 내장 되 어 있다. 절편 slice.slice 은 바 텀 배열 에 대한 추상 적 이 고 통제 이다.그것 은 구조 체 이다.
type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}
  • 밑바닥 수 조 를 가리 키 는 지침.(Golang 언어 는 원본 메모 리 를 조작 하 는 지침 이 없 기 때문에 unsafe 가방 은 메모리 포인터 에 대한 조작 을 제공 합 니 다. 일반적인 상황 에서 비 전문 인원 은 사용 하지 않 습 니 다)
  • 절편 의 진정한 길 이 는 바로 실제 요소 가 차지 하 는 크기 이다.
  • 절편 의 용량, 바 텀 고정 배열 의 길이.

  • 매번 고정 용량 의 절편 을 초기 화하 고 절편 내부 에 고정 크기 의 배열 을 유지 할 수 있 습 니 다.append 새로운 요소 가 부족 할 때 고정 크기 의 배열 이 부족 할 때 자동 으로 확 대 됩 니 다. 예 를 들 어:
    package main
    
    import "fmt"
    
    func main() {
        //        2   
        array := make([]int, 0, 2)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
    
        //    append             array
        _ = append(array, 1)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
        _ = append(array, 1)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
        _ = append(array, 1)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
    
        fmt.Println("-------")
    
        //         
        array = append(array, 1)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
        array = append(array, 1)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
        array = append(array, 1)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
        array = append(array, 1, 1, 1, 1)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
        array = append(array, 1, 1, 1, 1, 1, 1, 1, 1, 1)
        fmt.Println("cap", cap(array), "len", len(array), "array:", array)
    }
    

    출력:
    cap 2 len 0 array: []
    cap 2 len 0 array: []
    cap 2 len 0 array: []
    cap 2 len 0 array: []
    -------
    cap 2 len 1 array: [1]
    cap 2 len 2 array: [1 1]
    cap 4 len 3 array: [1 1 1]
    cap 8 len 7 array: [1 1 1 1 1 1 1]
    cap 16 len 16 array: [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
    

    우 리 는 Golang 의 절편 이 제자리 append 가 되 지 않 는 것 을 볼 수 있 습 니 다. 요 소 를 추가 할 때마다 새로운 인용 주 소 를 되 돌려 주 고 이 인용 을 이전의 절편 변 수 를 다시 부여 해 야 합 니 다.그리고 용량 이 부족 하면 자동 으로 배수 가 늘 어 나 고 용량 이 늘어난다.실제로 Golang 절편 길이 가 1024 보다 크 면 1.25 배 에 가 까 운 용량 으로 용량 을 확대 한다.
    구체 적 으로 표준 라 이브 러 리 runtime 하의 slice.go 문 서 를 참고 할 수 있다.
    1. 가 변 긴 배열 실현
    우 리 는 간단 하고 정 수 를 저장 하 는 가 변 적 이 고 긴 배열 버 전 을 실현 합 니 다.Golang 의 제한 으로 인해 [n]int 고정 크기 n 의 정수 배열 을 만 들 수 없고 상수 로 만 크기 를 만 들 수 있 습 니 다.
    그래서 우 리 는 절편 의 일부 기능 을 사용 하여 배열 을 대체 할 것 이다. 절편 자체 가 가 변 적 이 고 긴 배열 이지 만 우 리 는 그것 의 append 기능 을 사용 하지 않 고 배열 로 만 사용 할 것 이다.
    import (
        "sync"
    )
    
    //      
    type Array struct {
        array []int      //        ,              
        len   int        //     
        cap   int        //   
        lock  sync.Mutex //           
    }
    

    1.1. 배열 초기 화len 개의 요 소 를 만 들 고 용량 cap 의 가 변 긴 배열 을 만 듭 니 다.
    //          
    func Make(len, cap int) *Array {
        s := new(Array)
        if len > cap {
            panic("len large than cap")
        }
    
        //        
        array := make([]int, cap, cap)
    
        //    
        s.array = array
        s.cap = cap
        s.len = 0
        return s
    }
    

    주로 만 용량 과 만 크기 의 절편 을 이용 하여 고정 배열, 구조 체 Array 안의 필드 lencap 를 이용 하여 값 의 접근 을 제어 한다.가 변 배열 len > cap 을 설정 할 수 없습니다.
    시간 복잡 도 는 다음 과 같다. O(1) 메모리 공간 을 분배 하고 몇 개의 값 을 설정 하 는 것 이 상수 시간 이기 때문이다.
    1.2. 요소 추가
    //       
    func (a *Array) Append(element int) {
        //    
        a.lock.Lock()
        defer a.lock.Unlock()
    
        //       ,        
        if a.len == a.cap {
            //    ,     ,     
            newCap := 2 * a.len
    
            //         0,      1
            if a.cap == 0 {
                newCap = 1
            }
    
            newArray := make([]int, newCap, newCap)
    
            //              
            for k, v := range a.array {
                newArray[k] = v
            }
    
            //     
            a.array = newArray
            a.cap = newCap
    
        }
    
        //         
        a.array[a.len] = element
        //     +1
        a.len = a.len + 1
    
    }
    

    먼저 가 변 긴 배열 에 요 소 를 추가 하면 자 물 쇠 를 추가 하여 병발 안전 을 확보 할 수 있 습 니 다.그리고 값 을 배열 에 넣 습 니 다. a.array[a.len] = element 그리고 len + 1 실제 크기 가 하나 더 많아 졌 음 을 나타 냅 니 다.
    실제 크기 len = cap 는 위치 가 다 떨 어 졌 음 을 나타 내 고 남 은 공간 이 새 값 을 넣 지 않 으 면 고정 크기 2*len 의 새 배열 을 만들어 서 오래된 배열 을 교체 합 니 다. a.array = newArray 물론 용량 도 커 집 니 다. a.cap = newCap처음에 설 치 된 용량 cap = 0 이 라면 새로운 용량 은 1 부터 다.
    요 소 를 추가 할 때 주로 오래된 배열 의 데 이 터 를 새 배열 로 이동 합 니 다. 시간 복잡 도 는 다음 과 같 습 니 다. O(n)물론 용량 이 충분 한 경우 시간 복잡 도 는 다음 과 같다. O(1).
    여러 요 소 를 추가 하 는 방법:
    //       
    func (a *Array) AppendMany(element ...int) {
        for _, v := range element {
            a.Append(v)
        }
    }
    

    간단하게 옮 겨 다 니 면서 Append 함 수 를 호출 합 니 다.그 중에서 ...intGolang 의 언어 특징 으로 여러 함수 변 수 를 나타 낸다.
    1.3. 지정 한 다음 요 소 를 가 져 옵 니 다.
    //          
    func (a *Array) Get(index int) int {
        //    
        if a.len == 0 || index >= a.len {
            panic("index over len")
        }
        return a.array[index]
    }
    

    가 변 긴 배열 의 실제 크기 가 0 이거 나 아래 표 index 가 실제 길이 len 를 초과 하면 panic 경 계 를 넘 을 것 이다.
    아래 표 시 된 값 만 가 져 오기 때문에 시간 복잡 도 는 O(1) 입 니 다.
    1.4. 실제 길이 와 용량 가 져 오기
    //       
    func (a *Array) Len() int {
        return a.len
    }
    
    //     
    func (a *Array) Cap() int {
        return a.cap
    }
    

    시간 복잡 도 O(1).
    예시
    현재 우 리 는 완전한 가 변 긴 배열 의 예 를 실행 합 니 다.
    package main
    
    import (
        "fmt"
        "sync"
    )
    
    //      
    type Array struct {
        array []int      //        ,              
        len   int        //     
        cap   int        //   
        lock  sync.Mutex //           
    }
    
    //          
    func Make(len, cap int) *Array {
        s := new(Array)
        if len > cap {
            panic("len large than cap")
        }
    
        //        
        array := make([]int, cap, cap)
    
        //    
        s.array = array
        s.cap = cap
        s.len = 0
        return s
    }
    
    //       
    func (a *Array) Append(element int) {
        //    
        a.lock.Lock()
        defer a.lock.Unlock()
    
        //       ,        
        if a.len == a.cap {
            //    ,     ,     
            newCap := 2 * a.len
    
            //         0,      1
            if a.cap == 0 {
                newCap = 1
            }
    
            newArray := make([]int, newCap, newCap)
    
            //              
            for k, v := range a.array {
                newArray[k] = v
            }
    
            //     
            a.array = newArray
            a.cap = newCap
    
        }
    
        //         
        a.array[a.len] = element
        //     +1
        a.len = a.len + 1
    
    }
    
    //       
    func (a *Array) AppendMany(element ...int) {
        for _, v := range element {
            a.Append(v)
        }
    
    }
    
    //          
    func (a *Array) Get(index int) int {
        //    
        if a.len == 0 || index >= a.len {
            panic("index over len")
        }
        return a.array[index]
    }
    
    //       
    func (a *Array) Len() int {
        return a.len
    }
    
    //     
    func (a *Array) Cap() int {
        return a.cap
    }
    
    //     
    func Print(array *Array) (result string) {
        result = "["
        for i := 0; i < array.Len(); i++ {
            //      
            if i == 0 {
                result = fmt.Sprintf("%s%d", result, array.Get(i))
                continue
            }
    
            result = fmt.Sprintf("%s %d", result, array.Get(i))
        }
        result = result + "]"
        return
    }
    
    func main() {
        //        3     
        a := Make(0, 3)
        fmt.Println("cap", a.Cap(), "len", a.Len(), "array:", Print(a))
    
        //       
        a.Append(10)
        fmt.Println("cap", a.Cap(), "len", a.Len(), "array:", Print(a))
    
        //       
        a.Append(9)
        fmt.Println("cap", a.Cap(), "len", a.Len(), "array:", Print(a))
    
        //       
        a.AppendMany(8, 7)
        fmt.Println("cap", a.Cap(), "len", a.Len(), "array:", Print(a))
    }
    

    출력:
    cap 3 len 0 array: []
    cap 3 len 1 array: [10]
    cap 3 len 2 array: [10 9]
    cap 6 len 4 array: [10 9 8 7]
    

    용량 이 자동 으로 배로 늘 어 나 는 것 을 볼 수 있다.
    총화
    가 변 긴 배열 은 실제 개발 에 있어 서 고정 크기 배열 을 바탕 으로 자동 으로 용량 확장 을 하 는 데 자주 사용 된다.
    이 데이터 구조의 사용 빈도 가 너무 높 기 때문에 Golang 이 데이터 형식 을 자동 으로 제공 합 니 다. 절편 (가 변 긴 배열).여러분 은 일반적으로 개발 과정 에서 이 유형 을 직접 사용 하면 됩 니 다.
    시리즈 문장 입구
    저 는 진성 입 니 다. 제 가 직접 쓴 데이터 구조 와 알고리즘 (Golang 실현) 을 읽 는 것 을 환영 합 니 다. 글 은 더욱 우호 적 인 GitBook 을 읽 는 데 첫 발 을 내 디 뎠 습 니 다.
  • 데이터 구조 와 알고리즘 (Golang 구현) (1) 단순 입문 Golang - 프롤로그
  • 데이터 구조 와 알고리즘 (Golang 구현) (2) 단순 입문 Golang - 패키지, 변수 와 함수
  • 데이터 구조 와 알고리즘 (Golang 구현) (3) 단순 입문 Golang - 프로 세 스 제어 문
  • 데이터 구조 와 알고리즘 (Golang 구현) (4) 단순 입문 Golang - 구조 체 와 방법
  • 데이터 구조 와 알고리즘 (Golang 구현) (5) 단순 입문 Golang - 인터페이스
  • 데이터 구조 와 알고리즘 (Golang 실현) (6) 간단 한 입문 Golang - 병발, 협 정 과 채널
  • 데이터 구조 와 알고리즘 (Golang 구현) (7) Golang - 표준 라 이브 러 리 단순 입문
  • 데이터 구조 와 알고리즘 (Golang 실현) (8.1) 기초 지식 - 선언
  • 데이터 구조 와 알고리즘 (Golang 실현) (8.2) 기초 지식 - 분 치 법 과 귀속
  • 데이터 구조 와 알고리즘 (Golang 실현) (9) 기초 지식 - 알고리즘 복잡 도와 점진 적 기호
  • 데이터 구조 와 알고리즘 (Golang 구현) (10) 기초 지식 - 알고리즘 복잡 도 메 인 방법
  • 데이터 구조 와 알고리즘 (Golang 구현) (11) 흔 한 데이터 구조 - 선언
  • 데이터 구조 와 알고리즘 (Golang 구현) (12) 흔 한 데이터 구조 - 링크
  • 데이터 구조 와 알고리즘 (Golang 구현) (13) 흔 한 데이터 구조 - 가 변 긴 배열
  • 데이터 구조 와 알고리즘 (Golang 구현) (14) 흔 한 데이터 구조 - 스 택 과 대기 열
  • 데이터 구조 와 알고리즘 (Golang 구현) (15) 흔 한 데이터 구조 - 목록
  • 데이터 구조 와 알고리즘 (Golang 구현) (16) 흔 한 데이터 구조 - 사전
  • 데이터 구조 와 알고리즘 (Golang 구현) (17) 흔 한 데이터 구조 - 트 리
  • 데이터 구조 와 알고리즘 (Golang 구현) (18) 정렬 알고리즘 - 선언
  • 데이터 구조 와 알고리즘 (Golang 구현) (19) 정렬 알고리즘 - 거품 정렬
  • 데이터 구조 와 알고리즘 (Golang 구현) (20) 정렬 알고리즘 - 정렬 선택
  • 데이터 구조 와 알고리즘 (Golang 구현) (21) 정렬 알고리즘 - 정렬 삽입
  • 데이터 구조 와 알고리즘 (Golang 구현) (22) 정렬 알고리즘 - 힐 정렬
  • 데이터 구조 와 알고리즘 (Golang 구현) (23) 정렬 알고리즘 - 병합 정렬
  • 데이터 구조 와 알고리즘 (Golang 구현) (24) 정렬 알고리즘 - 우선 대기 열 및 쌓 기 정렬
  • 데이터 구조 와 알고리즘 (Golang 구현) (25) 정렬 알고리즘 - 빠 른 정렬
  • 데이터 구조 와 알고리즘 (Golang 구현) (26) 검색 알고리즘 - 해시 표
  • 데이터 구조 와 알고리즘 (Golang 구현) (27) 검색 알고리즘 - 이 진 트 리
  • 데이터 구조 와 알고리즘 (Golang 구현) (28) 검색 알고리즘 - AVL 트 리
  • 데이터 구조 와 알고리즘 (Golang 구현) (29) 검색 알고리즘 - 2 - 3 트 리 와 좌경 적색 트 리
  • 데이터 구조 와 알고리즘 (Golang 구현) (30) 검색 알고리즘 - 2 - 3 - 4 트 리 와 일반 레 드 블랙 트 리
  • 좋은 웹페이지 즐겨찾기