M.Hiroi's Home Page

Common Lisp Programming

お気楽 CLOS プログラミング入門

[ PrevPage | CLOS | NextPage ]

平衡木 : プログラムリスト

●AA 木

;;;
;;; aatree.lsp : 連想配列 (平衡木, AA tree, CLOS 用)
;;;
;;;              Copyright (C) 2023 Makoto Hiroi
;;;
(provide :aatree)
(defpackage :aatree (:use :cl))
(in-package :aatree)
(export '(make-treemap
          tree-emptyp
          tree-count
          tree-clear
          tree-exists
          tree-get
          tree-max
          tree-min
          tree-set
          tree-push
          tree-pop
          tree-del
          tree-max-del
          tree-min-del
          tree-mapc
          tree-fold-left
          tree-fold-right))

;;; メソッドの宣言
(defgeneric tree-emptyp (tm))
(defgeneric tree-count (tm))
(defgeneric tree-clear (tm))
(defgeneric tree-exists (tm k))
(defgeneric tree-get (tm k))
(defgeneric tree-max (tm))
(defgeneric tree-min (tm))
(defgeneric tree-set (tm k v))
(defgeneric tree-push (tm k v))
(defgeneric tree-pop (tm k))
(defgeneric tree-del (tm k))
(defgeneric tree-max-del (tm))
(defgeneric tree-min-del (tm))
(defgeneric tree-mapc (tm fn))
(defgeneric tree-fold-left (tm a fn))
(defgeneric tree-fold-right (tm a fn))

;;;
;;; 節の定義
;;;
(defclass node ()
  ((key    :accessor node-key    :initform nil :initarg :key)
   (value  :accessor node-value  :initform nil :initarg :value)
   (height :accessor node-height :initform 1   :initarg :height)
   (left   :accessor node-left   :initform nil :initarg :left)
   (right  :accessor node-right  :initform nil :initarg :right)))

;;; 終端
(defvar empty nil)

