Java 데이터 구조 및 알고리즘 시퀀스 테이블

        시퀀스 테이블은 일반적으로 어레이 스토리지를 사용하여 연속적인 물리적 주소를 갖는 스토리지 유닛의 세그먼트에 데이터 요소가 순차적으로 저장되는 선형 구조입니다. 어레이에서 데이터 추가, 삭제, 검색 및 수정을 완료합니다. 시퀀스 테이블은 일반적으로 다음과 같이 나눌 수 있습니다. 정적 시퀀스 테이블: 고정 길이 배열 스토리지를 사용합니다. 동적 시퀀스 테이블: 동적으로 개발된 어레이 스토리지를 사용합니다. 정적 시퀀스 테이블은 저장해야 하는 데이터의 양을 알 때 유용합니다. 정적 시퀀스 테이블의 고정 길이 배열로 인해 N이 커지고 공간이 너무 낭비되고 덜 부족하지 않습니다. 대조적으로 동적 시퀀스 테이블은 더 유연하고 공간의 크기가 동적으로 할당됩니다. 필요에 따라.

다음으로 동적 시퀀스 테이블을 구현해 보겠습니다.

먼저 구현할 인터페이스

 public class SeqList {
 
    // 打印顺序表 
    public void display() { }
 
    // 在 pos 位置新增元素 
    public void add(int pos, int data) { }
 
    // 判定是否包含某个元素 
    public boolean contains(int toFind) { return true; }
 
    // 查找某个元素对应的位置 
    public int search(int toFind) { return -1; }
 
    // 获取 pos 位置的元素 
    public int getPos(int pos) { return -1; }
 
    // 给 pos 位置的元素设为 value 
    public void setPos(int pos, int value) { }
 
    //删除第一次出现的关键字key 
    public void remove(int toRemove) { } 

    // 获取顺序表长度 
    public int size() { return 0; } 

    // 清空顺序表 
    public void clear() { }
}

둘째, 인터페이스의 실현

        1, 테이블의 프레임을 구축

        위 그림에서 알 수 있듯이 배열(int[] 요소)을 만들고 여기에 요소를 직접 추가해야 합니다. 동시에 이 테이블에 있는 배열의 크기도 알아야 하며 배열의 크기는 사용자가 결정합니다. 여기서는 초기 용량(int IntCapacity)이 10이라고 가정합니다. 이렇게 큰 테이블을 열었지만 모든 배열에 요소가 있는 것은 아닙니다. 이때 실제 크기인 실효 크기(int usedSize)를 알아야 합니다.

    public int[] elem;
    //有效的数据个数
    public int usedSize;
    //初始容量,且不能被改变
    public static final int intCapacity = 10;


    //创建对象并调用合适的构造方法
    public MyArrayList() {
        //创建一个初始容量为10个大小的数组对象
        this.elem = new int[intCapacity];
        this.usedSize = 0;
    }

       2. 주문표 인쇄

        먼저 시퀀스 테이블을 인쇄합니다. 인쇄 후에야 후속 인터페이스 구현이 올바른지 여부를 알 수 있습니다. 처음에는 테이블의 내용이 비어 있으므로 인쇄된 테이블은 자연스럽게 비어 있습니다. 여기서는 테이블에 내용이 있다고 가정합니다. 우리는 이 테이블을 순회하기만 하면 됩니다. 이 테이블의 유효한 요소를 인쇄하려면 IntCapacity이든 usedSize이든 순회 종료 조건을 지정해야 합니다.

