排序算法-歸并排序、堆排序赫舒、插入排序悍及、選擇排序、冒泡排序 golang

作者說明:郭玉樂 yulekwok@gmail.com

1.冒泡排序(Bubble Sort)

冒泡排序也叫做起泡排序
執(zhí)行流程
1 從頭開始比較每一對相鄰元素接癌,如果第1個(gè)比第2個(gè)大心赶,就交換它們的位置 ? 執(zhí)行完一輪后,最末尾那個(gè)元素就是最大的元素
2 忽略 1 中曾經(jīng)找到的最大元素缺猛,重復(fù)執(zhí)行步驟 1缨叫,直到全部元素有序

for end := len(this.Array) - 1; end > 0; end-- {
        for begin := 1; begin <= end; begin++ {
            if this.ComWithIndex(begin, begin-1) < 0 {
                this.Swap(begin, begin-1)
            }
        }
    }

冒泡排序 – 優(yōu)化1

如果序列已經(jīng)完全有序,可以提前終止冒泡排序,相當(dāng)于提前進(jìn)行終止

for end := len(this.Array) - 1; end > 0; end-- {
        sorted := true
        for begin := 1; begin <= end; begin++ {
            if this.ComWithIndex(begin, begin-1) < 0 {
                this.Swap(begin, begin-1)
                sorted = false
            }
        }
        if sorted{
            break
        }

    }

冒泡排序 – 優(yōu)化2

如果序列尾部已經(jīng)局部有序荔燎,可以記錄最后1次交換的位置耻姥,減少比較次數(shù)

//最壞、平均時(shí)間復(fù)雜度:O(n2)  最好時(shí)間復(fù)雜度:O(n)
//空間復(fù)雜度:O(1)
for end := len(this.Array) - 1; end > 0; end-- {
        sortedIndex := 1
        for begin := 1; begin <= end; begin++ {
            if this.ComWithIndex(begin, begin-1) < 0 {
                this.Swap(begin, begin-1)
                sortedIndex = begin
            }
        }
        end = sortedIndex
    }

golang 源碼

package mysort

import (
    "fmt"
    "time"
)

type Sort struct {
    Array     []int
    CmpCount  int64
    SwapCount int64
    begin     int64
    FuncType     string

}

func (this *Sort) SortArray(array []int)  {

    this.Array = make([]int, len(array))
    copy(this.Array, array)
    this.begin = time.Now().UnixNano()

}
func (this *Sort) SortFunc() {
    if this.Array == nil || len(this.Array) < 2 {
        return
    }
}
func (this *Sort) ComWithIndex(i1, i2 int) int {
    this.CmpCount++
    return this.Array[i1] - this.Array[i2]
}
func (this *Sort) ComWithValue(v1, v2 int) int {
    this.CmpCount++
    return v1 - v2
}
func (this *Sort) Swap(i1, i2 int) {
    this.Array[i2], this.Array[i1] = this.Array[i1], this.Array[i2]
    this.SwapCount++
}
func (this *Sort)ToString()  {
    fmt.Println("排序數(shù)組大小", len(this.Array),"排序方法",this.FuncType,"比較次數(shù)",this.CmpCount,"交換次數(shù)",this.SwapCount,"耗時(shí)",(time.Now().UnixNano() - this.begin)/1e6,"ms")

}

package mysort

type BubbleSort struct {
    Sort
}

func (this *BubbleSort) SortArray(array []int) {
    this.Sort.SortArray(array)
}
func (this *BubbleSort) SortFunc()  {
    this.Sort.SortFunc()
    for end := len(this.Array) - 1; end > 0; end-- {
        for begin := 1; begin <= end; begin++ {
            if this.ComWithIndex(begin, begin-1) < 0 {
                this.Swap(begin, begin-1)
            }
        }
    }

}
// 設(shè)置一個(gè)bool 的標(biāo)志有咨,判斷是否進(jìn)行過交換
func (this *BubbleSort) SortFunc1()  {
    this.Sort.SortFunc()
    for end := len(this.Array) - 1; end > 0; end-- {
        sorted := true
        for begin := 1; begin <= end; begin++ {
            if this.ComWithIndex(begin, begin-1) < 0 {
                this.Swap(begin, begin-1)
                sorted = false
            }
        }
        if sorted{
            break
        }

    }

}
func (this *BubbleSort) SortFunc2()  {
    this.Sort.SortFunc()
    for end := len(this.Array) - 1; end > 0; end-- {
        sortedIndex := 1
        for begin := 1; begin <= end; begin++ {
            if this.ComWithIndex(begin, begin-1) < 0 {
                this.Swap(begin, begin-1)
                sortedIndex = begin
            }
        }
        end = sortedIndex
    }

}
package main

