MikiTech

文系新卒エンジニアの学習記録

【基本情報】平成21年度春 午後Javaを解く

問題

※あくまで復習を兼ねています。間違っていたらご指摘おねがいします。 www.fe-siken.com

コード①

【プログラム1】

class GapBuffer{
    private static final int INITIAL_GAP_SIZE = 128;
    private char[] buffer;
    private int gapOffset = 0;
    private int gapSize = INITIAL_GAP_SIZE;

    GapBuffer(String initialText){
        buffer = new char[initialText.length() + gapSize];
        System.arraycopy(initialText.toCharArray(), 0, buffer, gapSize, initialText.length());
    }

    void insert(int offset, char ch){
        confirmGap(offset);
        buffer[gapOffset++] = ch;
        空欄A(問題)
    }

    void delete(int offset){
        if(length() == 0)
            return;
        confirmGap(offset + 1);
        gapOffset--;
        gapSize++;
    }

    char charAt(int offset){
        if(offset >= gapOffset)
            offset += 空欄B(問題)
        return buffer[offset];
    }

    int length(){return 空欄C;} (問題)

    private void confirmGap(int newGapOffset){
        if(gapSize == 0){
            char[] temp = new char[buffer.length + INITIAL_GAP_SIZE];
            System.arraycopy(buffer, 0, temp, 0, buffer.length);
            gapOffset = buffer.length;
            gapSize = INITIAL_GAP_SIZE;
            buffer = temp;
        }
        if(newGapOffset < gapOffset){
            System.arraycopy(buffer, newGapOffset, buffer, newGapOffset + gapSize, gapOffset - newGapOffset);
        }else{
            System.arraycopy(buffer, gapOffset + gapSize, buffer, gapOffset, newGapOffset - gapOffset);
        }
        gapOffset = newGapOffset;
    }
}

空欄ABCと表記

空欄aについて

ア:gapSize-- イ:gapSize++ ウ:gapSize - 1 エ:gapSize + 1
   void insert(int offset, char ch){
        confirmGap(offset);
        buffer[gapOffset++] = ch;
        空欄A(問題)
    }

insertメソッドは、問題文では

メソッド insert は,メソッド confirmGap を呼んで引数 offset の位置にギャップを 移動した上で,引数 offset で指定された位置に,引数 ch で指定された文字を挿入する。

とあり且つ挿入のイメージの説明では

まず,"プロ"の直後に"グラム"を移動することで,ギャップを"プログラム"と"説明"の間に移動する(図2②)。ギャップの先頭に"の"を格納する(図2③)。この操作によって,ギャップのサイズは1文字分小さくなり,ギャップの先頭位置は1文字分後ろへずれる。

とある。 これらの説明を踏まえ、insertメソッドを見てみるとギャップの移動を行っていると説明があるconfirmメソッド。
buffer[gapOffset++] = ch;で、説明にある「ギャップの先頭(gapOffset)に文字を格納する」という作業を行う。
なので残った作業はギャップのサイズは1文字分小さくなりという部分。
そのため選択肢のイとエは消える。

イとエはそれぞれ同じことをしているのだが、エのgapSize - 1というのは単独では使えない。
実際にコード書いてみるとコンパイルエラーが起こる。
おそらく正しくは、gapSize = gapSize - 1と再代入しなければならない。

よって答えは

空欄bについて

ア:buffer.length イ:gapOffset ウ:gapSize エ:length
   char charAt(int offset){
        if(offset >= gapOffset)
            offset += 空欄B(問題)
        return buffer[offset];
    }

空欄bがあるメソッドは、charAtメソッド。 charAtメソッドの説明は以下の通り。

メソッド charAt は,引数 offset で指定された位置の文字を返す。

引数offsetを説明の通り受けとっている。
gapOffsetはギャップの先頭位置で、offsetがギャップの先頭の位置より大きければどうする?という処理がif文内部。
ということは、offsetにgapSize分だけ足せばoffsetで指定した位置の文字が出力できるはず。

例えば、ABCDという4文字の文字列がある。
表示状は4文字だが、内部ではBとCの間にgapSize3つのギャップがある。

Dという文字を参照したいときは、内部では、ABC空空空Dとなっているはずなので、Dはoffset4とgapSize3を足した7になっているはずである。
なので答えは

       if(offset >= gapOffset)
            offset += 空欄B(問題)

この部分。
if文であるのに{}が省略されている。
JavaSilverでも問題に出されるように、if文の中括弧は省略可能である。

省略した場合は1行目の処理しか実行されない。

空欄cについて

lengthメソッドについて。