// 打印顺序表
    public void display() {

        int i  = 0;
        for(i = 0; i < this.usedSize; i++) {
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
        //System.out.print(Arrays.toString(this.elem));
    }

       3. pos 위치에 요소 추가 

        여기서 우리는 다음을 고려해야 합니다. 1, 달성 방법은 무엇입니까? 2. 입력 위치가 이 배열의 유효한 범위 내에 있습니까? 3. 이 어레이가 가득 찰 것입니까? 가득 차면 어떻게 해야 합니까?

        우리는 먼저 이 문제를 구현하는 방법을 고려합니다. 먼저 pos 위치를 찾은 후 요소를 내부로 이동하고 요소를 삽입할 위치를 남겨 두어야 합니다. 그렇지 않으면 직접 삽입이 pos 위치의 내용을 덮어씁니다. 따라서 요소를 pos 뒤에 이동합니다. 이동할 때 마지막 위치부터 시작하고 그렇지 않으면 pos 위치에서 이동해도 여전히 덮어쓰는 문제가 발생합니다. 완료되면 usedSize++에서 수행합니다.

        다음으로 질문 2와 3을 고려하십시오. 질문 2의 경우 pos는 유효한 범위 내에 있으며 조작할 수 있습니다. 이 범위는 아래 첨자 0에서 usedSizes - 1까지입니다. 이 범위를 벗어나면 불법이므로 경고해야 합니다. 예외를 사용하거나 인쇄할 수 있습니다. 질문 3, 우리는 전체 상황을 판단해야 합니다. 요소를 추가할 때 usedSize(유효 길이)가 누적되며, 요소가 충분히 추가되면 usedSize는 배열의 용량 길이와 같습니다. 확장이 필요한지 판단하는 조건은 다음과 같습니다. 동시에 초기 용량은 변경할 수 없으므로 용량 확장 시 어레이를 복사하여 용량을 확장해야 한다는 점에 유의해야 합니다. Arrays의 copyOf 메소드를 사용하여 어레이를 복사함과 동시에 용량을 확장합니다.

    //检查pos位置合法性
    private void checkPos(int pos) {

        if(pos < 0 || pos > this.usedSize) {
            throw new RuntimeException("pos位置不合法!");
        }
    }

    //检查数组是否满的情况
    private boolean isFull() {

        if(this.elem.length == this.usedSize) {
            return true;
        }
        return false;
    }

    // 在 pos 位置新增元素
    public void add(int pos, int data) {

        //pos位置合法性
        checkPos(pos);
        //检查数组是否满了
        if(isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);
        }
        //新增元素
        for(int i = this.usedSize - 1; i >= pos; i--) {
            this.elem[i + 1] = this.elem[i];
        }
        this.elem[pos] = data;
        this.usedSize++;
    }

        4. 요소가 포함되었는지 확인

        이것은 순회한 다음 판단하기만 하면 됩니다.        