import (
    "fmt"
    "iktolin.com/mysort"
    "iktolin.com/struct/firstStudy/Heap"
    "math/rand"
    "sync"
    "time"
)

func main() {

    algorithm()

}
// 算法
func algorithm() {
    wg := sync.WaitGroup{}
    var array []int
    rand.Seed(time.Now().UnixNano())
    for i := 0; i < 100000; i++ {
        x := rand.Intn(10209023)
        array = append(array, x)

    }

    //fmt.Println("排序前",array)
    //// 時(shí)間復(fù)雜度 O(n2)
    wg.Add(7)
    go func(array []int, w *sync.WaitGroup) {
        bubbleSort := mysort.BubbleSort{}
        bubbleSort.SortArray(array)
        bubbleSort.SortFunc()
        bubbleSort.ToString()
        w.Done()
    }(array, &wg)

    //fmt.Println(array)
    // 使用bool 值判斷是否進(jìn)行過排序琐簇,適用于原來就是排好序的
    go func(array []int, w *sync.WaitGroup) {
        bubbleSort1 := mysort.BubbleSort{}
        bubbleSort1.SortArray(array)
        bubbleSort1.SortFunc1()
        bubbleSort1.ToString()
        w.Done()
    }(array, &wg)

    go func(array []int, w *sync.WaitGroup) {
        bubbleSort2 := mysort.BubbleSort{}
        bubbleSort2.SortArray(array)
        bubbleSort2.SortFunc2()
        bubbleSort2.ToString()
        w.Done()
    }(array, &wg)
    // 使用bool 值判斷是否進(jìn)行過排序,適用于其中有局部排好序的

    go func(array []int, w *sync.WaitGroup) {
        slect := mysort.SelectionSort{}
        slect.SortArray(array)
        slect.SortFunc()
        slect.ToString()
        w.Done()
    }(array, &wg)

    go func(array []int, w *sync.WaitGroup) {
        heap := mysort.HeapSort{}
        heap.SortArray(array)
        heap.SortFunc()
        heap.ToString()
        w.Done()
    }(array, &wg)
    go func(array []int, w *sync.WaitGroup) {
        insertion := mysort.InsertionSort{}
        insertion.SortArray(array)
        insertion.SortFunc()
        insertion.ToString()
        w.Done()
    }(array, &wg)

    go func(array []int, w *sync.WaitGroup) {
        merge := mysort.MergeSort{}
        merge.SortArray(array)
        merge.SortFunc()
        merge.ToString()
        w.Done()
    }(array, &wg)

    wg.Wait()
    //排序數(shù)組大小 100000 排序方法 歸并排序 比較次數(shù) 1536231 交換次數(shù) 0 耗時(shí) 18 ms
    //排序數(shù)組大小 100000 排序方法 堆排序 比較次數(shù) 1509851 交換次數(shù) 99999 耗時(shí) 21 ms
    //排序數(shù)組大小 100000 排序方法 插入排序 比較次數(shù) 0 交換次數(shù) 0 耗時(shí) 4613 ms
    //排序數(shù)組大小 100000 排序方法 選擇排序 比較次數(shù) 4999950000 交換次數(shù) 99999 耗時(shí) 13306 ms
    //排序數(shù)組大小 100000 排序方法 冒泡排序 比較次數(shù) 4999418601 交換次數(shù) 2506933128 耗時(shí) 22555 ms
    //排序數(shù)組大小 100000 排序方法 冒泡排序 比較次數(shù) 4999950000 交換次數(shù) 2506933128 耗時(shí) 23048 ms
    //排序數(shù)組大小 100000 排序方法 冒泡排序 比較次數(shù) 4999880994 交換次數(shù) 2506933128 耗時(shí) 24453 ms

}

2.選擇排序(Selection Sort)

  1. 從序列中找出最大的那個(gè)元素,然后與最末尾的元素交換位置 執(zhí)行完一輪后婉商,最末尾的那個(gè)元素就是最大的元素

  2. 忽略 1 中曾經(jīng)找到的最大元素似忧,重復(fù)執(zhí)行步驟 1

    for end := len(this.Array) - 1; end > 0; end-- {
         max := 0
         for begin := 1; begin <= end; begin++ {
             if this.ComWithIndex(begin, begin-1) < 0 {
                 max = begin
             }
         }
         this.Swap(max, end)
     }
    

