見出し画像

バイナリーサーチツリー for TypeScript を ChatGPT に書かせると

入学しようかなと思う程度には、放送大学を好きなしょっさんです。

今朝ものんびりと見ていたんです。こちら。

今日の内容はバイナリーサーチツリー。この科目 Python でプログラム作ってアルゴリズムを学ぶ学習やってるんです。

授業の中で「これが最適なプログラムではありません。ChatGPTなどにも聞いてみましょう」みたいなこというんです。

なるほど。

ということで、適当な乱数をバイナリーサーチツリーにつっこんで、表示させるプログラムを ChatGPT4o に TypeScript で作ってもらいました。

表示のトコが授業と同じようにならなかったので、その辺だけ手を入れて作り直してみたコードがこちらです。

class TreeNode {
  value: number;
  left: TreeNode | null;
  right: TreeNode | null;

  constructor(value: number) {
    this.value = value;
    this.left = null;
    this.right = null;
  }
}

export class BinarySearchTree {
  root: TreeNode | null;

  constructor() {
    this.root = null;
  }

  // ノードの挿入
  insert(value: number): void {
    const newNode = new TreeNode(value);

    if (this.root === null) {
      this.root = newNode;
    } else {
      this.insertNode(this.root, newNode);
    }
  }

  private insertNode(node: TreeNode, newNode: TreeNode): void {
    if (newNode.value < node.value) {
      if (node.left === null) {
        node.left = newNode;
      } else {
        this.insertNode(node.left, newNode);
      }
    } else {
      if (node.right === null) {
        node.right = newNode;
      } else {
        this.insertNode(node.right, newNode);
      }
    }
  }

  // ノードの検索
  search(value: number): boolean {
    return this.searchNode(this.root, value) !== null;
  }

  private searchNode(node: TreeNode | null, value: number): TreeNode | null {
    if (node === null) {
      return null;
    }

    if (value < node.value) {
      return this.searchNode(node.left, value);
    } else if (value > node.value) {
      return this.searchNode(node.right, value);
    } else {
      return node;
    }
  }

  // ノードの削除
  remove(value: number): void {
    this.root = this.removeNode(this.root, value);
  }

  private removeNode(node: TreeNode | null, value: number): TreeNode | null {
    if (node === null) {
      return null;
    }

    if (value < node.value) {
      node.left = this.removeNode(node.left, value);
      return node;
    } else if (value > node.value) {
      node.right = this.removeNode(node.right, value);
      return node;
    } else {
      // 値が一致するノードが見つかった場合
      if (node.left === null && node.right === null) {
        return null; // 葉ノードの場合
      }

      if (node.left === null) {
        return node.right;
      }

      if (node.right === null) {
        return node.left;
      }

      // 両方の子ノードが存在する場合、右部分木の最小値を探して置き換える
      const tempNode = this.findMinNode(node.right);
      node.value = tempNode.value;
      node.right = this.removeNode(node.right, tempNode.value);
      return node;
    }
  }

  private findMinNode(node: TreeNode): TreeNode {
    while (node.left !== null) {
      node = node.left;
    }
    return node;
  }

  // ツリーの表示(in-order traversalを利用、深さ情報を出力)
  display(): void {
    this.inOrderTraversal(this.root, 0);
  }

  private inOrderTraversal(node: TreeNode | null, depth: number): void {
    if (node !== null) {
      this.inOrderTraversal(node.left, depth + 1);
      // console.log(`Value: ${node.value}, Depth: ${depth}`);
      for (let i = 0; i < depth; i++) {
        process.stdout.write('-');
      }
      console.log(node.value);
      this.inOrderTraversal(node.right, depth + 1);
    }
  }
}