// 判定是否包含某个元素
    public boolean contains(int toFind) {

        for(int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

        5. 요소에 해당하는 위치 찾기

        이것은 순회한 다음 판단하기만 하면 됩니다. 유효성 검사 함수는 이전에 작성되었으며 직접 호출할 수 있습니다.  

    // 查找某个元素对应的位置
    public int search(int toFind) {

        //合法性检查
        checkPos(toFind);
        for(int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

      6. pos 위치의 요소 가져오기

        고려해야 할 질문: 1. 어떻게 찾을 수 있습니까? 2. 합법성? 3. 테이블이 비어 있습니까?

        앞서 pos의 유효성을 판단하는 함수를 작성했는데 여기서는 호출만 하면 됩니다. 이제 문제 3을 풀어보자. 테이블이 비어 있는지 확인해야 하는 이유는 무엇입니까? 테이블이 비어 있어 유효 길이가 0임을 나타냅니다. 즉, 반환할 요소가 없고 가져올 필요가 없습니다.

    //判断是否为空
    private boolean isEmpty() {
        return this.usedSize == 0;
    }

    // 获取 pos 位置的元素
    public int getPos(int pos) {

        //表是否为空
        if (isEmpty()) {
            //也可以进行打印
            throw new RuntimeException("表为空!");
        }
        //检查合法性
        if(pos < 0 || pos >= this.usedSize) {
            throw new RuntimeException("pos位置不合法!");
        }
        //获取元素
        return this.elem[pos];
    }

        7. pos 위치의 요소를 값으로 설정

        먼저 유효성을 확인한 다음 값을 덮어씁니다. 테이블이 비어 있는지 여부를 판단해야 합니다.

    // 给 pos 位置的元素设为 value
    public void setPos(int pos, int value) {

        checkPos(pos);
        if(isFull()) {
            throw new RuntimeException("表为空!");
        }
        this.elem[pos] = value;
    }

       8. 키워드 키의 첫 번째 항목 삭제 

        삭제 후 유효 길이를 --.

    //删除第一次出现的关键字key
    public void remove(int toRemove) {

        int pos = search(toRemove);
        if(pos == -1) {
            System.out.println("未找到该值!");
            return;
        }
        for(int i = pos; i < this.usedSize - 1; i++) {
            this.elem[i] = this.elem[i + 1];
        }
        this.usedSize--;
    }

        9. 시퀀스 테이블의 길이 가져오기

        시퀀스 테이블의 길이는 유효 길이입니다.

    // 获取顺序表长度
    public int size() {

        if (!isEmpty()) {
            return this.usedSize;
        }
        return 0;
    }

        10. 시퀀스 테이블 지우기

        유효 길이를 0으로 둡니다.

    // 清空顺序表
    public void clear() {

        this.usedSize = 0;
    }

3. 모든 코드 및 결과

import java.util.Arrays;

/**
 * @author: Naion
 * @create: 2021-12-26 14:56
 **/

public class MySeqlist {

    //定义一个顺序表
    private int[] elem;
    private int usedSize;
    private int intCapacity = 10;

    //调用合适的构造方法
    public MySeqlist() {
        //定义大小
        this.elem = new int[intCapacity];
        this.usedSize = 0;
    }

    // 打印顺序表
    public void display() {

        int i = 0;
        for(i = 0; i < this.usedSize; i++) {
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }

    //检查pos位置合法性
    private void checkPos(int pos) {

        if(pos < 0 || pos > this.usedSize) {
            throw new RuntimeException("pos位置不合法!");
        }
    }

    //检查数组是否满的情况
    private boolean isFull() {

        if(this.elem.length == this.usedSize) {
            return true;
        }
        return false;
    }

    // 在 pos 位置新增元素
    public void add(int pos, int data) {

        //pos位置合法性
        checkPos(pos);
        //检查数组是否满了
        if(isFull()) {
            this.elem = Arrays.copyOf(this.elem, 2 * this.elem.length);
        }
        //新增元素
        for(int i = this.usedSize - 1; i >= pos; i--) {
            this.elem[i + 1] = this.elem[i];
        }
        this.elem[pos] = data;
        this.usedSize++;
    }

    // 判定是否包含某个元素
    public boolean contains(int toFind) {

        for(int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    // 查找某个元素对应的位置
    public int search(int toFind) {

        //合法性检查
        checkPos(toFind);
        for(int i = 0; i < this.usedSize; i++) {
            if(this.elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

    //判断是否为空
    private boolean isEmpty() {
        return this.usedSize == 0;
    }

    // 获取 pos 位置的元素
    public int getPos(int pos) {

        //表是否为空
        if (isEmpty()) {
            throw new RuntimeException("表为空!");
        }
        //检查合法性
        if(pos < 0 || pos >= this.usedSize) {
            throw new RuntimeException("pos位置不合法!");
        }
        //获取元素
        return this.elem[pos];
    }

    // 给 pos 位置的元素设为 value
    public void setPos(int pos, int value) {

        checkPos(pos);
        if(isFull()) {
            throw new RuntimeException("表为空!");
        }
        this.elem[pos] = value;
    }

    //删除第一次出现的关键字key
    public void remove(int toRemove) {

        int pos = search(toRemove);
        if(pos == -1) {
            System.out.println("未找到该值!");
            return;
        }
        for(int i = pos; i < this.usedSize - 1; i++) {
            this.elem[i] = this.elem[i + 1];
        }
        this.usedSize--;
    }

    // 获取顺序表长度
    public int size() {

        if (!isEmpty()) {
            return this.usedSize;
        }
        return 0;
    }
    // 清空顺序表
    public void clear() {

        this.usedSize = 0;
    }
}
/**
 * @author: Naion
 * @create: 2021-12-26 14:55
 **/

public class test_12_26_01 {

    public static void main(String[] args) {

        MySeqlist myseqlist = new MySeqlist();
        for(int i = 0; i < 10; i++) {
            myseqlist.add(i, i);
        }
        myseqlist.display();
        System.out.println("======");
        myseqlist.add(1, 3);
        myseqlist.display();
        System.out.println("======");
        System.out.println(myseqlist.contains(3));
        System.out.println("======");
        System.out.println(myseqlist.search(3));
        System.out.println("======");
        System.out.println(myseqlist.getPos(1));
        System.out.println("======");
        myseqlist.setPos(1, 0);
        myseqlist.display();
        System.out.println("======");
        myseqlist.remove(0);
        myseqlist.display();
        System.out.println("======");
        System.out.println(myseqlist.size());
        System.out.println("======");
        myseqlist.clear();
        myseqlist.display();
    }
}

넷째, 시퀀스 테이블의 문제

1. 시퀀스 테이블의 중간/머리 부분에 삽입 및 삭제, 시간 복잡도는 O(N)

2. 용량을 늘리려면 새 공간을 신청하고 데이터를 복사하고 기존 공간을 해제해야 합니다. 약간의 소비가 있을 것입니다.

3. 용량 확장은 일반적으로 2배 증가하며 어느 정도 공간 낭비가 있을 수 밖에 없습니다. 예를 들어, 현재 용량이 100이고 꽉 차면 용량을 200으로 늘립니다. 계속해서 5개의 데이터를 삽입하고 나중에 데이터를 삽입하지 않으므로 95개의 데이터 공간이 낭비됩니다.

이러한 문제를 해결하려면 단일 연결 목록이 필요합니다. 

추천

출처blog.csdn.net/Naion/article/details/122186009