//選擇排序的交換次數(shù)要遠(yuǎn)遠(yuǎn)少于冒泡排序,平均性能優(yōu)于冒泡排序
//最好丈秩、最壞盯捌、平均時(shí)間復(fù)雜度:O(n2),空間復(fù)雜度:O(1)蘑秽,屬于不穩(wěn)定排序

src

package mysort

type SelectionSort struct {
   Sort
}

//1 從序列中找出最大的那個(gè)元素饺著,然后與最末尾的元素交換位置 執(zhí)行完一輪后,最末尾的那個(gè)元素就是最大的元素
//2 忽略 1 中曾經(jīng)找到的最大元素肠牲,重復(fù)執(zhí)行步驟 1

//選擇排序的交換次數(shù)要遠(yuǎn)遠(yuǎn)少于冒泡排序幼衰,平均性能優(yōu)于冒泡排序
//最好、最壞埂材、平均時(shí)間復(fù)雜度:O(n2)塑顺,空間復(fù)雜度:O(1),屬于不穩(wěn)定排序
func (this *SelectionSort) SortFunc() {
   this.Sort.SortFunc()

   for end := len(this.Array) - 1; end > 0; end-- {
      max := 0
      for begin := 1; begin <= end; begin++ {
         if this.ComWithIndex(begin, begin-1) < 0 {
            max = begin
         }
      }
      this.Swap(max, end)
   }

}
package main

import (
    "fmt"
    "iktolin.com/mysort"
    "math/rand"
    "time"
)

func main()  {
    var array []int
    rand.Seed(time.Now().UnixNano())
    for i := 0; i < 40; i++ {
        x := rand.Intn(100)
        array = append(array, x)

    }


    fmt.Println("排序前",array)
    // 時(shí)間復(fù)雜度 O(n2)
    bubbleSort := mysort.BubbleSort{}
    bubbleSort.SortArray(array)
    bubbleSort.SortFunc()
    bubbleSort.ToString()
    //fmt.Println(array)
    // 使用bool 值判斷是否進(jìn)行過排序俏险,適用于原來就是排好序的
    bubbleSort1 := mysort.BubbleSort{}
    bubbleSort1.SortArray(array)
    bubbleSort1.SortFunc1()
    bubbleSort1.ToString()
    // 使用bool 值判斷是否進(jìn)行過排序,適用于其中有局部排好序的
    bubbleSort2 := mysort.BubbleSort{}
    bubbleSort2.SortArray(array)
    bubbleSort2.SortFunc2()
    bubbleSort2.ToString()


    slect :=mysort.SelectionSort{}
    slect.SortArray(array)
    slect.SortFunc()
    slect.ToString()
}
//排序前 [68 23 47 62 33 4 97 49 46 20 25 24 77 88 66 16 6 44 98 11 70 68 30 5 29 46 12 96 31 27 60 24 76 21 19 44 94 46 82 77]
    //排序比較次數(shù) 780 排序交換次數(shù) 369
    //排序比較次數(shù) 725 排序交換次數(shù) 369
    //排序比較次數(shù) 643 排序交換次數(shù) 369
    //排序比較次數(shù) 780 排序交換次數(shù) 39

3.選擇排序的優(yōu)化方案(堆排序)

package mysort

type HeapSort struct {
   Sort
   size int
}

