搜索二叉樹的實(shí)現(xiàn)


定義二叉樹的節(jié)點(diǎn):包含左節(jié)點(diǎn)扫俺,右節(jié)點(diǎn)和當(dāng)前結(jié)點(diǎn)的值
    /**
     * 定義二叉搜索樹的節(jié)點(diǎn)
     * @param <AnyType>
     */
    private static class BinaryNode<AnyType>{
        BinaryNode(AnyType theElement){
            this(theElement, null, null);
        }
        //通過構(gòu)造函數(shù)創(chuàng)建節(jié)點(diǎn)
        BinaryNode(AnyType theElement, BinaryNode<AnyType> left, BinaryNode<AnyType> right){
            this.theElement = theElement;
            this.left = left;
            this.right = right;
        }

        AnyType theElement;
        BinaryNode left;
        BinaryNode right;
    }
節(jié)點(diǎn)之間的比較方法:通過自定義的Comparator或默認(rèn)的Compare方法
    /**
     * 定義比較方法:若傳入了比較方式,則用傳入的比較方式,否則用默認(rèn)方式
     * 返回為0表示 lhs = rhs
     * 返回為負(fù)數(shù)表示 lhs < rhs
     * 返回為正數(shù)表示 lhs > rhs
     * @param lhs
     * @param rhs
     * @return
     */
    private int myCompare(AnyType lhs, AnyType rhs){
        if (cmp != null){
            return cmp.compare(lhs, rhs);
        } else {
            return  ((Comparable)lhs).compareTo(rhs);
        }
    }
查找結(jié)點(diǎn):比較傳入的元素與當(dāng)前結(jié)點(diǎn)元素的值按价,若傳入的元素小于當(dāng)前節(jié)點(diǎn)的元素赚爵,則繼續(xù)查找當(dāng)前結(jié)點(diǎn)的左子樹瓢湃,若大于矢炼,則繼續(xù)查找當(dāng)前結(jié)點(diǎn)的右子樹,若等于,表示找到該節(jié)點(diǎn)揖闸,返回true揍堕。
    /**
     * 搜索二叉樹中是否包含某個(gè)元素節(jié)點(diǎn)
     * @param x
     * @param t
     * @return
     */
    private boolean contains(AnyType x, BinaryNode<AnyType> t){
        if (t == null){
            return false;
        }
        //比較元素與當(dāng)前結(jié)點(diǎn)的元素
        int compareResult = myCompare(x, t.theElement);
        //小于當(dāng)前元素,則搜索左子樹
        if (compareResult < 0){
            contains(x, t.left);
        }
        //大于當(dāng)前元素汤纸,則搜索右子樹
        else if (compareResult > 0){
            contains(x, t.right);
        }
        //等于情況衩茸,表示存在,直接返回
        return true;
    }
插入節(jié)點(diǎn):若當(dāng)前結(jié)點(diǎn)為空贮泞,則將新節(jié)點(diǎn)放置此處楞慈,否則判斷傳入的值與當(dāng)前節(jié)點(diǎn)的值,若傳入的值小于當(dāng)前結(jié)點(diǎn)的值則繼續(xù)搜索當(dāng)前結(jié)點(diǎn)的左子樹啃擦,若大于囊蓝,則繼續(xù)搜索當(dāng)前結(jié)點(diǎn)的右子樹。
    /**
     * 實(shí)現(xiàn)插入操作
     * @param x
     * @param t
     * @return
     */
    private BinaryNode<AnyType> insert(AnyType x, BinaryNode<AnyType> t){
        //當(dāng)前節(jié)點(diǎn)為空议惰,則將該節(jié)點(diǎn)在此處
        if (t == null){
            return new BinaryNode<AnyType>(x, null, null);
        }
        //進(jìn)行比較
        int compareResult = myCompare(x, t.theElement);
        //元素小于當(dāng)前結(jié)點(diǎn)元素,則加入到左子樹
        if (compareResult < 0){
            t.left = insert(x, t.left);
        } else if (compareResult > 0){
            t.right = insert(x, t.right);
        } else {
            //do nothing
        }
        return t;
    }
刪除某個(gè)節(jié)點(diǎn):先根據(jù)給定的值找到要?jiǎng)h除的節(jié)點(diǎn)乡恕,若沒有找到該節(jié)點(diǎn)言询,則不會(huì)進(jìn)行刪除操作。