;;; 終端の生成
(defun make-empty ()
  (when (null empty)
    (setf empty (make-instance 'node)
          (node-height empty) 0
          (node-left empty) empty
          (node-right empty) empty))
  empty)

;;; 終端のチェック
(defun node-emptyp (node) (eq node empty))

;;;
;;; AA tree のバランス調整
;;;

;;; 右回転
(defun rotate-right (node)
  (let ((lnode (node-left node)))
    (setf (node-left node) (node-right lnode)
          (node-right lnode) node)
    lnode))

;;; 左回転
(defun rotate-left (node)
  (let ((rnode (node-right node)))
    (setf (node-right node) (node-left rnode)
          (node-left rnode) node)
    rnode))

;;; 左の子が赤の場合
(defun skew (node)
  (if (/= (node-height (node-left node)) (node-height node))
      node
    (rotate-right node)))

;;; 右の孫節が赤の場合
(defun split (node)
  (when (= (node-height node)
           (node-height (node-right (node-right node))))
    (setf node (rotate-left node)
          (node-height node) (+ (node-height node) 1)))
  node)

;;; 削除したときのバランスチェックと修正
(defun delete-balance (node)
  (let ((h (- (node-height node) 1)))
    (cond
     ((or (< (node-height (node-left node)) h)
          (< (node-height (node-right node)) h))
      (setf (node-height node) h)
      (when (> (node-height (node-right node)) h)
        (setf (node-height (node-right node)) h))
      (setf node (skew node)
            (node-right node) (skew (node-right node))
            (node-right (node-right node)) (skew (node-right (node-right node)))
            node (split node)
            (node-right node) (split (node-right node)))))
    node))

;;;
;;; 探索
;;;

;;; x と等しいキーを持つ node を返す
(defun node-search (node x elt= elt<)
  (cond
   ((node-emptyp node) empty)  ; キーが見つからない場合は空の木を返す
   ((funcall elt= (node-key node) x) node)
   ((funcall elt< x (node-key node))
    (node-search (node-left node) x elt= elt<))
   (t
    (node-search (node-right node) x elt= elt<))))

;;; 最小のキーを持つ node を返す
(defun node-search-min (node)
  (if (node-emptyp (node-left node))
      node
    (node-search-min (node-left node))))

;;; 最大のキーを持つ node を返す
(defun node-search-max (node)
  (if (node-emptyp (node-right node))
      node
    (node-search-max (node-right node))))

;;;
;;; 挿入
;;;

;;; キー x と値 vを挿入する
(defun node-insert (node x v elt= elt<)
  (cond
   ((node-emptyp node)
    ;; 新しい node を挿入する
    (make-instance 'node :key x :value v :left empty :right empty))
   ((funcall elt= (node-key node) x)
    ;; x と等しいキーがある
    (setf (node-value node) v)
    (throw 'key-found nil))
   ((funcall elt< x (node-key node))
    (setf (node-left node)
          (node-insert (node-left node) x v elt= elt<))
    (split (skew node)))
   (t
    (setf (node-right node)
          (node-insert (node-right node) x v elt= elt<))
    (split (skew node)))))

;;; キー x の値 (リスト) に v を push する
(defun node-push (node x v elt= elt<)
  (cond
   ((node-emptyp node)
    ;; 新しい node を挿入する (値は (list v) になる)
    (make-instance 'node :key x :value (list v) :left empty :right empty))
   ((funcall elt= (node-key node) x)
    ;; x と等しいキーがある
    (setf (node-value node) (cons v (node-value node)))
    (throw 'key-found nil))
   ((funcall elt< x (node-key node))
    (setf (node-left node)
          (node-push (node-left node) x v elt= elt<))
    (split (skew node)))
   (t
    (setf (node-right node)
          (node-push (node-right node) x v elt= elt<))
    (split (skew node)))))

;;;
;;; 削除
;;;

;;; 最大のキーとその値を削除
(defun node-delete-max (node)
  (cond
   ((node-emptyp (node-right node)) (node-left node))
   (t
    (setf (node-right node)
          (node-delete-max (node-right node)))
    (delete-balance node))))

;;; 最小のキーとその値を削除
(defun node-delete-min (node)
  (cond
   ((node-emptyp (node-left node)) (node-right node))
   (t
    (setf (node-left node)
          (node-delete-min (node-left node)))
    (delete-balance node))))

;;; キー key と等しい node を削除
(defun node-delete (node key elt= elt<)
  (cond
   ((node-emptyp node)
    ;; キーが見つからない
    (throw 'key-not-found nil))
   ((funcall elt= key (node-key node))
    ;; キーを発見
    (cond
     ((node-emptyp (node-left node)) (node-right node))
     ((node-emptyp (node-right node)) (node-left node))
     (t
      (let ((del-node (node-search-min (node-right node))))
        (setf (node-key node) (node-key del-node)
              (node-value node) (node-value del-node)
              (node-right node) (node-delete-min (node-right node)))
        (delete-balance node)))))
   ((funcall elt< key (node-key node))
    (setf (node-left node)
          (node-delete (node-left node) key elt= elt<))
    (delete-balance node))
   (t
    (setf (node-right node)
          (node-delete (node-right node) key elt= elt<))
    (delete-balance node))))

;;;
;;; 高階関数
;;;

;;; 巡回
(defun node-traverse (func node)
  (cond
   ((not (node-emptyp node))
    (node-traverse func (node-left node))
    (funcall func (node-key node) (node-value node))
    (node-traverse func (node-right node)))))

;;; 畳み込み (左部分木から)
(defun node-fold-left (func a node)
  (if (node-emptyp node)
      a
    (let ((b (node-fold-left func a (node-left node))))
      (node-fold-left func (funcall func b (node-key node) (node-value node)) (node-right node)))))

;;; 畳み込み (右部分木から)
(defun node-fold-right (func a node)
  (if (node-emptyp node)
      a
    (let ((b (node-fold-right func a (node-right node))))
      (node-fold-right func (funcall func b (node-key node) (node-value node)) (node-left node)))))

;;;
;;; treemap の定義
;;;
(defclass treemap ()
  ((root :accessor tree-root :initform nil :initarg :root)
   (size :accessor tree-size :initform 0   :initarg :size)
   (elt= :accessor tree-elt= :initform nil :initarg :elt=)
   (elt< :accessor tree-elt< :initform nil :initarg :elt<)))

;;; コンストラクタ
(defun make-treemap (elt= elt<)
  (make-instance 'treemap :root (make-empty) :elt= elt= :elt< elt<))

;;; treemap は空か?
(defmethod tree-emptyp ((tm treemap)) (node-emptyp (tree-root tm)))

;;; treemap のデータ数を返す
(defmethod tree-count ((tm treemap)) (tree-size tm))

;;; treemap を空にする
(defmethod tree-clear ((tm treemap))
  (setf (tree-root tm) empty
        (tree-size tm) 0))

;;; キーが存在すれば t を返す
(defmethod tree-exists ((tm treemap) key)
  (not (node-emptyp (node-search (tree-root tm) key (tree-elt= tm) (tree-elt< tm)))))

;;; キーの値を返す (見つからない場合は nil を返す)
(defmethod tree-get ((tm treemap) key)
  (node-value (node-search (tree-root tm) key (tree-elt= tm) (tree-elt< tm))))

;;; 最大の (key . val) を返す
(defmethod tree-max ((tm treemap))
  (if (tree-emptyp tm)
      nil
    (let ((node (node-search-max (tree-root tm))))
      (cons (node-key node) (node-value node)))))

;;; 最小の (key . val) を返す
(defmethod tree-min ((tm treemap))
  (if (tree-emptyp tm)
      nil
    (let ((node (node-search-min (tree-root tm))))
      (cons (node-key node) (node-value node)))))

;;; キーと値をセットする
;;; 新規追加の場合は t を返す。同じキーを見つけたら、値を書き換えて nil を返す
(defmethod tree-set ((tm treemap) key value)
  (catch 'key-found
    (setf (tree-root tm)
          (node-insert (tree-root tm) key value (tree-elt= tm) (tree-elt< tm)))
    (incf (tree-size tm))
    t))

;;; キーが新規の場合、キーの値に (list value) を追加して t を返す
;;; キーが存在する場合、その先頭に value を追加して nil を返す
(defmethod tree-push ((tm treemap) key value)
  (catch 'key-found
    (setf (tree-root tm)
          (node-push (tree-root tm) key value (tree-elt= tm) (tree-elt< tm)))
    (incf (tree-size tm))
    t))

;;; キーが存在して値がリストの場合、リストからデータを pop する
;;; それ以外は nil を返す
(defmethod tree-pop ((tm treemap) key)
  (let ((node (node-search (tree-root tm) key (tree-elt= tm) (tree-elt< tm))))
    (when (consp (node-value node))
      (pop (node-value node)))))

;;; キーとその値を削除して t を返す
;;; キーが見つからない場合は nil を返す
(defmethod tree-del ((tm treemap) key)
  (catch 'key-not-found
    (setf (tree-root tm)
          (node-delete (tree-root tm) key (tree-elt= tm) (tree-elt< tm)))
    (decf (tree-size tm))
    t))

;;; 最大の key, value を削除して t を返す
(defmethod tree-max-del ((tm treemap))
  (unless (tree-emptyp tm)
    (setf (tree-root tm) (node-delete-max (tree-root tm)))
    (decf (tree-size tm))
    t))

;;; 最小の key, value を削除して t を返す
(defmethod tree-min-del ((tm treemap))
  (unless (tree-emptyp tm)
    (setf (tree-root tm) (node-delete-min (tree-root tm)))
    (decf (tree-size tm))
    t))

;;; キーと値に関数 fn を適用する
(defmethod tree-mapc ((tm treemap) fn)
  (node-traverse fn (tree-root tm)))

;;; 左部分木からの畳み込み
(defmethod tree-fold-left ((tm treemap) a fn)
  (node-fold-left fn a (tree-root tm)))

;;; 右部分木からの畳み込み
(defmethod tree-fold-right ((tm treemap) a fn)
  (node-fold-right fn a (tree-root tm)))

●赤黒木

;;;
;;; rbtree.lsp : 連想配列 (赤黒木, CLOS 版)
;;;
;;;              Copyright (C) 2023 Makoto Hiroi
;;;

(provide :rbtree)
(defpackage :rbtree (:use :cl))
(in-package :rbtree)
(export '(make-treemap
          tree-emptyp
          tree-count
          tree-clear
          tree-exists
          tree-get
          tree-max
          tree-min
          tree-set
          tree-push
          tree-pop
          tree-del
          tree-max-del
          tree-min-del
          tree-mapc
          tree-fold-left
          tree-fold-right))

;;; メソッドの宣言
(defgeneric tree-emptyp (tm))
(defgeneric tree-count (tm))
(defgeneric tree-clear (tm))
(defgeneric tree-exists (tm k))
(defgeneric tree-get (tm k))
(defgeneric tree-max (tm))
(defgeneric tree-min (tm))
(defgeneric tree-set (tm k v))
(defgeneric tree-push (tm k v))
(defgeneric tree-pop (tm k))
(defgeneric tree-del (tm k))
(defgeneric tree-max-del (tm))
(defgeneric tree-min-del (tm))
(defgeneric tree-mapc (tm fn))
(defgeneric tree-fold-left (tm a fn))
(defgeneric tree-fold-right (tm a fn))

;;; 終端
(defvar empty nil)

;;;
;;; 節の定義
;;;
(defclass node ()
  ((key   :accessor node-key   :initform nil   :initarg :key)
   (value :accessor node-value :initform nil   :initarg :value)
   (color :accessor node-color :initform 'red  :initarg :color)
   (left  :accessor node-left  :initform empty :initarg :left)
   (right :accessor node-right :initform empty :initarg :right)))

;;; 終端の生成
(defun make-empty ()
  (when (null empty)
    (setf empty
          (make-instance 'node :color 'black :left nil :right nil)))
  empty)

;;; 終端のチェック
(defun node-emptyp (node) (eq node empty))

;;; 色のチェック
(defun node-blackp (node) (eq (node-color node) 'black))
(defun node-redp (node) (eq (node-color node) 'red))

;;;
;;; バランスの修正処理
;;;

;;; 右回転
(defun rotate-right (node)
  (let ((lnode (node-left node)))
    (setf (node-left node) (node-right lnode)
          (node-right lnode) node
          (node-color lnode) (node-color node)
          (node-color node) 'red)
    lnode))

;;; 左回転
(defun rotate-left (node)
  (let ((rnode (node-right node)))
    (setf (node-right node) (node-left rnode)
          (node-left rnode) node
          (node-color rnode) (node-color node)
          (node-color node) 'red)
    rnode))

;;; 4node の分割
(defun node-split (node)
  (setf (node-color node) 'red
        (node-color (node-left node)) 'black
        (node-color (node-right node)) 'black))

;;; 左部分木の修正
(defun balance-insert-left (node flag)
  (unless flag
    (when (node-blackp node)
      (setf flag t)
      ;; 左(赤)の子に赤があるか
      (when (node-redp (node-right (node-left node)))
        (setf (node-left node)
              (rotate-left (node-left node))))
      (when (node-redp (node-left (node-left node)))
        ;; 赤が 2 つ続く
        (if (node-redp (node-right node))
            (progn
              (node-split node)
              (setf flag nil))
          (setf node (rotate-right node))))))
  (values node flag))

(defun balance-delete-left (node flag)
  (unless flag
    (cond
     ((and (node-blackp (node-left (node-right node)))
           (node-blackp (node-right (node-right node))))
      ;; right is 2 node
      (cond
       ((node-blackp (node-right node))
        ;; node is 2 node
        (setf (node-color (node-right node)) 'red)
        (when (node-blackp node)
          (return-from balance-delete-left (values node nil)))
        (setf (node-color node) 'black))
       (t
        ;; node is 3 node
        (setf node (rotate-left node)
              (node-left node) (balance-delete-left (node-left node) nil)))))
     (t
      ;; right is 3, 4 node
      (when (node-redp (node-left (node-right node)))
        (setf (node-right node) (rotate-right (node-right node))))
      (setf node (rotate-left node)
            (node-color (node-left node)) 'black
            (node-color (node-right node)) 'black))))
  (values node t))

;;; 右部分木の修正
(defun balance-insert-right (node flag)
  (unless flag
    (when (node-blackp node)
      (setf flag t)
      ;; 右(赤)の子に赤があるか
      (when (node-redp (node-left (node-right node)))
        (setf (node-right node)
              (rotate-right (node-right node))))
      (when (node-redp (node-right (node-right node)))
        ;; 赤が 2 つ続く
        (if (node-redp (node-left node))
            (progn
              (node-split node)
              (setf flag nil))
          (setf node (rotate-left node))))))
  (values node flag))

(defun balance-delete-right (node flag)
  (unless flag
    (cond
     ((and (node-blackp (node-left (node-left node)))
           (node-blackp (node-right (node-left node))))
      (cond
       ((node-blackp (node-left node))
        ;; left is 2 node
        (setf (node-color (node-left node)) 'red)
        (when (node-blackp node)
          (return-from balance-delete-right (values node nil)))
        (setf (node-color node) 'black))
       (t
        (setf node (rotate-right node)
              (node-right node) (balance-delete-right (node-right node) nil)))))
     (t
      ;; node is 3, 4 node
      (when (node-redp (node-right (node-left node)))
        (setf (node-left node)
              (rotate-left (node-left node))))
      (setf node (rotate-right node)
            (node-color (node-right node)) 'black
            (node-color (node-left node)) 'black))))
  (values node t))

;;;
;;; 探索
;;;
(defun node-search (node key elt= elt<)
  (cond
   ((node-emptyp node) empty)
   ((funcall elt= key (node-key node)) node)
   ((funcall elt< key (node-key node))
    (node-search (node-left node) key elt= elt<))
   (t
    (node-search (node-right node) key elt= elt<))))

;;; 最小のキーを持つ node を返す
(defun node-search-min (node)
  (if (node-emptyp (node-left node))
      node
    (node-search-min (node-left node))))

;;; 最大のキーを持つ node を返す
(defun node-search-max (node)
  (if (node-emptyp (node-right node))
      node
    (node-search-max (node-right node))))

;;;
;;; 挿入
;;;
(defun node-insert (node key x elt= elt<)
  (cond
   ((node-emptyp node)
    ;; 新しい節を挿入する
    (values (make-instance 'node :key key :value x) nil))
   ((funcall elt= key (node-key node))
    ;; 同じキーを見つけたので値を書き換える
    (setf (node-value node) x)
    (throw 'key-found nil))
   ((funcall elt< key (node-key node))
    ;; 左部分木をたどる
    (multiple-value-bind
     (node1 flag)
     (node-insert (node-left node) key x elt= elt<)
     (setf (node-left node) node1)
     (multiple-value-setq (node1 flag) (balance-insert-left node flag))
     (values node1 flag)))
   (t
    ;; 右部分木をたどる
    (multiple-value-bind
     (node1 flag)
     (node-insert (node-right node) key x elt= elt<)
     (setf (node-right node) node1)
     (multiple-value-setq (node1 flag) (balance-insert-right node flag))
     (values node1 flag)))))

(defun node-push (node key x elt= elt<)
  (cond
   ((node-emptyp node)
    ;; 新しい節を挿入する
    (values (make-instance 'node :key key :value (list x)) nil))
   ((funcall elt= key (node-key node))
    ;; 同じキーを見つけたので値を書き換える
    (setf (node-value node) (cons x (node-value node)))
    (throw 'key-found nil))
   ((funcall elt< key (node-key node))
    ;; 左部分木をたどる
    (multiple-value-bind
     (node1 flag)
     (node-push (node-left node) key x elt= elt<)
     (setf (node-left node) node1)
     (multiple-value-setq (node1 flag) (balance-insert-left node flag))
     (values node1 flag)))
   (t
    ;; 右部分木をたどる
    (multiple-value-bind
     (node1 flag)
     (node-push (node-right node) key x elt= elt<)
     (setf (node-right node) node1)
     (multiple-value-setq (node1 flag) (balance-insert-right node flag))
     (values node1 flag)))))

;;;
;;; 削除
;;;

;;; 最大のキーとその値を削除
(defun node-delete-max (node)
  (cond
   ((node-emptyp (node-right node))
    (cond
     ((node-emptyp (node-left node))
      (values empty (node-redp node)))
     (t
      (setf (node-color (node-left node)) 'black)
      (values (node-left node) t))))
   (t
    (multiple-value-bind
     (node1 flag)
     (node-delete-max (node-right node))
     (setf (node-right node) node1)
     (multiple-value-setq (node1 flag) (balance-delete-right node flag))
     (values node1 flag)))))

;;; 最小のキーとその値を削除
(defun node-delete-min (node)
  (cond
   ((node-emptyp (node-left node))
    (cond
     ((node-emptyp (node-right node))
      (values empty (node-redp node)))
     (t
      (setf (node-color (node-right node)) 'black)
      (values (node-right node) t))))
   (t
    (multiple-value-bind
     (node1 flag)
     (node-delete-min (node-left node))
     (setf (node-left node) node1)
     (multiple-value-setq (node1 flag) (balance-delete-left node flag))
     (values node1 flag)))))

;;; キー key と等しい node を削除
(defun node-delete (node key elt= elt<)
  (cond
   ((node-emptyp node)
    (throw 'key-not-found nil))
   ((funcall elt= key (node-key node))
    (cond
     ((and (node-emptyp (node-left node))
           (node-emptyp (node-right node)))
      (values empty (node-redp node)))
     ((node-emptyp (node-right node))
      (setf (node-color (node-left node)) 'black)
      (values (node-left node) t))
     ((node-emptyp (node-left node))
      (setf (node-color (node-right node)) 'black)
      (values (node-right node) t))
     (t
      (let ((del-node (node-search-min (node-right node))))
        (setf (node-key node) (node-key del-node)
              (node-value node) (node-value del-node))
        (multiple-value-bind
         (node1 flag)
         (node-delete-min (node-right node))
         (setf (node-right node) node1)
         (multiple-value-setq (node1 flag) (balance-delete-right node flag))
         (values node1 flag))))))
   ((funcall elt< key (node-key node))
    (multiple-value-bind
     (node1 flag)
     (node-delete (node-left node) key elt= elt<)
     (setf (node-left node) node1)
     (multiple-value-setq (node1 flag) (balance-delete-left node flag))
     (values node1 flag)))
   (t
    (multiple-value-bind
     (node1 flag)
     (node-delete (node-right node) key elt= elt<)
     (setf (node-right node) node1)
     (multiple-value-setq (node1 flag) (balance-delete-right node flag))
     (values node1 flag)))))

;;;
;;; 高階関数
;;;

;;; 巡回
(defun node-traverse (func node)
  (cond
   ((not (node-emptyp node))
    (node-traverse func (node-left node))
    (funcall func (node-key node) (node-value node))
    (node-traverse func (node-right node)))))

;;; 畳み込み (左部分木から)
(defun node-fold-left (func a node)
  (if (node-emptyp node)
      a
    (let ((b (node-fold-left func a (node-left node))))
      (node-fold-left func (funcall func b (node-key node) (node-value node)) (node-right node)))))

;;; 畳み込み (右部分木から)
(defun node-fold-right (func a node)
  (if (node-emptyp node)
      a
    (let ((b (node-fold-right func a (node-right node))))
      (node-fold-right func (funcall func b (node-key node) (node-value node)) (node-left node)))))

;;;
;;; 連想配列 (赤黒木) の定義
;;;
(defclass treemap ()
  ((root :accessor tree-root :initform nil :initarg :root)
   (size :accessor tree-size :initform 0   :initarg :size)
   (elt= :accessor tree-elt= :initform nil :initarg :elt=)
   (elt< :accessor tree-elt< :initform nil :initarg :elt<)))

;;; コンストラクタ
(defun make-treemap (elt= elt<)
  (make-instance 'treemap :root (make-empty) :elt= elt= :elt< elt<))

;;; treemap は空か?
(defmethod tree-emptyp ((tm treemap)) (node-emptyp (tree-root tm)))

;;; treemap のデータ数を返す
(defmethod tree-count ((tm treemap)) (tree-size tm))

;;; treemap を空にする
(defmethod tree-clear ((tm treemap))
  (setf (tree-root tm) empty
        (tree-size tm) 0))

;;; キーが存在すれば t を返す
(defmethod tree-exists ((tm treemap) key)
  (not (node-emptyp (node-search (tree-root tm) key (tree-elt= tm) (tree-elt< tm)))))

;;; キーの値を返す (見つからない場合は nil を返す)
(defmethod tree-get ((tm treemap) key)
  (node-value (node-search (tree-root tm) key (tree-elt= tm) (tree-elt< tm))))

;;; 最大の (key . val) を返す
(defmethod tree-max ((tm treemap))
  (if (tree-emptyp tm)
      nil
    (let ((node (node-search-max (tree-root tm))))
      (cons (node-key node) (node-value node)))))

;;; 最小の (key . val) を返す
(defmethod tree-min ((tm treemap))
  (if (tree-emptyp tm)
      nil
    (let ((node (node-search-min (tree-root tm))))
      (cons (node-key node) (node-value node)))))

;;; キーと値をセットする
;;; 新規追加の場合は t を返す。同じキーを見つけたら、値を書き換えて nil を返す
(defmethod tree-set ((tm treemap) key value)
  (catch 'key-found
    (setf (tree-root tm) (node-insert (tree-root tm) key value (tree-elt= tm) (tree-elt< tm))
          (node-color (tree-root tm)) 'black)
    (incf (tree-size tm))
    t))

;;; キーが新規の場合、キーの値に (list value) を追加して t を返す
;;; キーが存在する場合、その先頭に value を追加して nil を返す
(defmethod tree-push ((tm treemap) key value)
  (catch 'key-found
    (setf (tree-root tm) (node-push (tree-root tm) key value (tree-elt= tm) (tree-elt< tm))
          (node-color (tree-root tm)) 'black)
    (incf (tree-size tm))
    t))

;;; キーが存在して値がリストの場合、リストからデータを pop する
;;; それ以外は nil を返す
(defmethod tree-pop ((tm treemap) key)
  (let ((node (node-search (tree-root tm) key (tree-elt= tm) (tree-elt< tm))))
    (when (consp (node-value node))
      (pop (node-value node)))))

;;; キーとその値を削除して t を返す
;;; キーが見つからない場合は nil を返す
(defmethod tree-del ((tm treemap) key)
  (catch 'key-not-found
    (setf (tree-root tm) (node-delete (tree-root tm) key (tree-elt= tm) (tree-elt< tm))
          (node-color (tree-root tm)) 'black)
    (decf (tree-size tm))
    t))

;;; 最大の key, value を削除して t を返す
(defmethod tree-max-del ((tm treemap))
  (unless (tree-emptyp tm)
    (setf (tree-root tm) (node-delete-max (tree-root tm)))
    (decf (tree-size tm))
    t))

;;; 最小の key, value を削除して t を返す
(defmethod tree-min-del ((tm treemap))
  (unless (tree-emptyp tm)
    (setf (tree-root tm) (node-delete-min (tree-root tm)))
    (decf (tree-size tm))
    t))

;;; キーと値に関数 fn を適用する
(defmethod tree-mapc ((tm treemap) fn)
  (node-traverse fn (tree-root tm)))

;;; 左部分木からの畳み込み
(defmethod tree-fold-left ((tm treemap) a fn)
  (node-fold-left fn a (tree-root tm)))

;;; 右部分木からの畳み込み
(defmethod tree-fold-right ((tm treemap) a fn)
  (node-fold-right fn a (tree-root tm)))

●スプレー木

;;;
;;; splay.lsp : スプレー木 (Top Down Splay, CLOS 用)
;;;
;;;             Copyright (C) 2023 Makoto Hiroi
;;;
(provide :splay)
(defpackage :splay (:use :cl))
(in-package :splay)
(export '(make-treemap
          tree-emptyp
          tree-count
          tree-clear
          tree-exists
          tree-get
          tree-max
          tree-min
          tree-set
          tree-push
          tree-pop
          tree-del
          tree-max-del
          tree-min-del
          tree-mapc
          tree-fold-left
          tree-fold-right))

;;; メソッドの定義
(defgeneric tree-emptyp (tm))
(defgeneric tree-count (tm))
(defgeneric tree-clear (tm))
(defgeneric tree-exists (tm k))
(defgeneric tree-get (tm k))
(defgeneric tree-max (tm))
(defgeneric tree-min (tm))
(defgeneric tree-set (tm k v))
(defgeneric tree-push (tm k v))
(defgeneric tree-pop (tm k))
(defgeneric tree-del (tm k))
(defgeneric tree-max-del (tm))
(defgeneric tree-min-del (tm))
(defgeneric tree-mapc (tm fn))
(defgeneric tree-fold-left (tm a fn))
(defgeneric tree-fold-right (tm a fn))

;;;
;;; 節の定義 (終端は nil)
;;;
(defclass node ()
  ((key    :accessor node-key    :initform nil :initarg :key)
   (value  :accessor node-value  :initform nil :initarg :value)
   (left   :accessor node-left   :initform nil :initarg :left)
   (right  :accessor node-right  :initform nil :initarg :right)))

;;;
;;; splay 操作関数
;;;

;;; 右回転
(defun rotate-right (node)
  (let ((lnode (node-left node)))
    (setf (node-left node) (node-right lnode)
          (node-right lnode) node)
    lnode))

;;; 左回転
(defun rotate-left (node)
  (let ((rnode (node-right node)))
    (setf (node-right node) (node-left rnode)
          (node-left rnode) node)
    rnode))

;;; Top-Down Splay
(defun node-splay (node key elt= elt<)
  (let* ((wnode (make-instance 'node))  ; Splay 作業用セル
         (rnode wnode)                  ; rnode は右部分木になる節を追加する
         (lnode wnode))                 ; lnode は左部分木になる節を追加する
    (loop
     (cond
      ((funcall elt= key (node-key node)) (return))
      ((funcall elt< key (node-key node))
       ;; node は右部分木になる
       (cond
        ((null (node-left node)) (return))
        ((funcall elt< key (node-key (node-left node)))
          ;; 右回転
         (setf node (rotate-right node))
         (when (null (node-left node)) (return))))
       (setf (node-left rnode) node
             rnode node
             node (node-left node)))
      (t
       ;; node は左部分木になる
       (cond
        ((null (node-right node)) (return))
        ((funcall elt< (node-key (node-right node)) key)
         ;; 左回転
         (setf node (rotate-left node))
         (when (null (node-right node)) (return))))
       (setf (node-right lnode) node
             lnode node
             node (node-right node)))))
    (setf (node-left rnode) (node-right node)
          (node-right lnode) (node-left node)
          (node-left node) (node-right wnode)
          (node-right node) (node-left wnode))
    node))

;;;
;;; 探索
;;;

;;; 最大値の探索
(defun node-search-max (node)
  (let* ((wnode (make-instance 'node)) ; Splay 作業用セル
         (lnode wnode))                ; lnode は左部分木になる節を追加する
    (loop
     (when (null (node-right node)) (return))
     ;; node は左部分木になる
     ;; 左回転
     (setf node (rotate-left node))
     (when (null (node-right node)) (return))
     (setf (node-right lnode) node
           lnode node
           node (node-right node)))
    (setf (node-right lnode) (node-left node)
          (node-left node) (node-right wnode))
    node))

;;; 最小値の探索
(defun node-search-min (node)
  (let* ((wnode (make-instance 'node)) ; Splay 作業用セル
         (rnode wnode))                ; rnode は右部分木になる節を追加する
    (loop
     (when (null (node-left node)) (return))
     ;; node は右部分木になる
     ;; 右回転
     (setf node (rotate-right node))
     (when (null (node-left node)) (return))
     (setf (node-left rnode) node
           rnode node
           node (node-left node)))
    (setf (node-left rnode) (node-right node)
          (node-right node) (node-left wnode))
    node))

;;;
;;; 高階関数
;;;

;;; 巡回
(defun node-traverse (fn node)
  (cond
   (node
    (node-traverse fn (node-left node))
    (funcall fn (node-key node) (node-value node))
    (node-traverse fn (node-right node)))))

;;; 畳み込み
(defun node-fold-left (func a node)
  (if (null node)
      a
    (let ((b (node-fold-left func a (node-left node))))
      (node-fold-left func (funcall func b (node-key node) (node-value node)) (node-right node)))))

(defun node-fold-right (func a node)
  (if (null node)
      a
    (let ((b (node-fold-right func a (node-right node))))
      (node-fold-right func (funcall func b (node-key node) (node-value node)) (node-left node)))))

;;;
;;; 連想配列 (スプレイ木)
;;;
(defclass treemap ()
  ((root :accessor tree-root :initform nil :initarg :root)
   (size :accessor tree-size :initform 0   :initarg :size)
   (elt= :accessor tree-elt= :initform nil :initarg :elt=)
   (elt< :accessor tree-elt< :initform nil :initarg :elt<)))

;;; コンストラクタ
(defun make-treemap (elt= elt<)
  (make-instance 'treemap :elt= elt= :elt< elt<))

;;; 木は空か?
(defmethod tree-emptyp ((tm treemap)) (null (tree-root tm)))

;;; 木の要素数を返す
(defmethod tree-count ((tm treemap)) (tree-size tm))

;;; 木を空にする
(defmethod tree-clear ((tm treemap))
  (setf (tree-root tm) nil
        (tree-size tm) 0))

;;; 木に key があるか?
(defmethod tree-exists ((tm treemap) key)
  (with-slots
   (root elt= elt<) tm
   (unless (null root)
     (setf root (node-splay root key elt= elt<))
     (funcall elt= key (node-key root)))))

;;; キーの値を求める
(defmethod tree-get ((tm treemap) key)
  (with-slots
   (root elt= elt<) tm
   (unless (null root)
     (setf root (node-splay root key elt= elt<))
     (when (funcall elt= key (node-key root))
       (node-value root)))))

;;; 最大のキーとその値を求める
(defmethod tree-max ((tm treemap))
  (with-slots
   (root) tm
   (unless (null root)
     (setf root (node-search-max root))
     (cons (node-key root) (node-value root)))))

;;; 最小のキーとその値を求める
(defmethod tree-min ((tm treemap))
  (with-slots
   (root) tm
   (unless (null root)
     (setf root (node-search-min root))
     (cons (node-key root) (node-value root)))))

;;; root に新しい node を追加する
(defun insert-new-node (root node elt<)
  (if (funcall elt< (node-key node) (node-key root))
      (setf (node-left node) (node-left root)
            (node-right node) root
            (node-left root) nil)
    (setf (node-left node) root
          (node-right node) (node-right root)
          (node-right root) nil))
  node)

;;; キーと値を挿入する
(defmethod tree-set ((tm treemap) key value)
  (with-slots
   (root size elt= elt<) tm
   (cond
    ((null root)
     ;; 最初のデータ
     (setf root (make-instance 'node :key key :value value))
     (incf size)
     t)
    (t
     (setf root (node-splay root key elt= elt<))
     (cond
      ((funcall elt= key (node-key root))
       ;; 同じキーを発見
       (setf (node-value root) value)
       nil)
      (t
       ;; 新規追加
       (let ((node (make-instance 'node :key key :value value)))
         (setf root (insert-new-node root node elt<)))
       (incf size)
       t))))))

;;; キーの値に value を push する
(defmethod tree-push ((tm treemap) key value)
  (with-slots
   (root size elt= elt<) tm
   (cond
    ((null root)
     ;; 最初のデータ
     (setf root (make-instance 'node :key key :value (list value)))
     (incf size)
     t)
    (t
     (setf root (node-splay root key elt= elt<))
     (cond
      ((funcall elt= key (node-key root))
       ;; 同じキーを発見
       (setf (node-value root) (cons value (node-value root)))
       nil)
      (t
       ;; 新規追加
       (let ((node (make-instance 'node :key key :value (list value))))
         (setf root (insert-new-node root node elt<)))
       (incf size)
       t))))))

;;; キーの値からデータを pop する
(defmethod tree-pop ((tm treemap) key)
  (with-slots
   (root elt= elt<) tm
   (unless (null root)
     (setf root (node-splay root key elt= elt<))
     (when (and (funcall elt= key (node-key root))
                (consp (node-value root)))
       (pop (node-value root))))))

;;; 木から key とその値を削除する
(defmethod tree-del ((tm treemap) key)
  (with-slots
   (root size elt= elt<) tm
   (unless (null root)
     (setf root (node-splay root key elt= elt<))
     (when (funcall elt= key (node-key root))
       (cond
        ((null (node-left root))
         (setf root (node-right root)))
        ((null (node-right root))
         (setf root (node-left root)))
        (t
         (let ((node (node-splay (node-left root) key elt= elt<)))
           (setf (node-right node) (node-right root)
                 root node))))
       (decf size)
       t))))

;;; 最大のキーと値を削除
(defmethod tree-max-del ((tm treemap))
  (unless (tree-emptyp tm)
    (let ((node (node-search-max (tree-root tm))))
      (setf (tree-root tm) (node-left node))
      (decf (tree-size tm))
      (cons (node-key node) (node-value node)))))

;;; 最小のキーと値を削除
(defmethod tree-min-del ((tm treemap))
  (unless (tree-emptyp tm)
    (let ((node (node-search-min (tree-root tm))))
      (setf (tree-root tm) (node-right node))
      (decf (tree-size tm))
      (cons (node-key node) (node-value node)))))

;;; 巡回
(defmethod tree-mapc ((tm treemap) fn)
  (node-traverse fn (tree-root tm)))

;;; 左部分木から畳み込む
(defmethod tree-fold-left ((tm treemap) a fn)
  (node-fold-left fn a (tree-root tm)))

;;; 右部分木から畳み込む
(defmethod tree-fold-right ((tm treemap) a fn)
  (node-fold-right fn a (tree-root tm)))

Copyright (C) 2023 Makoto Hiroi
All rights reserved.

[ PrevPage | CLOS | NextPage ]