function generateUniqueRandomNumbers(
  min: number,
  max: number,
  count: number
): number[] {
  if (count > max - min + 1) {
    throw new Error('範囲に対して数が多すぎます');
  }

  const numbers: number[] = [];
  for (let i = min; i <= max; i++) {
    numbers.push(i);
  }

  for (let i = numbers.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [numbers[i], numbers[j]] = [numbers[j], numbers[i]];
  }

  return numbers.slice(0, count);
}

// 1から10000の乱数を1000個、重複なく生成して表示する
const bst = new BinarySearchTree();
generateUniqueRandomNumbers(1, 10000, 100).forEach(value => bst.insert(value));

console.log('In-order Traversal with Depth:');
bst.display(); // ノードの値と深さが表示される

いやー凄いなー。手を入れたのは、ここだけ。

      // console.log(`Value: ${node.value}, Depth: ${depth}`);
      for (let i = 0; i < depth; i++) {
        process.stdout.write('-');
      }
      console.log(node.value);

これ以外は生成されたコードだけです。もっと洗練されたコードを作ることは可能だと思いますが、ちょっとお願いしたらすぱっと書いてくれるの本当にヤバイ。

出力サンプルはこんな感じ。

In-order Traversal with Depth:
-----67
----235
---428
------605
-------660
--------714
-----890
----945
--1384
  :
(中略)
  :
--9102
---9312
-9451
--9516
----9572
---9676
-----9700
------9756
----9860
-----9996

アルゴリズム面白いし生成AIも便利だけど、自分で考えずにこうやって出てくるのも考えものだな。とかちょっと冷静になってしまう。

おまけ

テストコードは GitHub Copilot に作ってもらいました。Jest です。

import {BinarySearchTree} from '../src/bst';

describe('BinarySearchTree', () => {
  test('insert and search', () => {
    const bst = new BinarySearchTree();
    bst.insert(10);
    bst.insert(5);
    bst.insert(15);
    bst.insert(3);
    bst.insert(7);
    bst.insert(12);
    bst.insert(18);

    expect(bst.search(10)).toBe(true);
    expect(bst.search(5)).toBe(true);
    expect(bst.search(15)).toBe(true);
    expect(bst.search(3)).toBe(true);
    expect(bst.search(7)).toBe(true);
    expect(bst.search(12)).toBe(true);
    expect(bst.search(18)).toBe(true);
    expect(bst.search(100)).toBe(false);
  });
  test('remove', () => {
    const bst = new BinarySearchTree();
    bst.insert(10);
    bst.insert(5);
    bst.insert(15);
    bst.insert(3);
    bst.insert(7);
    bst.insert(12);
    bst.insert(18);

    expect(bst.search(10)).toBe(true);
    bst.remove(10);
    expect(bst.search(10)).toBe(false);

    expect(bst.search(5)).toBe(true);
    bst.remove(5);
    expect(bst.search(5)).toBe(false);

    expect(bst.search(15)).toBe(true);
    bst.remove(15);
    expect(bst.search(15)).toBe(false);

    expect(bst.search(3)).toBe(true);
    bst.remove(3);
    expect(bst.search(3)).toBe(false);

    expect(bst.search(7)).toBe(true);
    bst.remove(7);
    expect(bst.search(7)).toBe(false);

    expect(bst.search(12)).toBe(true);
    bst.remove(12);
    expect(bst.search(12)).toBe(false);

    expect(bst.search(18)).toBe(true);
    bst.remove(18);
    expect(bst.search(18)).toBe(false);
  });

  test('remove root', () => {
    const bst = new BinarySearchTree();
    bst.insert(10);
    bst.insert(5);
    bst.insert(15);
    bst.insert(3);
    bst.insert(7);
    bst.insert(12);
    bst.insert(18);

    expect(bst.search(10)).toBe(true);
    bst.remove(10);
    expect(bst.search(10)).toBe(false);
  });
});

この記事が参加している募集

貴方がサポートしてくれると、私が幸せ。 私が幸せになると、貴方も幸せ。 新しいガジェット・ソフトウェアのレビューに、貴方の力が必要です。