ア:buffer.length イ:buffer.length - gapOffset ウ:buffer.length - gapSize エ:buffer.length - INITIAL_GAP_SIZE
int length(){return C;}

問題文の説明では以下のように記載されている。

メソッド length は,テキストの文字数を返す。

f:id:Mikiyakupo:20200831124919p:plain
説明はこれだけだが、問題文の図を見ればいいように、配列bufferの長さからgapSizeを引けばいい。 ので答えは

コード②

【プログラム2】

public class Editor {
    private 【空欄D】 buf;
    private int cursor = 0;

    private Editor(String  text){
        buf = new GapBuffer(text);
    }

    private void run(){
        Display.output(buf,cursor);
        char ch;

        while((ch = CharReader.get()) != CharReader.EOF){
            switch(ch){
                case CharReader.MOVE_FORWARD:
                    moveCursor(1);
                    break;
                case CharReader.MOVE_BACKWARD:
                    moveCursor(-1);
                    break;
                case CharReader.MOVE_DELETE:
                    if(cursor < buf.length()){
                        buf.delete(【空欄E】);
                    }
                    break;
             default:
                buf.insert(【空欄F】,ch);
                break;
            }
            Display.output(buf,cursor);
        }
    }

    private void moveCursor(int n){
        int newCursor = cursor + n;
        if(newCursor >= 0 && newCursor <= buf.length()){
            cursor = newCursor;
        }
    }

    public static void main(String[] args) {
        Editor editor = new Editor(args[0]);
        editor.run();
    }
}

空欄dについて

ア:CharReader イ:DisplayEditor ウ:GapBuffer エ:Object オ:StringBuffer

空欄dは型名の問題。

   private 【空欄D】 buf;
    private int cursor = 0;

bufが使われている箇所をプログラム2の中で探すと、

buf = new GapBuffer(text);

GapBufferのインスタンスが代入されている。
そのため答えはウ。

空欄eとfについて

ア:--cursor イ:++cursor ウ:cursor エ:cursor-- オ:cursor++
   private void run(){
        Display.output(buf,cursor);
        char ch;

        while((ch = CharReader.get()) != CharReader.EOF){
            switch(ch){
                case CharReader.MOVE_FORWARD:
                    moveCursor(1);
                    break;
                case CharReader.MOVE_BACKWARD:
                    moveCursor(-1);
                    break;
                case CharReader.MOVE_DELETE:
                    if(cursor < buf.length()){
                        buf.delete(【空欄E】);
                    }
                    break;
             default:
                buf.insert(【空欄F】,ch);
                break;
            }
            Display.output(buf,cursor);
        }
    }

空欄eとfはそれぞれdで答えたbufのクラスのメソッドであるdeleteとinsertに何を渡せばよいかという問題。

ここでプログラム1を見てみると、

   void insert(int offset, char ch){
        confirmGap(offset);
        buffer[gapOffset++] = ch;
        空欄A(問題)
    }

    void delete(int offset){
        if(length() == 0)
            return;
        confirmGap(offset + 1);
        gapOffset--;
        gapSize++;
    }

とある。 deleteはoffset、つまり文字の位置を指定している。
問題文には、

カーソルは,文字の間にあり,カーソルの位置はオフセット値で表し,フィールド cursor に保持される

と記載されているため、そのままのcursorを渡せばいい。

続いてinsert。(これが厄介)
そもそもinsertメソッドが呼ばれている部分はここ

default:
    buf.insert(【空欄F】,ch);
break;

これはswitch文の制御でどこにも当てはまらなかった場合の処理を記載している。
この制御についての記載を探すと、

文字の入力は,外部で与えられるクラス CharReader で行う。メソッドgetは,ターミナルから1文字ずつ読み込む。CharReader には,次の制御文字が定義されている。制御文字以外の文字が入力されたときは,カーソルの位置に文字を挿入し,カーソルを1文字分進める

とある。つまり、cursorは+1されていれば良さそうだ。

イかオに定まる。

イ:++cursor オ:cursor++

これは前置インクリメント後置インクリメントの問題。
前置インクリメントは、先に+1してから処理を行い
後置インクリメントは、処理を行ってから+1する。

insertは、「与えられた数値の場所に挿入」する。 先の説明カーソルの位置に文字を挿入しにもあったので、ここは後置インクリメントのが正解。

だって5文字目に挿入したいのに、+1されて6文字目に挿入されたらおかしいよね。って問題。

答えまとめ

a=ア b=ウ c=ウ d=エ e=ウ f=オ 

最初Java難しくね‥‥と思いましたが、意外にもちゃんと問題文読めば解けそうな気がしてきました…! 引き続きがんばります。