HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

各言語でStack

手元にある各言語で、標準入力からの数値列をStackに放り込んで、入力とは逆順になるように標準出力に吐き出すプログラムを書いてみようと思ったメモ。

標準入力から入力される数値列の要件は以下の通り。

  • 1行に1つの数値が書かれている
    • 不正入力のチェックは不要とする
  • いくつの数値が入力されるかは不明(ただし、メモリがあふれることが無い程度に手加減する)
  • 入力される数値は符号付32ビット整数とする

前回と要件ややることは一緒だが、Stack構造を扱ってみようというのが今回の目的。

環境

手元にあるものということで、環境は以下のものに限定する。

入力ファイルの例

  • 001.txt
0
1
-1
256
-256
32768
-32768
2147483647
-2147483648

期待される出力の例

  • 001.txt
-2147483648
2147483647
-32768
32768
-256
256
-1
1
0

Java

import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        try (Scanner in = new Scanner(System.in);
            PrintWriter out = new PrintWriter(System.out)
        ) {
            Deque<Integer> stack = new ArrayDeque<>();

            while (in.hasNextInt()) {
                stack.push(in.nextInt());
            }

            while (stack.peek() != null) {
                out.println(stack.pop());
            }
        }
    }
}

Javaには、Stackとして使えるjava.util.Dequeの実装クラスがあるので、それを使って簡単に書ける。

C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int capacity;
    int size;
    int* elemData;
} IntStack;

IntStack* IntStack_new(int capacity) {
    IntStack* stack = (IntStack*)calloc(sizeof(IntStack), 1);
    stack->elemData = (int*)calloc(sizeof(int), capacity);
    stack->capacity = capacity;
    stack->size = 0;
    return stack;
}
void IntStack_destroy(IntStack* stack) {
    free(stack->elemData);
    free(stack);
}
int IntStack_isEmpty(IntStack* stack) {
    return stack->size == 0;
}
void IntStack_push(IntStack* stack, int elem) {
    if (stack->size + 1 > stack->capacity) {
        int newCapacity = stack->capacity * 2;
        int* newElemData = (int*)calloc(sizeof(int), newCapacity);
        memcpy(newElemData, stack->elemData, sizeof(int) * stack->size);
        free(stack->elemData);
        stack->elemData = newElemData;
        stack->capacity = newCapacity;
    }

    stack->elemData[(stack->size)++] = elem;
}
int IntStack_pop(IntStack* stack) {
    return stack->elemData[--(stack->size)];
}

int main(int argc, char** argv) {
    IntStack* stack = IntStack_new(256);

    int num;
    while (scanf("%ld", &num) == 1) {
        IntStack_push(stack, num);
    }

    while (!IntStack_isEmpty(stack)) {
        printf("%d\n", IntStack_pop(stack));
    }

    IntStack_destroy(stack);

    return 0;
}

C言語は当然自前実装。

C++

#include <algorithm>
#include <iostream>
#include <stack>

using namespace std;

int main(int argc, char** argv) {
    stack<int> stack;
    int num;

    while (cin >> num) {
        stack.push(num);
    }

    while (!stack.empty()) {
        cout << stack.top() << endl;
        stack.pop();
    }

    return EXIT_SUCCESS;
}

C++にはstackがあるので、それを使って簡単に書ける。

PHP

<?php

class Stack {
    private $elemData = array();
    public function isEmpty() {
        return count($this->elemData) === 0;
    }
    public function push($value) {
        array_push($this->elemData, $value);
    }
    public function pop() {
        $value = array_pop($this->elemData);
        return $value;
    }
}

$lines = file('php://stdin');

$stack = new Stack();

foreach ($lines as $line) {
    $stack->push((int)$line);
}

while (!$stack->isEmpty()) {
    printf("%d\n", $stack->pop());
}

PHPには標準ではStackクラスが無いので書いてみた。単なる配列のラッパー。

Python 2

import sys

class Stack:
    elemData = []
    def push(self, value):
        self.elemData.append(value)
    def pop(self):
        return self.elemData.pop()
    def isEmpty(self):
        return len(self.elemData) == 0

stack = Stack()
while True:
    line = sys.stdin.readline()
    if line == '':
        break
    stack.push(int(line))

while stack.isEmpty() != True:
    print stack.pop()

Python 2ではStackクラスが見当たらなかったので書いてみた。単なる配列のラッパー。

Python 3