a. 刪除的節(jié)點(diǎn)為葉子節(jié)點(diǎn)傲宜,即沒有孩子运杭,則直接刪除即可,不會(huì)破壞樹的結(jié)構(gòu)函卒。

Paste_Image.png

b. 若節(jié)點(diǎn)中只包含左子樹辆憔,或只包含右子樹,則直接刪除該節(jié)點(diǎn)报嵌,并將其左子樹或右子樹設(shè)置為父節(jié)點(diǎn)的左子樹或右子樹即可虱咧。

Paste_Image.png

c. 當(dāng)刪除的節(jié)點(diǎn)中包含左右子樹時(shí),一般的策略是用其右子樹的最小數(shù)據(jù)代替要?jiǎng)h除的節(jié)點(diǎn)锚国,并遞歸刪除該節(jié)點(diǎn)腕巡。因?yàn)橛易訕涞淖钚」?jié)點(diǎn)是不可能有左子樹的,因此第二次刪除較為容易血筑。

Paste_Image.png

如上圖绘沉,我們要?jiǎng)h除的節(jié)點(diǎn)是5,則找到該節(jié)點(diǎn)豺总,然后找到節(jié)點(diǎn)值為5的右子樹的最小節(jié)點(diǎn)车伞,即節(jié)點(diǎn)值為6的節(jié)點(diǎn)--->將節(jié)點(diǎn)值為6的節(jié)點(diǎn)代替要?jiǎng)h除的節(jié)點(diǎn)5---->然后遞歸刪除原本的節(jié)點(diǎn)6

    /**
     * 實(shí)現(xiàn)移除某個(gè)節(jié)點(diǎn)
     * @param x
     * @param t
     * @return
     */
    private BinaryNode<AnyType> remove(AnyType x, BinaryNode<AnyType> t){
        if (t == null){
            return t;
        }
        //比較大小
        int compareResult = myCompare(x, t.theElement);
        //元素小于當(dāng)前結(jié)點(diǎn)元素,則搜索左子樹
        if (compareResult < 0){
            t.left = remove(x, t.left);
        }
        //元素大于當(dāng)前結(jié)點(diǎn)元素喻喳,則搜索右子樹
        else if (compareResult > 0){
            t.right = remove(x, t.right);
        }
        //相等另玖,表示找到對(duì)應(yīng)的節(jié)點(diǎn),如果該節(jié)點(diǎn)存在左右孩子
        else if (t.left != null && t.right != null){
            //搜索到右子樹的最小節(jié)點(diǎn),并替代當(dāng)前結(jié)點(diǎn)
            t.theElement = (AnyType) findMin(t.right).theElement;
            //并遞歸刪除右子樹的最小節(jié)點(diǎn)
            t.right = remove(t.theElement, t.right);
        }
        //否則日矫,將不為空的孩子節(jié)點(diǎn)替代掉當(dāng)前結(jié)點(diǎn)
        else {
            t = (t.left != null) ? t.left : t.right;
        }
        return t;
    }
查找最大的節(jié)點(diǎn):不斷向右邊搜索節(jié)點(diǎn)赂弓,直到該節(jié)點(diǎn)不存在右邊子節(jié)點(diǎn)。
查找最小的節(jié)點(diǎn):不斷向左邊搜索節(jié)點(diǎn)哪轿,直到該節(jié)點(diǎn)不存在左邊子節(jié)點(diǎn)盈魁。
    /**
     *  實(shí)現(xiàn)獲取二叉樹中最小的節(jié)點(diǎn)
     *  遞歸查找左子樹,直到當(dāng)前結(jié)點(diǎn)的左節(jié)點(diǎn)為空窃诉,則返回當(dāng)前節(jié)點(diǎn)
     * @param t
     * @return
     */
    private BinaryNode<AnyType> findMin(BinaryNode<AnyType> t){
        if (t == null){
            return null;
        } else if (t.left == null){
            return t;
        }
        return findMin(t.left);
    }

    /**
     * 實(shí)現(xiàn)獲取二叉樹中最大的節(jié)點(diǎn)
     * 遞歸查找右子樹杨耙,直到當(dāng)前節(jié)點(diǎn)的右節(jié)點(diǎn)為空,返回當(dāng)前節(jié)點(diǎn)
     * @param t
     * @return
     */
    private BinaryNode<AnyType> findMax(BinaryNode<AnyType> t){
        if (t == null){
            return null;
        } else if (t.right == null){
            return t;
        }
        return findMax(t.right);
    }