// 對數(shù)據(jù)進(jìn)行原地建堆
//將建立好的堆的root最后的位置交換位置扬绪,然后將size -- 然后將0號位置進(jìn)行下濾操作
//siftdown 直到堆的值為1
// 選最值使用堆來操作
// 第一個(gè)葉子節(jié)點(diǎn)是size 的一半 所以第一個(gè)非葉子節(jié)點(diǎn) 是 (size >> 1) -1
func (this *HeapSort) SortFunc() {
   this.size = len(this.Array)
   for i := (this.size >> 1) - 1; i >= 0; i-- {
      this.siftDown(i)
   }
   for this.size > 1 {
      this.Swap(0, this.size-1)
      this.size--
      this.siftDown(0)
   }

}
func (this *HeapSort) siftDown(index int) {
   v := this.Array[index]
   half := (this.size >> 1)
   // 1.找其左右子節(jié)點(diǎn) 找到最大的子節(jié)點(diǎn)開始交換數(shù)值
   for index < half {
      // 1.index 只有左節(jié)點(diǎn)
      // index 有左右子節(jié)點(diǎn)
      //默認(rèn)和左邊進(jìn)行比較
      childIndex := (index << 1) + 1
      childValue := this.Array[childIndex]
      rightIndex := childIndex + 1
      if rightIndex < this.size && this.Array[rightIndex] > childValue {
         childIndex = rightIndex
         childValue = this.Array[childIndex]
      }
      if v >= childValue {
         break
      }
      this.Array[index] = childValue
      index = childIndex

   }
   this.Array[index] = v
  // 在99999 比較情況下 選擇排序和堆排序
    //排序結(jié)果 無 排序比較次數(shù) 4999950000 排序交換次數(shù) 99999 耗時(shí) 10019693000
    //排序結(jié)果 無 排序比較次數(shù) 0 排序交換次數(shù) 99999 耗時(shí) 12014000
}

4.二分搜索

前提是要有序的數(shù)組

package mysort

type Binarysearch struct {
   Data []int
}
// 前提數(shù)組是要有序的
//查找v在有序數(shù)組array中的位置
func (this *Binarysearch) IndexOf(v int) (index int) {
   if this.Data == nil || len(this.Data) == 0 {
      return -1
   }
   begin := 0
   end := len(this.Data)
   for begin < end {
      mid := (begin + end) >> 1
      if this.Data[mid] > v {
         end = mid
      } else if this.Data[mid] < v {
         begin = mid + 1
      } else {
         index = mid
         return
      }

   }
   return -1
}
//查找v在有序數(shù)組array中待插入位置
func (this *Binarysearch) Find(v int) (index int) {
   if this.Data == nil || len(this.Data) == 0 {
      return -1
   }
   begin := 0
   end := len(this.Data)
   for begin < end {
      mid := (begin + end) >> 1
      if this.Data[mid] > v {
         end = mid
      } else if this.Data[mid] < v {
         begin = mid + 1
      }

   }
   return begin
}

5.插入排序

package mysort

type InsertionSort struct {
   Sort
   Binarysearch

}
//插入排序(Insertion Sort)
//插入排序非常類似于撲克牌的排序
//執(zhí)行流程
//1 在執(zhí)行過程中竖独,插入排序會(huì)將序列分為2部分
//頭部是已經(jīng)排好序的,尾部是待排序的
//2 從頭開始掃描每一個(gè)元素
//每當(dāng)掃描到一個(gè)元素挤牛,就將它插入到頭部合適的位置莹痢,使得頭部數(shù)據(jù)依然保持有序
func (this *InsertionSort) SortFunc() {
   this.SortFunc2()

}
//
func (this *InsertionSort) SortFunc0() {
   for begin := 1; begin < len(this.Array); begin++ {
      // 找合適的位置然后將數(shù)放進(jìn)去
      current := begin
      for current > 0 {
         if this.ComWithIndex(current,current -1) < 0 {
            this.Swap(current,current-1)
         }
         current --
      }
   }
}
// 優(yōu)化 將交換改為挪動(dòng)
// 先將代插入的元素備份,然后挪動(dòng)比其大的元素
// 將待插入的元素放到這個(gè)位置
func (this *InsertionSort) SortFunc1() {
   for begin := 1; begin < len(this.Array); begin++ {
      // 找合適的位置然后將數(shù)放進(jìn)去
      current := begin
      beginV := this.Array[begin]
      for current > 0 && this.ComWithValue(beginV,this.Array[current -1])< 0{
         this.Array[current]=this.Array[current -1]
         current --
      }
      this.Array[current] = beginV

   }
}
// 使用二分查找
func (this *InsertionSort) SortFunc2() {
   for begin := 1; begin < len(this.Array); begin++ {
      // 找合適的位置然后將數(shù)放進(jìn)去
      beginV := this.Array[begin]
      this.Data = this.Array
      index := this.Find(begin)
      for i := begin; i > index ; i-- {
         this.Array[i]=this.Array[i -1]
      }
      this.Array[index] = beginV

   }
}

6.歸并排序