import sys

class Stack:
    elemData = []
    def push(self, value):
        self.elemData.append(value)
    def pop(self):
        return self.elemData.pop()
    def isEmpty(self):
        return len(self.elemData) == 0

stack = Stack()
while True:
    line = sys.stdin.readline()
    if line == '':
        break
    stack.push(int(line))

while stack.isEmpty() != True:
    print(stack.pop())

Python 3ではStackクラスが見当たらなかったので書いてみた。単なる配列のラッパー。

Ruby

class Stack
    def initialize
        @elemData = []
    end
    def push(value)
        @elemData.push(value)
    end
    def pop
        @elemData.pop
    end
    def isEmpty
        return @elemData.size == 0
    end
end

stack = Stack.new
while line = STDIN.gets
    num = line.to_i
    stack.push(num)
end

while !stack.isEmpty
    print stack.pop(),"\n"
end

RubyではStackクラスが見当たらなかったので書いてみた。単なる配列のラッパー。

Perl

Perlにはpush/pop関数があるということだが、なんか微妙なので、2パターン書いてみた。

push/pop関数バージョン

my @stack = ();

my $line;
while ($line = readline(STDIN)) {
    my $num = $line + 0;
    push @stack, $num;
}

while ($#stack + 1 > 0) {
    my $value = @stack[$#stack];
    pop @stack;
    print "$value\n";
}

Stackモジュールバージョン

Stack.pm

package Stack;

sub new {
    my %self;
    my $class = shift;
    $self->{elemData} = ();
    $self->{size} = 0;
    return bless $self, $class;
}
sub push {
    my $self = shift;
    my $value = shift;
    $self->{elemData}[$self->{size}] = $value;
    ++$self->{size};
}
sub top {
    my $self = shift;
    return $self->{elemData}[$self->{size} - 1];
}
sub pop {
    my $self = shift;
    --$self->{size};
    delete $self->{elemData}[$self->{size}];
}
sub isEmpty {
    my $self = shift;
    return $self->{size} == 0;
}

1;

Main.pl

require "Stack.pm";

my $stack = Stack->new;

my $line;
while ($line = readline(STDIN)) {
    my $num = $line + 0;
    $stack->push($num);
}

while (!$stack->isEmpty()) {
    my $value = $stack->top();
    $stack->pop();
    print "$value\n";
}

Go

listをスタック代わりに直接使うということを考えたが、せっかくなので、Stackパッケージを作ってみた。

src/stack/stack.go

package stack;

import (
    "container/list"
)

type Stack struct {
    elemData *list.List
}

func (s *Stack) Init() *Stack {
    s.elemData = list.New()
    return s
}

func New() *Stack {
    return new(Stack).Init()
}

func (s *Stack) Push(v interface{}) {
    s.elemData.PushBack(v)
}

func (s *Stack) Pop() interface{} {
    e := s.elemData.Back()
    s.elemData.Remove(e)
    return e.Value
}

func (s *Stack) IsEmpty() bool {
    return s.elemData.Len() == 0
}

Main.go

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strconv"
    "stack"
)

func main() {
    aStack := stack.New()
    stdin := bufio.NewReader(os.Stdin)
    buf := make([]byte, 0, 1024)
    for {
        line, prefix, err := stdin.ReadLine()
        if err == io.EOF {
            break
        }
        buf = append(buf, line...)
        if prefix {
            continue
        }
        s := string(buf)
        num, err2 := strconv.Atoi(s)
        if err2 != nil {
            panic(err2)
        }
        buf = make([]byte, 0, 1024)

        aStack.Push(num)
    }

    for !aStack.IsEmpty() {
        fmt.Println(aStack.Pop())
    }
}

実行するときに、GOPATH=$(pwd) go run Main.goってしてやらないと、カレントディレクトリのソースを参照してくれないのでちょっとハマった。

bash

#! /bin/bash

stack=()

while IFS=$'\n' read line ; do
    num=$(echo ${line} | sed -e 's/^\([+-]*[0-9][0-9]*\).*/\1/')
    num=$((num+0))
    stack=(${num} "${stack[@]}")
done

while [ ${#stack[@]} -gt 0 ]; do
    echo ${stack[0]}
    stack=("${stack[@]:1}")
done

あえて配列を使って書いたが、65536行のデータを食わせたら全然返ってこなかったので、大量のデータを処理する際には素直に他の言語で書いた方が良い。