LoginSignup
1
0

More than 3 years have passed since last update.

Fortran で array list を作ってみた

Last updated at Posted at 2019-07-14

動機

前回は Fortran で linked list を実装しましたが、私が Java で普段よく使うのは ArrayList の方なので、今回は array list を実装します (前回記事 Fortran で linked list を作ってみた) 。配列が優秀な Fortran では array list の方が実装しやすいと思います。

array list とは

array list は要素を配列としてもつリストのことです。長さが固定されている配列とは異なり、長さを自由に変えることができるのが特徴です。 linked list と比較すると、要素の追加や削除は遅い $O(N)$ ですが、要素の検索は高速 $O(1)$ です。

環境

macOS Sierra (10.12.6)
GNU Fortran (GCC) 6.3.0

プログラム

実際に実装したのが以下のものです。

array_list.f08
module mod_array_list
  implicit none

  type t_array_list
    integer :: num = 0
    integer, pointer :: arr(:) => null()
  end type t_array_list

contains

  subroutine add(list,item)
    implicit none
    type(t_array_list), intent(inout) :: list
    integer, intent(in) :: item
    integer, allocatable :: tmp(:)

    if (.not.associated(list%arr)) allocate(list%arr(1))
    if (list%num == size(list%arr)) then
      allocate(tmp(list%num))
      tmp = list%arr
      deallocate(list%arr)
      allocate(list%arr(2*list%num))
      list%arr(1:list%num) = tmp
      deallocate(tmp)
    end if

    list%num = list%num+1
    list%arr(list%num) = item
    return
  end subroutine add

  subroutine clear(list)
    implicit none
    type(t_array_list), intent(inout) :: list

    if (associated(list%arr)) deallocate(list%arr)
    list%num = 0
    return
  end subroutine clear

  function get(list,i) result(item)
    implicit none
    type(t_array_list), intent(inout) :: list
    integer, intent(in) :: i
    integer :: item

    item = list%arr(i)
    return
  end function get

  function remove(list,i) result(item)
    implicit none
    type(t_array_list), intent(inout) :: list
    integer, intent(in) :: i
    integer :: item

    item = list%arr(i)
    list%arr(i:) = list%arr(i+1:)
    list%num = list%num-1
    return
  end function remove

  subroutine replace(list,i,item)
    implicit none
    type(t_array_list), intent(inout) :: list
    integer, intent(in) :: i
    integer :: item

    list%arr(i) = item
    return
  end subroutine replace

  function first_index_of(list,item) result(idx)
    implicit none
    type(t_array_list), intent(inout) :: list
    integer, intent(in) :: item
    integer :: idx, i

    idx = -1
    do i = 1, list%num
      if (list%arr(i) == item) then
        idx = i
        return
      end if
    end do
    return
  end function first_index_of

  function last_index_of(list,item) result(idx)
    implicit none
    type(t_array_list), intent(inout) :: list
    integer, intent(in) :: item
    integer :: idx, i

    idx = -1
    do i = list%num, 1, -1
      if (list%arr(i) == item) then
        idx = i
        return
      end if
    end do
    return
  end function last_index_of

  subroutine show_all(list)
    implicit none
    type(t_array_list), intent(inout) :: list
    integer :: i

    if (.not.associated(list%arr)) return
    write(*,'(i0)',advance='no') list%arr(1)
    do i = 2, list%num
      write(*,'(x,i0)',advance='no') list%arr(i)
    end do
    write(*,*)
    return
  end subroutine show_all

end module mod_array_list

また、実装できているか確認するために以下のプログラムも書きました。

test_array_list.f08
program test_array_list
  use mod_array_list
  implicit none
  type(t_array_list) :: list
  integer :: i, n = 3

  do i = 1, n
    call add(list,i)
    write(*,'("add: ",i0," size: ",i0)') i, list%num
  end do
  do i = 1, n
    call add(list,i)
    write(*,'("add: ",i0," size: ",i0)') i, list%num
  end do

  call show_all(list)

  write(*,'("first_index_of 2: ",i0," size: ",i0)') first_index_of(list,2), list%num

  write(*,'("last_index_of 2: ",i0," size: ",i0)') last_index_of(list,2), list%num

  write(*,'("remove at 3: ",i0," size: ",i0)') remove(list,3), list%num

  call show_all(list)

  call replace(list,3,9)
  write(*,'("replace at 3, size: ",i0)') list%num

  call show_all(list)

  write(*,'("get at 3: ",i0," size: ",i0)') get(list,3), list%num

  call show_all(list)

  call clear(list)
  write(*,'("clear, size: ",i0)') list%num

  call show_all(list)

  call add(list,10)
  write(*,'("add: ",i0," size: ",i0)') 10, list%num

  call show_all(list)

  stop
end program test_array_list

実行結果は以下のとおりです。

add: 1 size: 1
add: 2 size: 2
add: 3 size: 3
add: 1 size: 4
add: 2 size: 5
add: 3 size: 6
1 2 3 1 2 3
first_index_of 2: 2 size: 6
last_index_of 2: 5 size: 6
remove at 3: 3 size: 5
1 2 1 2 3
replace at 3, size: 5
1 2 9 2 3
get at 3: 9 size: 5
1 2 9 2 3
clear, size: 0
add: 10 size: 1
10

linked list よりも簡潔に実装できました。

追記 2019/08/11

不必要な部分を削り、よりオブジェクト指向な書き方に変更しました (ソースコード) 。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0