執(zhí)行流程

  1. 不斷地將當(dāng)前序列平均分割成2個(gè)子序列 (分割)
    直到不能再分割(序列中只剩1個(gè)元素)
  2. 不斷地將2個(gè)子序列合并成一個(gè)有序序列 (合并)
    直到最終只剩下1個(gè)有序序列
package mysort

type MergeSort struct {
   leftArray []int
   Sort
}

func (this *MergeSort) SortFunc() {
   this.leftArray = make([]int, len(this.Array)>>1)
   this.sort(0, len(this.Array))
}

// [begin,end)
func (this *MergeSort) sort(begin, end int) {
   if end-begin < 2 {
      return
   }

   mid := (begin + end) >> 1
   this.sort(begin, mid)
   this.sort(mid, end)
   this.merge(begin, mid, end)

}

// 將 【begin mid) 和 [mid end)
func (this *MergeSort) merge(begin, mid, end int) {
   li, le := 0, mid-begin
   ri, re := mid, end
   ai := begin
   // 備份左邊數(shù)組  將 [begin,mid) 備份出來
   for i := li; i < le; i++ {
      this.leftArray[i] = this.Array[begin+i]
   }
   //如果左邊還沒有結(jié)束墓赴,如果右邊結(jié)束的話竞膳,那么就不用管任何事情了
   for li < le {
      if ri < re && this.ComWithValue(this.Array[ri], this.leftArray[li]) < 0 {
         this.Array[ai] = this.Array[ri]
         ai++
         ri++
      } else {
         this.Array[ai] = this.leftArray[li]
         ai++
         li++
      }
   }
}
//排序數(shù)組大小 1000000 排序方法 堆排序 排序比較次數(shù) 18388630 排序交換次數(shù) 999999 耗時(shí) 191247000
//排序數(shù)組大小 1000000 排序方法 歸并排序 排序比較次數(shù) 18670630 排序交換次數(shù) 0 耗時(shí) 135949000

總結(jié)時(shí)間耗時(shí)

//排序數(shù)組大小 100000 排序方法 歸并排序 比較次數(shù) 1536231 交換次數(shù) 0 耗時(shí) 18 ms
//排序數(shù)組大小 100000 排序方法 堆排序 比較次數(shù) 1509851 交換次數(shù) 99999 耗時(shí) 21 ms
//排序數(shù)組大小 100000 排序方法 插入排序 比較次數(shù) 0 交換次數(shù) 0 耗時(shí) 4613 ms
//排序數(shù)組大小 100000 排序方法 選擇排序 比較次數(shù) 4999950000 交換次數(shù) 99999 耗時(shí) 13306 ms
//排序數(shù)組大小 100000 排序方法 冒泡排序 比較次數(shù) 4999418601 交換次數(shù) 2506933128 耗時(shí) 22555 ms
//排序數(shù)組大小 100000 排序方法 冒泡排序 比較次數(shù) 4999950000 交換次數(shù) 2506933128 耗時(shí) 23048 ms
//排序數(shù)組大小 100000 排序方法 冒泡排序 比較次數(shù) 4999880994 交換次數(shù) 2506933128 耗時(shí) 24453 ms
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市诫硕,隨后出現(xiàn)的幾起案子坦辟,更是在濱河造成了極大的恐慌,老刑警劉巖章办,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锉走,死亡現(xiàn)場離奇詭異,居然都是意外死亡藕届,警方通過查閱死者的電腦和手機(jī)挪蹭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來休偶,“玉大人梁厉,你說我怎么就攤上這事√ざ担” “怎么了词顾?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵八秃,是天一觀的道長。 經(jīng)常有香客問我计技,道長喜德,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任垮媒,我火速辦了婚禮舍悯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘睡雇。我一直安慰自己萌衬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布它抱。 她就那樣靜靜地躺著秕豫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪混移。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天侮穿,我揣著相機(jī)與錄音歌径,去河邊找鬼。 笑死亲茅,一個(gè)胖子當(dāng)著我的面吹牛回铛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播克锣,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼茵肃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了袭祟?” 一聲冷哼從身側(cè)響起验残,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎榕酒,沒想到半個(gè)月后胚膊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡想鹰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年紊婉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辑舷。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喻犁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肢础,我是刑警寧澤还栓,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站传轰,受9級特大地震影響剩盒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜慨蛙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一辽聊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧期贫,春花似錦跟匆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至封孙,卻和暖如春迹冤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背虎忌。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工叁巨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呐籽。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像蚀瘸,于是被迫代替她去往敵國和親狡蝶。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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