實(shí)現(xiàn)三種遍歷樹的方式:
/**
     * 前序遍歷
     * 訪問順序?yàn)椋焊?jié)點(diǎn)->左節(jié)點(diǎn)->右節(jié)點(diǎn)
     * @param node
     */
    public void preOrder(BinaryNode<AnyType> node){
        if (node != null){
            System.out.print(node.right + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }

    /**
     * 中序遍歷
     * 訪問順序?yàn)椋鹤蠊?jié)點(diǎn)->根節(jié)點(diǎn)->右節(jié)點(diǎn)
     * @param node
     */
    public void inOrder(BinaryNode<AnyType> node){
        if (node != null){
            inOrder(node.left);
            System.out.print(node.theElement + " ");
            inOrder(node.right);
        }
    }

    /**
     * 后序遍歷
     * 訪問順序?yàn)椋鹤蠊?jié)點(diǎn)->右節(jié)點(diǎn)->根節(jié)點(diǎn)
     * @param node
     */
    public void postOrder(BinaryNode<AnyType> node){
        if (node != null){
            postOrder(node.left);
            postOrder(node.right);
            System.out.print(node.theElement + " ");
        }
    }
完整代碼:
package BinaryTree;

import org.omg.CORBA.Any;

import java.nio.BufferUnderflowException;
import java.util.Comparator;

/**
 * Created by Administrator on 2017/3/7/007.
 * 實(shí)現(xiàn)搜索二叉樹的基本操作
 */
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {

    /**
     * 定義二叉搜索樹的節(jié)點(diǎn)
     * @param <AnyType>
     */
    private static class BinaryNode<AnyType>{
        BinaryNode(AnyType theElement){
            this(theElement, null, null);
        }
        //通過構(gòu)造函數(shù)創(chuàng)建節(jié)點(diǎn)
        BinaryNode(AnyType theElement, BinaryNode<AnyType> left, BinaryNode<AnyType> right){
            this.theElement = theElement;
            this.left = left;
            this.right = right;
        }

        AnyType theElement;
        BinaryNode left;
        BinaryNode right;
    }

    /**
     * 定義二叉樹的根節(jié)點(diǎn)
     */
    private BinaryNode<AnyType> root;

    /**
     * 定義比較方式
     */
    private Comparator<? super AnyType> cmp;

    public BinarySearchTree(){
        this(null);
    }

    /**
     * 構(gòu)造函數(shù)飘痛,傳入比較方式
     * @param c
     */
    public BinarySearchTree(Comparator<? super AnyType> c){
        root = null;
        cmp = c;
    }

    /**
     * 定義比較方法:若傳入了比較方式珊膜,則用傳入的比較方式,否則用默認(rèn)的方法
     * @param lhs
     * @param rhs
     * @return
     */
    private int myCompare(AnyType lhs, AnyType rhs){
        if (cmp != null){
            return cmp.compare(lhs, rhs);
        } else {
            return  ((Comparable)lhs).compareTo(rhs);
        }

    }

    /**
     * 使二叉樹變?yōu)榭?     */
    public void makeEmpty(){
        root = null;
    }

    /**
     * 檢查二叉樹是否為空
     * @return
     */
    public boolean isEmpty(){
        return root == null;
    }

    /**
     * 檢查二叉樹中是否包含某個(gè)元素
     * @param x
     * @return
     */
    public boolean contains(AnyType x){
        return contains(x, root);
    }

    /**
     * 搜索查找二叉樹中最小的元素
     * @return
     */
    public AnyType findMin(){
        if (isEmpty()) throw new BufferUnderflowException();
        return findMin(root).theElement;
    }

    /**
     * 搜索查找二叉樹中最大的元素
     * @return
     */
    public AnyType findMax(){
        if (isEmpty()) throw new BufferUnderflowException();
        return findMax(root).theElement;
    }

    /**
     * 插入元素
     * @param x
     */
    public void insert(AnyType x){
        root = insert(x, root);
    }

    /**
     * 刪除元素
     * @param x
     */
    public void remove(AnyType x){
        root = remove(x, root);
    }


    /**
     * 搜索二叉樹中是否包含某個(gè)元素節(jié)點(diǎn)
     * @param x
     * @param t
     * @return
     */
    private boolean contains(AnyType x, BinaryNode<AnyType> t){
        if (t == null){
            return false;
        }
        //比較元素與當(dāng)前結(jié)點(diǎn)的元素
        int compareResult = myCompare(x, t.theElement);
        //小于當(dāng)前元素宣脉,則搜索左子樹
        if (compareResult < 0){
            contains(x, t.left);
        }
        //大于當(dāng)前元素车柠,則搜索右子樹
        else if (compareResult > 0){
            contains(x, t.right);
        }
        //等于情況,表示存在塑猖,直接返回
        return true;
    }

    /**
     *  實(shí)現(xiàn)獲取二叉樹中最小的節(jié)點(diǎn)
     *  遞歸查找左子樹竹祷,直到當(dāng)前結(jié)點(diǎn)的左節(jié)點(diǎn)為空,則返回當(dāng)前節(jié)點(diǎn)
     * @param t
     * @return
     */
    private BinaryNode<AnyType> findMin(BinaryNode<AnyType> t){
        if (t == null){
            return null;
        } else if (t.left == null){
            return t;
        }
        return findMin(t.left);
    }

    /**
     * 實(shí)現(xiàn)獲取二叉樹中最大的節(jié)點(diǎn)
     * 遞歸查找右子樹羊苟,直到當(dāng)前節(jié)點(diǎn)的右節(jié)點(diǎn)為空塑陵,返回當(dāng)前節(jié)點(diǎn)
     * @param t
     * @return
     */
    private BinaryNode<AnyType> findMax(BinaryNode<AnyType> t){
        if (t == null){
            return null;
        } else if (t.right == null){
            return t;
        }
        return findMax(t.right);
    }

    /**
     * 實(shí)現(xiàn)插入操作
     * @param x
     * @param t
     * @return
     */
    private BinaryNode<AnyType> insert(AnyType x, BinaryNode<AnyType> t){
        //當(dāng)前節(jié)點(diǎn)為空,則將該節(jié)點(diǎn)在此處
        if (t == null){
            return new BinaryNode<AnyType>(x, null, null);
        }
        //進(jìn)行比較
        int compareResult = myCompare(x, t.theElement);
        //元素小于當(dāng)前結(jié)點(diǎn)元素蜡励,則加入到左子樹
        if (compareResult < 0){
            t.left = insert(x, t.left);
        } else if (compareResult > 0){
            t.right = insert(x, t.right);
        } else {
            //do nothing
        }
        return t;
    }

    /**
     * 實(shí)現(xiàn)移除某個(gè)節(jié)點(diǎn)
     * @param x
     * @param t
     * @return
     */
    private BinaryNode<AnyType> remove(AnyType x, BinaryNode<AnyType> t){
        if (t == null){
            return t;
        }
        //比較大小
        int compareResult = myCompare(x, t.theElement);
        //元素小于當(dāng)前結(jié)點(diǎn)元素令花,則搜索左子樹
        if (compareResult < 0){
            t.left = remove(x, t.left);
        }
        //元素大于當(dāng)前結(jié)點(diǎn)元素,則搜索右子樹
        else if (compareResult > 0){
            t.right = remove(x, t.right);
        }
        //相等凉倚,表示找到對(duì)應(yīng)的節(jié)點(diǎn)兼都,如果該節(jié)點(diǎn)存在左右孩子
        else if (t.left != null && t.right != null){
            //搜索到右子樹的最小節(jié)點(diǎn),并替代當(dāng)前結(jié)點(diǎn)
            t.theElement = (AnyType) findMin(t.right).theElement;
            //并遞歸刪除右子樹的最小節(jié)點(diǎn)
            t.right = remove(t.theElement, t.right);
        }
        //否則稽寒,將不為空的孩子節(jié)點(diǎn)替代掉當(dāng)前結(jié)點(diǎn)
        else {
            t = (t.left != null) ? t.left : t.right;
        }
        return t;
    }

    /**
     * 前序遍歷
     * 訪問順序?yàn)椋焊?jié)點(diǎn)->左節(jié)點(diǎn)->右節(jié)點(diǎn)
     * @param node
     */
    public void preOrder(BinaryNode<AnyType> node){
        if (node != null){
            System.out.print(node.right + " ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }

    /**
     * 中序遍歷
     * 訪問順序?yàn)椋鹤蠊?jié)點(diǎn)->根節(jié)點(diǎn)->右節(jié)點(diǎn)
     * @param node
     */
    public void inOrder(BinaryNode<AnyType> node){
        if (node != null){
            inOrder(node.left);
            System.out.print(node.theElement + " ");
            inOrder(node.right);
        }
    }

    /**
     * 后序遍歷
     * 訪問順序?yàn)椋鹤蠊?jié)點(diǎn)->右節(jié)點(diǎn)->根節(jié)點(diǎn)
     * @param node
     */
    public void postOrder(BinaryNode<AnyType> node){
        if (node != null){
            postOrder(node.left);
            postOrder(node.right);
            System.out.print(node.theElement + " ");
        }
    }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末俯抖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瓦胎,更是在濱河造成了極大的恐慌芬萍,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搔啊,死亡現(xiàn)場(chǎng)離奇詭異柬祠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)负芋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門漫蛔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗜愈,“玉大人,你說我怎么就攤上這事莽龟∪浼蓿” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵毯盈,是天一觀的道長(zhǎng)剃毒。 經(jīng)常有香客問我,道長(zhǎng)搂赋,這世上最難降的妖魔是什么赘阀? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮脑奠,結(jié)果婚禮上基公,老公的妹妹穿的比我還像新娘。我一直安慰自己宋欺,他們只是感情好轰豆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著齿诞,像睡著了一般酸休。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掌挚,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天雨席,我揣著相機(jī)與錄音菩咨,去河邊找鬼吠式。 笑死,一個(gè)胖子當(dāng)著我的面吹牛抽米,可吹牛的內(nèi)容都是我干的特占。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼云茸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼是目!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起标捺,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤懊纳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后亡容,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嗤疯,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年闺兢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茂缚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖脚囊,靈堂內(nèi)的尸體忽然破棺而出龟糕,到底是詐尸還是另有隱情,我是刑警寧澤悔耘,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布讲岁,位于F島的核電站,受9級(jí)特大地震影響淮逊,放射性物質(zhì)發(fā)生泄漏催首。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一泄鹏、第九天 我趴在偏房一處隱蔽的房頂上張望郎任。 院中可真熱鬧,春花似錦备籽、人聲如沸舶治。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霉猛。三九已至,卻和暖如春珠闰,著一層夾襖步出監(jiān)牢的瞬間惜浅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工伏嗜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坛悉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓承绸,卻偏偏與公主長(zhǎng)得像裸影,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子军熏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • B樹的定義 一棵m階的B樹滿足下列條件: 樹中每個(gè)結(jié)點(diǎn)至多有m個(gè)孩子轩猩。 除根結(jié)點(diǎn)和葉子結(jié)點(diǎn)外,其它每個(gè)結(jié)點(diǎn)至少有m...
    文檔隨手記閱讀 13,221評(píng)論 0 25
  • 數(shù)據(jù)結(jié)構(gòu)與算法--從平衡二叉樹(AVL)到紅黑樹 上節(jié)學(xué)習(xí)了二叉查找樹荡澎。算法的性能取決于樹的形狀均践,而樹的形狀取決于...
    sunhaiyu閱讀 7,648評(píng)論 4 32
  • 數(shù)據(jù)結(jié)構(gòu)和算法--二叉樹的實(shí)現(xiàn) 幾種二叉樹 1、二叉樹 和普通的樹相比摩幔,二叉樹有如下特點(diǎn): 每個(gè)結(jié)點(diǎn)最多只有兩棵子...
    sunhaiyu閱讀 6,461評(píng)論 0 14
  • 四热鞍、樹與二叉樹 1. 二叉樹的順序存儲(chǔ)結(jié)構(gòu) 二叉樹的順序存儲(chǔ)就是用數(shù)組存儲(chǔ)二叉樹葫慎。二叉樹的每個(gè)結(jié)點(diǎn)在順序存儲(chǔ)中都有...
    MinoyJet閱讀 1,528評(píng)論 0 7
  • 特里莎修女說:“人們經(jīng)常是不講道理的衔彻、沒有邏輯的和以自我為中心的,不管怎樣偷办,你要原諒他們艰额。即使你是友善的,人們可能...
    petitsh閱讀 334評(píng)論 0 1