日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

算法我也不知道有没有下一个---一个题目的开端(索引堆与图)

發布時間:2025/3/17 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法我也不知道有没有下一个---一个题目的开端(索引堆与图) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么80%的碼農都做不了架構師?>>> ??

病痛了一周,折磨來折磨去,終于還是平靜了下來,現在能把上周末"貫穿"學到的最后一個基礎數據結構的知識給沉淀沉淀了。也是即將再單位分享的東西:圖論。這東西,想當年大二,學校的時候,只是理解或者畫圖,就已經很費勁了,當時我們平時作業包括后來的期末考試也只是到理解原理的層面,會畫圖,就行,實現什么的,根本別想。我自己當年也是認真看過,死磕過幾個算法的實現:最小生成樹、最短路徑等,然而,是看不懂的。這么多年過去了,自己編程能力和見識多了,回過頭來,發現,其實并沒那么難,只不過比平時的業務邏輯稍微復雜些,但是相較于框架的源碼復雜度來說,還是遠遠夠不到的。這一次,我先以一道題開始,逐步將相關的知識點講下來,采取這種方式,最后,會拓展的講講其他的實現,恩,開干

零、一些話

本次的題目,其實算是一道功能實現題,但是能很直接的看出使用的數據結構和大二數據結構課本中介紹的這種數據結構的基本幾個之一的算法,所以非常考察當年本科計算機基礎的夯實程度與編程實踐能力。還是那句話,不要整天咔咔咔的寫個curd就覺得會編程,很牛逼。計算機能解決的問題,遠遠不止curd,編程能力也遠遠不止curd。同樣,這道題,也是一道面試題(具體出處,我就不說了),成敗與否,工資高與低,日子苦逼與否,可能往往取決于一道題,并非危言聳聽。有人覺得算法沒用,平時用不到,都是api調用,我耗時耗力學,有啥回報呢,我能用來解決什么問題呢?下面我來談談我的想法。

算法,我覺得類似于我現在追的一部翻拍武俠劇《倚天屠龍記》中的兩部武學經典《九陽神功》與《乾坤大挪移》。張無忌整個過程中似乎并沒有學什么具體的武功招式,與外家功夫,只學了這兩部內功圣經,就已經干翻六大派高手,干翻趙敏手下的一大堆的援軍與玄冥二老,稱霸武林。可是這兩部武學內功并沒有交張無忌一招一式啊!我覺得算法如此。我們現在編程生活中,幾乎不用我們去實現鏈表,更不可能讓我們實現一個紅黑樹,更別提讓我們寫一個圖的深度遍歷,因為太多太多的框架都幫助我們實現了。然而,試想一種情況:如果一個開發者,能白板寫大頂堆小頂堆,能白板手寫紅黑樹,能立馬手動編碼實現一道基于數據結構的中等難度的LeetCode上面的習題,難道他不會調用spring的api?難道他不會寫個sql去查詢數據庫?我相信即使他不會,也比一般開發者學的快!更進一步,如果你發現你要根據具體的業務場景實現自己的業務負載均衡模型、在電信的業務模型中對具體的一個表達式進行解析(恩,我弄過)、在游戲開發領域快速判斷兩點之間的連通性等等這些,都是必須要牢靠掌握數據結構與算法能力的。哪怕是,我們想要更佳平滑的彌補HashMap的多線程坑,不懂數據結構,那是絕對不可能的。

也許百度百度,可能大家都能知道怎么弄。可是自我思考得來的解決與百度來的解決,那是截然不同的兩種能力等級!解決問題的速度,也是不一樣的。更佳的,當面臨系統優化、制定規則引擎、寫一些系統工具,那算法與數據結構就是無論如何都無法繞開的了。所以為什么很多大廠面試,為啥愿意面算法,讓你手寫算法,原因在此。本來就是更上了一個level啊!是否錄取一個應聘者,如何開工資,能力等級是多少,高下立判!

一、算法原題

Kiwiland市的鐵路系統服務于多個城鎮。由于資金問題,所有線路均為“單向線路”。例如,由Kaitaia向Invercargill的方向有一條鐵路線,但反方向卻沒有路線。事實上,即使這兩個方向都有鐵路線,他們也可能是不同的線路軌跡,里程數也不一定相同。

這道題就是要幫助鐵路系統為乘客提供線路信息。具體來講,你需要計算出某條線路的里程數,兩個城鎮之間的線路數量以及其中的最短線路。

**Input:**一個有向圖(directed graph),其中的節點表示一個城鎮,線表示兩個城鎮間的線路,線的權重表示距離。一條線路不得出現兩次或以上,且起點城鎮和終點城鎮不得相同。

**Output:**測試1至5,如果該線路不存在,則輸出 'NO SUCH ROUTE',否則就按照給定的線路行進,注意不要添加任何其他站點! 例如,在下面第1條線路中,必須從A城開始,直接到達B城(距離為5),然后直接到達C城(距離為4)。

  • 線路A-B-C的距離
  • 線路A-D的距離
  • 線路A-D-C的距離
  • 線路A-E-B-C-D的距離
  • 線路A-E-D的距離
  • 從C點開始,在C點結束,沿途最多可以有3個站點,符合該要求的線路有幾條? 在下面給出的示例數據中,共有2條符合線路:C-D-C (2 站),C-E-B-C (3 站)
  • 從A點開始,在C點結束,要求線路上必須有4個站點,符合該要求的線路有幾條? 在下面給出的示例數據中,共有3條符合線路:A 到 C (通過 B,C,D); A 到 C (經過 D,C,D); 以及 A 到 C (經過 D,E,B).
  • A 到 C的最短路線長度
  • B 到 B的最短路線長度
  • 從C點開始,在C點結束,要求距離小于30,符合該要求的線路有幾條? 在下面給出的示例數據中,符合條件的線路有:CDC, CEBC, CEBCDC, CDCEBC, CDEBC, CEBCEBC, CEBCEBCEBC.
  • 測試輸入:

    在測試輸入中,城鎮名字由A、B、C、D代表。例如AB5表示從A到B,線路距離為5.

    圖表: AB5, BC4, CD8, DC8, DE6, AD5, CE2, EB3, AE7

    要求輸出:

    Output #1: 9

    Output #2: 5

    Output #3: 13

    Output #4: 22

    Output #5: NO SUCH ROUTE

    Output #6: 2

    Output #7: 3

    Output #8: 9

    Output #9: 9

    Output #10: 7

    從題目可以看出,其實就是要實現一個最簡單的圖,并最終實現一個最短路徑的算法。當然這個過程中,會涉及一些數據結構與算法:堆(索引最小堆)、鄰接矩陣表示圖、圖的深度優先遍歷、有環圖的遍歷、Dijkastra最短路徑算法(正權邊)。下面會一個個來說。

    二、最小堆

    首先我們圍繞這道題,從最最基礎的結構 — 堆,說起。以往,各種教學,都從大頂堆講,然后自己私下去拓展學小頂堆,這回我們直接從小頂堆,來入手。首先讓我們看看堆的定義(來源于維基百科):

    (英語:Heap)是計算機科學中的一種特別的樹狀數據結構。若是滿足以下特性,即可稱為堆:“給定堆中任意節點 P 和 C,若 P 是 C 的母節點,那么 P 的值會小于等于(或大于等于) C 的值”。若母節點的值恒小于等于子節點的值,此堆稱為最小堆(min heap);反之,若母節點的值恒大于等于子節點的值,此堆稱為最大堆(max heap)。在堆中最頂端的那一個節點,稱作根節點(root node),根節點本身沒有母節點(parent node)。

    總結下:

    • 樹狀結構
    • 完全二叉(多叉)樹(除了葉子節點,其他節點必須所有孩子都有值)
    • 任意父親節點大于(小于)或者等于孩子節點
    • 大于:最大堆;小于:最小堆

    下面是堆的基礎模型圖:

    相應的,我們使用的存儲堆的數據結構,更多的使用一個數組,如下:

    使用數組具體的母子節點的換算公式是:

    • 獲取當前節點的父親節點索引:parentNodeIndex = (currentNodeIndex-1)/2
    • 獲取當前節點的孩子索引:
      • 左孩子:leftNodeIndex = currentNodeIndex*2 + 1
      • 右孩子:rightNodeIndex = currentNodeIndex*2 + 2

    下面是我總結的大體上堆這種數據結構的優點:

    • 快速的獲取最大(最小)值:O(1)復雜度
    • 簡單、快速的底層存儲邏輯
    • 堆排序(O(nlogn))

    三、最小堆的核心實現(基于Java)

    先給出基礎的骨架代碼

    public class MinPriorityQueue<K extends Comparable<K>> {// 堆的基礎存儲數據結構private Object[] elements;// 當前堆中元素個數private int size;public MinPriorityQueue() {this.elements = new Object[Common.INIT_SIZE];this.size = 0;}private void checkLength(int index) {if (index < 0 || index >= this.elements.length) {throw new IllegalArgumentException("超出限制");}}public int lchild(int index) {checkLength(index);return (index * 2) + 1;}public int rchild(int index) {checkLength(index);return (index * 2) + 2;}public int parent(int index) {checkLength(index);return (index - 1) / 2;}public void swap(int i, int j) {checkLength(i);checkLength(j);K temp = (K) elements[i];elements[i] = elements[j];elements[j] = temp;}@Overridepublic String toString() {return "MinPriorityQueue{" +"elements=" + Arrays.toString(elements) +", size=" + size +'}';} }

    有幾點:

    • 內部存儲由于擦除原因,使用了Object
    • 每個泛型參數類型都要是可比較類型(Comparable),因為要比較父子節點大小
    • size表示當前堆中元素大小
    • 當然,這里可以直接使用Comparable類型的基礎數組存儲

    1、上浮操作與添加元素

    上浮是保證整個堆保證原先數據規則的一種手段,主要用于添加元素的時候,每次添加元素,我們會直接放到內部基礎數組最后一個索引位置,然后做上浮操作,下面我們隨便添加一個數字(9),然后看看整體上浮過程是如何變化的:

    整個過程比較簡單,主要是當前節點和父親加點比較:

    /*** 上浮*/public void swam(int index) {// 防止索引溢出checkLength(index);int p = index;while (p > 0) {K currentEle = (K) elements[p];int parentIndex = parent(p);// 核心,用于比對當前節點與父親節點的大小if (currentEle.compareTo((K) elements[parentIndex]) < 0) {// 交換當前索引與父親節點索引中的值swap(p, parentIndex);p = parentIndex;} else {// 一旦發現當前值大于父親節點,就停止循環break;}}}

    有了上浮操作,那么向堆中添加元素的代碼也是比較簡單的了:

    /*** 添加元素*/public void addElement(K element) {if (size == elements.length) {// 添加堆的容量resize();}elements[size] = element;swam(size);// 維護當前堆數量大小size++;}/*** 擴容*/public void resize() {int length = elements.length;Object[] tempArr = new Object[length + Common.GROW_SIZE];System.arraycopy(elements, 0, tempArr, 0, length);this.elements = tempArr;}

    2、下沉操作與刪除元素

    相對比較來說,下沉會更加復雜一些,復雜點在于,每次都要進行當前節點與幾個孩子節點的比較操作,可是當前節點是否有孩子節點,還是要判斷的。總的來說,要花心思去保護索引溢出的情況。首先,讓我們看看刪除一個堆內元素是如何進行的:

    • 保存堆頂元素的值
    • 交換堆頂和最后的結點
    • 刪除最后一個節點的值,指向null
    • 對堆頂(索引為0)做下沉操作

    下面是下沉操作的基礎代碼:

    /*** 下沉*/public void sink(int index) {checkLength(index);int p = index;/*** 如果左孩子大于或者等于當前堆中元素個數的話,* 表明當前節點已經是葉子節點,可以不用繼續遍歷了*/while (p < size && lchild(p) < size) {K currentEle = (K) elements[p];// 獲取左孩子索引int lchild = lchild(p);// 獲取右孩子索引int rchild = rchild(p);// 獲取左孩子的值K lelement = (K) elements[lchild];// 獲取右孩子的值K relement = (K) elements[rchild];// 核心,獲取左右孩子最小值的那個節點索引,注意,這里右孩子有可能為空int minChildIndex = Objects.isNull(relement) ? lchild :(lelement.compareTo(relement) > 0 ? rchild : lchild);// 使用當前節點值與最小值比較,如果當前值還要小,那就交換if (currentEle.compareTo((K) elements[minChildIndex]) > 0) {swap(p, minChildIndex);p = minChildIndex;} else {break;}}}

    在這里,主要對節點索引進行了詳盡的判斷與保護,接下來,就是刪除元素的方法代碼:

    /*** 刪除堆頂元素*/public K delElemet() {if(size == 0){throw new IllegalArgumentException("當前堆已經空了");}K result = (K) elements[0];if (size > 1) {swap(0, size - 1);elements[--size] = null;sink(0);} else {size--;}return result;}

    3、調整數組成為一個最小堆

    通常情況下,我們接收到的是一整個數組的值,然后需要我們整理,才能變成一個最小堆,這個過程我們稱它為:heapify。就是重新調整。讓我們來看下一組數組Integer[] arr = {90,34,99,57,11,67,55,23,76,33,45}如何進行從新調整的:

    做一些介紹:

    • 每次從第一個非葉子節點開始進行每個節點的下沉操作
    • 第一個非葉子節點的索引 = (最后一個節點索引-1)/2
    • 整體時間復雜度是:O(n)

    下面就是基礎的代碼實現:

    // 每次傳入數組的大小 public MinPriorityQueue(Comparable[] comps) {if (Objects.isNull(comps) || comps.length == 0) {throw new IllegalArgumentException("數組不能為空");}this.elements = new Object[comps.length];this.size = 0;for (int i = 0; i < comps.length && comps[i] != null; i++) {this.elements[i] = comps[i];this.size++;}heapify();}private void heapify() {if (this.size == 0) {return;}int index = (this.size - 2) / 2;for (int i = index; i >= 0; i--) {// 下沉sink(i);}}

    到此,我們對于一個最小堆的全部實現,就完成了。下面開始介紹基于堆的一種拓展數據結構 — 索引最小堆

    四、索引最小堆

    經歷了最小堆的"洗禮",發現如下幾個問題:

    • 每次交換都是使用原始元素進行交換
    • 沒提供修改固定索引元素的方法
    • 如果每個節點元素是一個復雜且龐大的值,那么交換過程會導致很多問題(慢、內存溢出)

    就此,索引堆概念出現了:

    • 每個實際元素的數組中的索引位置不變
    • 另申請一個與堆同等大小的數組,存儲每個元素在堆中實際位置
    • 再來一個同等大小的數組,反向索引具體堆中的位置(數組索引 —> 堆上的索引)

    (最后一點最不好理解,后面會有介紹)如此一來,每次元素添加到堆中,具體的元素就不會隨著上浮下沉而變換位置,真正變換的,是索引值(就是一個整型)。

    1、索引最小堆演示

    下面我根據上面最小堆,進一步擴展成索引最小堆,一步步演示,我們使用的原始數組是:

    Integer[] arr = {90,34,99,57,11,67,55,23,76,33,45}

    (1)不加反向索引

    可以看到全程沒有進行存儲元素的移動,全部是元素所對應的索引值進行移動,這樣一來,就能很好的解決上面元素復雜,移動緩慢的問題。

    (2)加上反向索引

    上面的索引堆還存在一個問題,就是,我更改堆中對應一個具體索引的元素值,之后,我并不知道這個值對應的具體在堆中的位置,例如:

  • 改變索引4中元素11的值:data[4] = 12
  • 我們想要確定11這個元素堆中的位置(其實是在索引數組的第一個位置上,就是0上面)
  • 然后根據這個位置,對這個位置前面的進行上浮操作,這個位置后面的進行下沉操作,這樣就能從新調整堆
  • 這個時候,反向索引就有用了!我下面展現下最終加上反向索引的最終形式:

    如果i表示具體索引值,recs表示反向索引數組,indexes表示索引數組,這幾個的關系是:

    • recs[indexes[i]] = i
    • indexes[recs[i]] = i

    反向數組不太好理解,可以多看看,多看看。其實就是一個存儲當前索引對應的數據,在堆中的位置,這個位置其實也是一個索引,只不過這個索引指向的是索引數組

    2、索引最小堆的基礎實現

    首先是基礎框架的代碼:

    public class IndexMinPriorityQueue<K extends Comparable<K>> {// 索引數組private int[] indexes;// 原始數據的數組private Object[] elements;// 反向索引數組private int[] recs;// 當前堆元素的大小private int size;public IndexMinPriorityQueue() {this.indexes = new int[Common.INIT_SIZE];this.elements = new Object[Common.INIT_SIZE];this.recs = new int[Common.INIT_SIZE];this.size = 0;for (int i = 0; i < Common.INIT_SIZE; i++) {this.indexes[i] = -1;this.recs[i] = -1;}}public IndexMinPriorityQueue(int count) {this.indexes = new int[count];this.elements = new Object[count];this.recs = new int[count];this.size = 0;for (int i = 0; i < count; i++) {// 默認初始化時候,堆內沒有元素時候兩個索引數組的每個字段都初始化成-1this.indexes[i] = -1;this.recs[i] = -1;}} }

    加入了兩個輔助性質的數組,我們來看看其他的一些修改點,首先是交換數據的方法:

    public void swap(int i, int j) {if (i < 0 || i >= size) {throw new IllegalArgumentException("超出限制");}if (j < 0 || j >= size) {throw new IllegalArgumentException("超出限制");}// 可以看到,每次只交換索引數組中的值,真實數據數組不變int temp = indexes[i];indexes[i] = indexes[j];indexes[j] = temp;// 反向索引數組內部值的確認recs[indexes[i]] = i;recs[indexes[j]] = j;}

    相應的,上浮與下沉的方法也是要變動的:

    /*** 下沉*/public void sink(int index) {if (index < 0 || index > size) {throw new IllegalArgumentException("超出限制");}int p = index;while (p < size && lchild(p) < size) {// 可以看到,每次取元素,都是要據具體的索引數組的值來定位真實數據數組的位置K currentEle = (K) elements[indexes[p]];int lchild = lchild(p);int rchild = rchild(p);K lelement = (K) elements[indexes[lchild]];// 索引數組的值為-1,表示當前元素被刪除或者就是沒存入int minChildIndex = indexes[rchild] == -1 ? lchild :(lelement.compareTo((K) elements[indexes[rchild]]) > 0 ? rchild : lchild);if (currentEle.compareTo((K) elements[indexes[minChildIndex]]) > 0) {swap(p, minChildIndex);p = minChildIndex;} else {break;}}}/*** 上浮*/public void swam(int index) {if (index < 0 || index >= size) {throw new IllegalArgumentException("超出限制");}int p = index;while (p > 0) {K currentEle = (K) elements[indexes[p]];int parentIndex = parent(p);K pelement = (K) elements[indexes[parentIndex]];if (Objects.nonNull(pelement) && currentEle.compareTo(pelement) < 0) {swap(p, parentIndex);p = parentIndex;} else {break;}}}

    添加是對添加蒜素的修改:

    /*** 添加元素*/public void addElement(K element) {if (size == elements.length) {// 擴容resize();}// 索引數組的末尾添加這個元素的索引值indexes[size] = size;// 反向索引也是最后一位添加recs[size] = size;// 其實這也是最后一位添加,因為此時indexes[size] = sizeelements[indexes[size]] = element;// 先對最后一位的索引進行上浮操作,然后再將size加一swam(size++);}/*** 擴容*/public void resize() {int length = elements.length;Object[] tempArr = new Object[length + Common.GROW_SIZE];int[] tempIndexes = new int[length + Common.GROW_SIZE];int[] tempRecs = new int[length + Common.GROW_SIZE];System.arraycopy(elements, 0, tempArr, 0, length);System.arraycopy(indexes, 0, tempIndexes, 0, length);System.arraycopy(recs, 0, tempRecs, 0, length);for (int i = length; i < tempIndexes.length; i++) {tempIndexes[i] = -1;tempRecs[i] = -1;}this.elements = tempArr;this.indexes = tempIndexes;this.recs = tempRecs;}

    下面看看刪除一個堆頂元素的修改:

    /*** 刪除堆頂元素** @return 堆頂的具體元素值*/public K delElemet() {K result = (K) elements[indexes[0]];delEl();return result;}/*** 刪除堆頂元素** @return 堆頂的具體元素索引值*/public int delElemetIndex() {int result = indexes[0];delEl();return result;}private void delEl() {if (size > 1) {// 這里其實是交換索引數組的第一位和最后一位的值swap(0, size - 1);}// 此時要把末尾的索引值對應的元素置空,代表刪除原始數據elements[indexes[--size]] = null;// 當然,反向索引數組的值也要刪除,置位-1recs[indexes[size]] = -1;// 當然,最后要把索引數組值刪除,其實就是最后一位indexes[size] = -1;// 對索引數組,就是第一位開始,做下沉sink(0);}

    最后的最后,我們就可以看看如何修改一個堆中的元素了

    public void change(int index, K element) {if (index < 0 || index > size) {throw new IllegalArgumentException("超出限制");}this.elements[index] = element;// 這時候,反向索引數組就顯示作用了:獲取這個修改值對應的堆中的索引值int currentHeapIndex = this.recs[index];swam(currentHeapIndex);sink(currentHeapIndex);}

    五、圖的基礎

    好吧,到了圖這里,已經深入到計算機科學領域了,我作為一個工程狗,真心無法,也沒有能力一箭到底!所以在此,我先上定義,然后我們截取最簡單,切合具體的實際問題(這里就是第一章那道題)來說相關的圖論的基礎結構與算法,其他的,有關圖論的東西太多太多,有興趣可以自己深入研究。下面是wiki上面的一個定義:

    圖有多種變體,包括簡單圖、多重圖、有向圖、無向圖等,但大體上有以下兩種定義方式。

    二元組的定義

    一張 是一個二元組,其中稱為頂點集,稱為邊集。它們亦可寫成和。 的元素是一個二元組數對,用表示,其中。

    三元組的定義

    一張 是一個三元組,其中稱為頂集(Vertices set),稱為邊集(Edges set),與不相交;稱為關聯函數,將中的每一個元素映射到。如果那么稱邊連接頂點,而則稱作的端點,此時關于相鄰。同時,若兩條邊有一個公共頂點,則稱關于相鄰。

    恩,說實話,我也看不懂,具體對于我們這次要解決的實際問題,相關的數據結構的知識點,提取出以下幾點:

    • 我們要實現一個有向圖
    • 而且是有向加權圖
    • 會有環
    • 邊用E(edge)來表示
    • 節點用V(Vertices)來表示
    • 我們這里固定使用一種表示方法來進行圖的存儲:鄰接表

    下面我們就開搞!

    1、有向圖

    我們來看看題目中,要我們實現的有向圖的基本輸入是:

    AB5, BC4, CD8, DC8, DE6, AD5, CE2, EB3, AE7

    根據此文字表述,我們畫出如下的示意圖:

    有話說:不要在意邊的長短與權值大小的對應比例,只是一種展示、展示、展示!

    接下來我們就用代碼來實現相應的V(定點)與E(邊)

    // 定點的抽象數據定義 public interface IVertices<V> {// 獲取這個節點的值V getData();// 獲取當前節點的索引值int getIndex(); }// 邊的抽象數據定義 public interface IEdge<V> {// 獲取一條邊起始頂點的對象V getV1();// 獲取一條邊結束頂點的對象V getV2();// 獲取一條邊的權值int getWeight(); }

    2、鄰接表存儲表示法

    最常用的圖的表示法有兩種:鄰接矩陣、鄰接表。響應的適用場景如下:

    • 鄰接矩陣:適用于稠密圖
    • 鄰接表:適用于稀疏圖

    一般來說,我們解決實際問題,都是稀疏圖,所以常用鄰居表,本次我們只看鄰接表的表示法,來存儲一個圖。下面是基本的鄰接表示意圖:

    根據上面這個圖的展示,整個圖使用鄰接表存儲,會有下面的幾點:

    • 一個圖對象保存一個map
    • key值是圖中的頂點
    • value值是list,list中的每個值是以key值頂點為起始的邊
    • 頂點對象要實現hashCode與equals方法,因為要當key

    下面就是一個圖的基本代碼實現,使用鄰接表的方式:

    public class Graph<V extends IVertices, E extends IEdge<V>> {// 當前圖中的結點數目private int vsize;// 當前圖中的邊的數目private int esize;// 鄰接表private Map<V, List<E>> vectors;public Graph() {this.vsize = 0;this.esize = 0;this.vectors = new HashMap<>();}// 根據所有的結點來初始化public Graph(V[] datas) {if (Objects.isNull(datas) || datas.length == 0) {throw new IllegalArgumentException("初始化失敗");}this.vsize = datas.length;this.esize = 0;this.vectors = new HashMap<>();for (int i = 0; i < this.vsize; i++) {this.vectors.put(datas[i], new LinkedList<>());}}// 添加一條邊public void addEdge(E w) {List<E> ts = this.vectors.get(w.getV1());if (ts == null) {throw new IllegalArgumentException("這個節點不存在");}if (!ts.contains(w)) {ts.add(w);this.esize++;}}// 獲取總節點數public int getVsize() {return vsize;}// 獲取總邊數public int getEsize() {return esize;}public Map<V, List<E>> getVectors() {return vectors;} }

    六、圖的遍歷(深度優先)

    根據題目,我這里介紹深度優先遍歷的整個過程與實現。當然還有廣度優先遍歷,會在后面的最短路徑上深入介紹。

    1、題目節點遍歷展示

    我們隨便找出一個小題:

    從C點開始,在C點結束,沿途最多可以有3個站點,符合該要求的線路有幾條? 在下面給出的示例數據中,共有2條符合線路:C-D-C (2 站),C-E-B-C (3 站)

    從上面的圖,我們來看下整體深度遍歷是如何進行的:

    細心的看這個動態圖,很好的展示了,整個深度遍歷的求解過程。

    2、代碼實現

    下面我就用代碼來實現這一過程。相對來說,要實現這個過程并非那么容易,因為要控制類似于:"最多","剛好","最多長度"等這些個區間求解。所以,要有響應的訪問計數值,來進行輔助。首先我們來看看深度遍歷圖的對象的基礎:

    public class WordDepestPath {// 要遍歷的圖private Graph<WordVector, WordEdge> graph;// 記錄當前邊被訪問到的次數private Map<WordEdge, Integer> edgeVisitedCount;// 記錄當前頂點被訪問到的次數private Map<WordVector, Integer> verticesVisitedCount;public WordDepestPath(Graph<WordVector, WordEdge> graph) {this.graph = graph;this.edgeVisitedCount = new HashMap<>();this.verticesVisitedCount = new HashMap<>();// 獲取圖的鄰接表Map<WordVector, List<WordEdge>> vectors = graph.getVectors();// 遍歷所有的邊,進行初始化for (Map.Entry<WordVector, List<WordEdge>> entry : vectors.entrySet()) {List<WordEdge> value = entry.getValue();for (WordEdge it : value) {// 起始狀態頂點和邊都沒有被訪問到一次edgeVisitedCount.put(it, 0);verticesVisitedCount.put(it.getV1(), 0);}}} }

    這里的WordVector、WordEdge分別是IVertices、IEdge的實現,主要頂點內包裝了個字符串,例如:"A"。當然,因為要作為map的key值,必須要實現hashcode與equals方法,如下代碼:

    public class WordEdge implements IEdge<WordVector>, Comparable<WordEdge> {private WordVector v1, v2;private int weight;public WordEdge() {}public WordEdge(WordVector v1, WordVector v2, int weight) {this.v1 = v1;this.v2 = v2;this.weight = weight;}@Overridepublic WordVector getV1() {return v1;}@Overridepublic WordVector getV2() {return v2;}@Overridepublic int getWeight() {return weight;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;WordEdge wordEdge = (WordEdge) o;return weight == wordEdge.weight &&Objects.equals(v1, wordEdge.v1) &&Objects.equals(v2, wordEdge.v2);}@Overridepublic int hashCode() {return Objects.hash(v1, v2, weight);}@Overridepublic String toString() {return "WordEdge{" +"v1=" + v1 +", v2=" + v2 +", weight=" + weight +'}';}@Overridepublic int compareTo(WordEdge o) {return this.weight - o.getWeight();} }public class WordVector implements IVertices<String>, Comparable<WordVector>{private int index;private String word;public WordVector() {}public WordVector(int index, String word) {this.index = index;this.word = word;}@Overridepublic int getIndex() {return index;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;WordVector that = (WordVector) o;return index == that.index &&Objects.equals(word, that.word);}@Overridepublic int hashCode() {return Objects.hash(index, word);}@Overridepublic String toString() {return word;}@Overridepublic int compareTo(WordVector o) {return this.getIndex() - o.getIndex();}@Overridepublic String getData() {return this.word;} }

    下面是深度遍歷的入口方法:

    public List<List<WordEdge>> depestPath(WordVector src, WordVector dest) {List<List<WordEdge>> result = new ArrayList<>();Map<WordVector, List<WordEdge>> vectors = this.graph.getVectors();List<WordEdge> wordEdgesSrc = vectors.get(src);List<WordEdge> wordEdgesDest = vectors.get(dest);if (wordEdgesSrc == null || wordEdgesDest == null) {throw new IllegalArgumentException("沒有此次搜索路徑的結點");}for (WordEdge edge : wordEdgesSrc) {Stack<WordEdge> stack = new Stack<>();stack.push(edge);edgeVisitedCount.put(edge, edgeVisitedCount.get(edge) + 1);depestPathLargest3(edge, dest, 1, stack, result);edgeVisitedCount.put(stack.peek(), 0);stack.pop();}return result;}

    最后是我們核心深度遞歸遍歷圖的方法:

    /*** 最多三站地的路徑求解方法* 解決思路:* 如果整個路徑上面最多只允許有三個頂點(除開起始節點)* 那么就是說,如果是一個有環有向圖,那么這個解的邊* 最多只能被訪問一次。如果多被訪問一次,那么就會超出* 三個頂點的題目要求,所以整個過程,重點要控制這個邊* 的訪問次數* @param currentEdge 當前遍歷到的邊* @param dest 目標頂點* @param largest 當前遍歷到的站點的數量* @param stack 棧,用于輔助保存遍歷節點* @param result 結果集,保存了所有符合條件的路徑*/private void depestPathLargest3(WordEdge currentEdge, WordVector dest, int largest,Stack<WordEdge> stack, List<List<WordEdge>> result) {// 遞歸終止條件if (edgeVisitedCount.get(stack.peek()).intValue() >= 2) {stack.pop();return;}WordVector v2 = currentEdge.getV2();// 注意這里:如果到了目的頂點,但是不滿足最長路徑值,同樣不能成為結果if (v2.getData().equals(dest.getData()) && largest <= 3) {// 此分支,就是表示一條我們求解的路徑ArrayList<WordEdge> rightPath = new ArrayList<>();result.add(rightPath);for (WordEdge it : stack) {rightPath.add(it);}}List<WordEdge> edges = this.graph.getVectors().get(v2);// 這種情況表示下個頂點沒有臨邊,那就要棧頂的邊不可走,要出棧if (edges.isEmpty()) {stack.pop();return;}// 對當前層遍歷到的邊的結束頂點,進行鄰接邊的遍歷for (WordEdge it : edges) {// 每每遍歷到了一個鄰接邊,要進行入棧+計數stack.push(it);edgeVisitedCount.put(it, edgeVisitedCount.get(it) + 1);// 開始遞歸depestPathLargest3(it, dest, largest + 1, stack, result);}/*** 注意這里,走到了這個地方,表示遍歷鄰邊已經結束,* 每次彈出一個值的之前,要把這個鄰邊對應的訪問計數* 清零,為了不影響后面的遞歸結束判斷*/edgeVisitedCount.put(stack.peek(), 0);stack.pop();}

    根據這種思路,我們要求解下面兩個問題,也是依葫蘆畫瓢了:

  • 從A點開始,在C點結束,要求線路上必須有4個站點,符合該要求的線路有幾條? 在下面給出的示例數據中,共有3條符合線路:A 到 C (通過 B,C,D); A 到 C (經過 D,C,D); 以及 A 到 C (經過 D,E,B).
  • 從C點開始,在C點結束,要求距離小于30,符合該要求的線路有幾條? 在下面給出的示例數據中,符合條件的線路有:CDC, CEBC, CEBCDC, CDCEBC, CDEBC, CEBCEBC, CEBCEBCEBC.
  • 七、圖的最短路徑問題

    我們這里求最短路徑,使用最經典的迪杰克斯拉算法(Dijkstra),這個算法,用來求單源最短路徑使用,有一定的限制:

    • 所有邊的權值只能是正數,不能有負權邊
    • 每次要使用索引堆進行輔助

    下面我們一步步來講解下,如何求上面算法題中的一小題,就是最短路徑的問題:

    A 到 C的最短路線長度

    1、迪杰克斯拉算法展示

    下面是動圖展示,然后我們一步步說如何求解:

    一些前置條件:

  • 索引堆中,索引值對應每個節點:1->A,2->B,3->C,4->D,5->E
  • 索引堆中,具體的真實值存儲選取的單源節點到當前節點最短的路徑值:A->0,B->5,C->9,D->5,E->7
  • 下面是具體的求解過程:

  • 首先將原點加入到堆中,那原點對應的值是0
  • 開始循環從堆中拿堆頂的數據,直到堆為空為止
  • 每次拿到數據之后,遍歷拿到的節點的所有鄰邊
  • 拿到每個鄰邊的另一端的結點,判斷這個節點是否被確定下來
  • 如果沒有確定下來,那就看當前從此路徑過來的總路徑,是否比當前節點的路徑要短
  • 如果短,則跟新當前節點的路徑值,如果不短,則跳過
  • 當然,這個結點有可能還沒有統計過路徑長度,路徑為空,這種時候直接將節點,對應的路徑值,壓入索引堆中
  • 如果當前節點已經是確定路徑的結點了,那就跳過當前節點與鄰邊的遍歷
  • 注意:每次從堆頂拿到的,是最小的路徑值,那這個路徑對應另一端的節點就被確認下來,因為我們沒有考慮負權邊,所以不可能存在另外一個路徑,到這個節點還要短,所以每次堆頂拿到的值,必須要被標記成已確定
  • 如此遍歷,直到堆為空的情況結束
  • 這就是全過程,下面我們來看看代碼實現

    2、迪杰克斯拉算法的代碼實現

    public class Dijsktra {// 我們要求解的原圖(鄰接表存儲)private Graph<WordVector, WordEdge> graph;// 索引小頂堆private IndexMinPriorityQueue<Integer> queue;// 保存每個節點是否被確認下來的映射,默認是falseprivate Map<WordVector, Boolean> isMarked;// 保存源節點到每個節點的最小路徑值private Number[] distTo;// 保存每個節點的最短路徑是從那個鄰邊到達的private WordEdge[] from;public Number[] getDistTo() {return distTo;}public Dijsktra(Graph<WordVector, WordEdge> graph, WordVector src) {this.graph = graph;this.queue = new IndexMinPriorityQueue<>(graph.getVsize());this.isMarked = new HashMap<>();distTo = new Number[graph.getVsize()];from = new WordEdge[graph.getVsize()];// 默認將每個節點的確認映射,設置成false,就是都是未確認狀態for (Map.Entry<WordVector, List<WordEdge>> entry : graph.getVectors().entrySet()) {WordVector key = entry.getKey();isMarked.put(key, false);}// 初始化最短路徑保存數組,與最短路徑的鄰邊數組for (int i = 0; i < graph.getVsize(); i++) {distTo[i] = 0.0;from[i] = null;}// 第一個將源節點加入到結構中from[src.getIndex()] = new WordEdge(src, src, 0);// 注意,加入的索引值與對應的結點,還有值是路徑的長度this.queue.insert(src.getIndex(), from[src.getIndex()].getWeight());this.isMarked.put(src, true);// 開始遍歷索引堆while (!this.queue.isEmpty()) {// 獲取堆頂的元素索引Integer nodeIndex = this.queue.delElemetIndex();// 通過索引值與鄰邊數組,獲取對應的當前遍歷的堆頂定點WordVector v2 = from[nodeIndex].getV2();// 當前節點就是最短路徑了,所以標記已被確認this.isMarked.put(v2, true);// 開始遍歷當前節點的所有鄰邊List<WordEdge> edges = this.graph.getVectors().get(v2);for (WordEdge it : edges) {// 查詢鄰邊另一邊的結點,看看路徑情況WordVector nextNode = it.getV2();if (!this.isMarked.get(nextNode)) {int nextNodeIndex = nextNode.getIndex();/*** 核心:首先的if邏輯判斷很關鍵,* 看看當前節點索引對應的路徑值有沒有開始統計,* 并且如果開始統計有值的話,就計算從當前鄰邊到* 達當前節點的路徑長度,是否小于已經存在的路徑* 如果小,就要更新,不小就略過。*/if (from[nextNodeIndex] == null|| distTo[v2.getIndex()].intValue() + it.getWeight() < distTo[nextNodeIndex].intValue()) {// 內部,表示要更新當前節點的最短路徑,那就要改各個數組與索引堆中的值distTo[nextNodeIndex] = distTo[v2.getIndex()].intValue() + it.getWeight();from[nextNodeIndex] = it;// 索引堆也有兩種情況,有這個值,沒這值if (queue.contain(nextNodeIndex))queue.change(nextNodeIndex, distTo[nextNodeIndex].intValue());elsequeue.insert(nextNodeIndex, distTo[nextNodeIndex].intValue());}}}}} }

    如此,其實已經解決了我們題目中的所有問題

    轉載于:https://my.oschina.net/UBW/blog/3039949

    總結

    以上是生活随笔為你收集整理的算法我也不知道有没有下一个---一个题目的开端(索引堆与图)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    香蕉网站在线观看 | 国际精品久久久久 | 91久久精品一区 | 亚洲精品国偷拍自产在线观看蜜桃 | 久久艹综合 | 久久久成人精品 | 亚洲无吗av| 日韩久久精品一区二区三区下载 | 伊人资源视频在线 | 日韩女同av | 亚洲精品国产自产拍在线观看 | 日本精品久久久久中文字幕 | 中文字幕韩在线第一页 | 亚洲黄在线观看 | 99成人精品| 日韩理论电影网 | 99精品久久精品一区二区 | 91久久爱热色涩涩 | av观看久久久 | 亚洲人成影院在线 | 2019中文 | 欧美在线视频一区二区三区 | 日韩在线观看你懂的 | 国产一区二区精品久久 | 激情亚洲综合在线 | 高清视频一区二区三区 | 综合色爱| 婷婷精品 | 中文字幕资源站 | 国产资源网| 亚洲精品国偷自产在线99热 | 国产一区二区三区四区大秀 | 国产一区在线视频 | 国产精品3 | 久久国产精品免费 | 日本精品视频一区 | 欧美孕妇与黑人孕交 | 久久精品99北条麻妃 | 国产精品久久久久久久久久久久午夜 | 97人人模人人爽人人少妇 | 国内久久精品 | 亚洲精品一区二区精华 | 黄色电影小说 | 99视频在线精品国自产拍免费观看 | 人人模人人爽 | 日韩中文幕 | 国内精品久久久久久中文字幕 | 亚洲黄色一级电影 | 午夜av一区二区三区 | 欧美日产在线观看 | www178ccom视频在线 | 国产精品久久久久久久久久久久久久 | 日韩免费电影 | 亚洲成人av免费 | 91精品国产麻豆国产自产影视 | 99久久国产免费免费 | 欧美日韩高清一区二区 国产亚洲免费看 | 久久99国产精品久久99 | 69精品视频| 国产午夜麻豆影院在线观看 | 日韩理论电影网 | 国产探花在线看 | 欧美性色19p | 99国产在线| 亚洲一区二区三区四区精品 | 91成人精品一区在线播放69 | 开心激情五月网 | 中文字幕一区二区三区在线播放 | 97在线观看免费视频 | 中文字幕二区三区 | 97在线影视| 日韩免费| 日本久久中文字幕 | 91在线看视频免费 | 日韩在线观看网址 | 美女av电影 | 中文一区二区三区在线观看 | 午夜精品久久久久久久爽 | 中文国产字幕在线观看 | 91成人网在线 | 中文字幕网址 | 激情av网址 | 99热精品国产一区二区在线观看 | 色噜噜在线观看 | 久久综合福利 | 97av视频| 中文字幕免费一区 | 在线看成人av | 欧美一级网站 | 国产成人久久精品77777 | 91精品日韩| 13日本xxxxxⅹxxx20 | 久久久私人影院 | 国产精彩视频 | 日本精品va在线观看 | 国产精品中文在线 | 99久久久国产精品免费观看 | 亚洲精选在线 | 亚洲精品在线观 | 中文在线字幕免费观 | 国产视频一区二区在线 | 精品免费久久 | 在线精品视频免费播放 | 成人免费在线观看电影 | 久久av一区二区三区亚洲 | 手机在线看片日韩 | 国产在线毛片 | 毛片激情永久免费 | av 一区 二区 久久 | 国产精品伦一区二区三区视频 | 国产一二三区av | 片黄色毛片黄色毛片 | 免费看黄在线看 | 狠狠色伊人亚洲综合网站色 | 在线小视频国产 | 日韩免费一级a毛片在线播放一级 | 久久久毛片 | 蜜桃视频在线观看一区 | 96在线| 麻豆传媒视频在线播放 | 久久精品99国产精品日本 | 综合激情婷婷 | 日韩大片在线免费观看 | 四虎精品成人免费网站 | 国产精品无av码在线观看 | 在线电影播放 | 黄色一级大片在线观看 | 亚洲免费在线 | 果冻av在线 | 深夜精品福利 | 久久视频免费看 | 超碰在线人| 成人免费视频播放 | 日韩在线免费电影 | 免费高清在线观看电视网站 | 亚洲黄色三级 | 91大神免费在线观看 | 亚洲综合精品在线 | 99免在线观看免费视频高清 | 超级碰99 | 成人三级网址 | 久久夜夜爽| 久久小视频 | 亚洲乱码精品久久久久 | 精品亚洲成人 | 国产高清av在线播放 | 国产剧情av在线播放 | 在线看不卡av | 五月综合激情 | 亚洲精品影视在线观看 | 久久在线免费 | 中文字幕在线播放一区二区 | 日日天天av | 久久女教师 | 亚洲春色综合另类校园电影 | 91九色免费视频 | 又黄又色又爽 | 亚洲精品视频中文字幕 | 在线视频电影 | 欧美性色网站 | 91在线区| 片黄色毛片黄色毛片 | 婷婷六月天综合 | 五月天国产精品 | 97人人澡人人添人人爽超碰 | 国内一级片在线观看 | 亚洲精品在线观看不卡 | www.av免费观看 | 91女神的呻吟细腰翘臀美女 | 国产成人在线免费观看 | 91视视频在线直接观看在线看网页在线看 | 91在线麻豆 | 日本韩国精品一区二区在线观看 | 国产亚洲日本 | 免费av大全| 日韩中文字幕在线不卡 | 免费在线观看视频一区 | 91精品久久久久久久91蜜桃 | 米奇狠狠狠888 | 日韩电影一区二区三区 | 18国产精品白浆在线观看免费 | 日韩视频一区二区三区在线播放免费观看 | 婷婷成人在线 | 中文字幕资源网 国产 | 亚洲精品自拍视频在线观看 | 成年人在线免费看 | 丁香婷婷综合五月 | 激情久久网| 四虎影视成人永久免费观看视频 | 超碰免费成人 | 国产欧美日韩精品一区二区免费 | 波多野结衣资源 | 久久男人中文字幕资源站 | 久久久久福利视频 | 在线观看国产福利片 | 欧美日韩在线观看不卡 | 在线观看视频免费播放 | 亚洲黄色免费电影 | 久久精品99国产精品酒店日本 | 不卡视频一区二区三区 | av国产网站 | 毛片一级免费一级 | 国产91精品看黄网站 | 美女国内精品自产拍在线播放 | 草久热 | 免费在线观看av不卡 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 国产一区二区视频在线播放 | 亚州精品一二三区 | 午夜在线资源 | 一级成人免费 | 日韩av在线免费看 | 亚欧日韩av| 亚洲国产免费看 | 激情av资源 | 夜夜爽88888免费视频4848 | 久久99日韩 | 免费欧美精品 | 99久久婷婷国产 | 欧美另类巨大 | 久久看免费视频 | 亚洲在线视频播放 | 精品久久毛片 | 国产精品麻豆果冻传媒在线播放 | 成人免费视频播放 | 国产精品免费久久久久久 | 视频一区在线免费观看 | 国产一区二区三区在线免费观看 | 一区在线电影 | 日韩欧美视频免费看 | 免费观看一区二区 | 天堂网一区二区三区 | 国产精品亚州 | 国产成人一区二区三区影院在线 | 午夜精品久久久久久久久久久 | 人人干网 | 婷婷色网视频在线播放 | 日韩一二区在线观看 | 99亚洲视频 | 久草精品视频在线观看 | 欧美性高跟鞋xxxxhd | 色综合小说 | 日韩a级免费视频 | 日韩特级黄色片 | 丁香婷婷基地 | 久久久九色精品国产一区二区三区 | av在线一级| 欧美日韩一区二区免费在线观看 | av免费网站在线观看 | 日韩电影在线观看一区二区三区 | 久久久激情视频 | 亚洲一区二区高潮无套美女 | 成年人视频在线免费观看 | av成人在线观看 | 久久精品一区二区三区国产主播 | 粉嫩av一区二区三区免费 | 九九热久久久 | 99久久久| 99亚洲国产 | 天天干天天做 | 在线观看91精品视频 | 九九在线高清精品视频 | 99操视频| 四虎成人精品在永久免费 | 婷婷伊人五月 | 四虎在线免费视频 | 久草视频资源 | 丁香导航 | 欧美亚洲国产精品久久高清浪潮 | 色小说av | 国产精品久久伊人 | 蜜臀久久99精品久久久酒店新书 | 免费黄色网址大全 | 一区二区三区免费看 | 久久精品高清 | 成人影音在线 | 天天射天天干 | 黄色片免费电影 | 久久久久免费精品视频 | 亚洲国产中文字幕在线 | 夜夜澡人模人人添人人看 | 国产黄色在线观看 | 在线观看精品黄av片免费 | 亚洲欧美精品一区二区 | 97精品国自产拍在线观看 | 久久综合亚洲鲁鲁五月久久 | 亚洲伊人天堂 | 伊人天堂久久 | 看黄色.com | 欧美在线一级片 | 久久99久久99精品免观看粉嫩 | 精品国产午夜 | 中文字幕中文字幕在线中文字幕三区 | www.久久久com | 中文字幕免费观看 | 亚洲精品无 | 国产午夜精品一区二区三区 | 在线观看国产www | 久久99九九99精品 | 亚洲伦理精品 | 免费看片日韩 | 日韩在线视频免费看 | 国产视频日韩视频欧美视频 | 久久精品国产99国产 | 超碰日韩在线 | 婷色| 免费毛片一区二区三区久久久 | 亚洲1级片 | 久草在线视频在线观看 | 日本性生活免费看 | 99色在线观看 | 亚洲精品久久久久www | 人人插人人做 | 美女福利视频一区二区 | 天天操天天干天天干 | 手机成人av在线 | 亚洲精品国产品国语在线 | 五月天丁香视频 | .国产精品成人自产拍在线观看6 | 天天干天天干天天射 | 国产成人无码AⅤ片在线观 日韩av不卡在线 | 国产精品成人一区二区 | 久久天天躁夜夜躁狠狠85麻豆 | 午夜10000| 国产黄网站在线观看 | 99久久爱 | 国内毛片毛片 | 三级视频国产 | 久久天天躁狠狠躁亚洲综合公司 | 天天色中文 | 亚洲精品乱码久久 | 日韩欧美69 | 国产精品一区二区三区四区在线观看 | 丁香婷婷激情五月 | 怡春院av| 女人魂免费观看 | 国产成人在线一区 | 在线观看午夜 | 国产精品 日韩精品 | 免费毛片一区二区三区久久久 | 色99导航 | 日韩在线视 | 国语自产偷拍精品视频偷 | 国产日韩在线视频 | 久久免费在线观看视频 | 西西444www | 久久久久伊人 | 免费视频99| 久久一久久 | 99久久影院 | av综合站| 免费色视频网址 | 久久久久国产精品一区 | 国产va饥渴难耐女保洁员在线观看 | 日韩欧美视频在线播放 | 国产成人精品aaa | 色婷婷综合视频在线观看 | 激情丁香5月 | 69av久久| 色夜视频 | 人人舔人人爽 | 美女免费电影 | 超碰97中文 | 激情综合中文娱乐网 | 国产精品一区二区精品视频免费看 | 麻豆视频入口 | 欧美成人黄色 | 亚洲日韩精品欧美一区二区 | 毛片黄色一级 | 亚洲综合干 | av免费看在线| 国产亚洲视频系列 | 手机av永久免费 | 日韩精品在线一区 | 国产区精品视频 | 国产成人福利在线观看 | 人人舔人人插 | 免费观看福利视频 | 国内一级片在线观看 | 国产在线中文 | 91av大全| 中文字幕不卡在线88 | 国产日韩欧美视频在线观看 | 亚洲精品视频 | 91视频在线免费下载 | av在线网站免费观看 | 午夜在线免费视频 | 欧美激情综合网 | 六月丁香综合网 | 免费在线观看国产精品 | 亚洲日本一区二区在线 | 国产在线中文字幕 | 久久综合福利 | 国产亚洲婷婷免费 | av在线在线 | 一区二区三区四区免费视频 | 国产精品久久久久婷婷 | 国产精品国产三级国产不产一地 | 亚洲精品资源 | www日韩精品 | 国产日韩av在线 | 久久久综合香蕉尹人综合网 | 日韩精选在线观看 | 夜夜躁狠狠躁 | 在线91av| 激情五月在线视频 | 国产999视频在线观看 | 国产一区二区高清视频 | 久草在线免费资源 | 999成人网 | 成人在线视频网 | 欧美日韩精品在线视频 | 中文字幕在线观看你懂的 | 深爱婷婷网 | 日韩一级电影网站 | 免费在线观看日韩视频 | 久久xx视频| 操操操日日日 | 成人啪啪18免费游戏链接 | 韩国av一区二区三区在线观看 | 国产美女免费观看 | 国产精品观看视频 | 日韩h在线观看 | 久久综合国产伦精品免费 | 欧美激情另类 | 欧美专区亚洲专区 | 欧美日韩99 | 欧美中文字幕第一页 | 在线日韩中文 | 国产精品久久三 | www免费在线观看 | 久久午夜免费视频 | 丁香婷婷激情网 | av一本久道久久波多野结衣 | www.香蕉视频在线观看 | 丝袜美腿一区 | 色综合久久久久久中文网 | 久久在草 | 久久99精品视频 | 玖玖精品在线 | 久久99精品久久久久久 | 99在线热播 | 久久精品a| 少妇做爰k8经典 | 午夜久久久久久久久 | 免费在线视频一区二区 | 五月婷婷综合网 | 国产在线 一区二区三区 | 日韩av一卡二卡三卡 | 日韩电影一区二区在线观看 | 在线免费成人 | 成片免费观看视频999 | 欧美另类交人妖 | 在线观看的av网站 | 在线观看免费观看在线91 | 色av资源网 | 久久伊人爱 | 免费观看成年人视频 | 91精品久久久久久综合五月天 | 米奇狠狠狠888 | 日韩电影黄色 | 深夜精品福利 | 免费手机黄色网址 | 五月综合 | 人人爽人人做 | 天操夜夜操 | 中文字幕中文中文字幕 | 精品国产美女 | 欧美-第1页-屁屁影院 | 黄污网站在线观看 | 精品99在线| 久久精品伊人 | 天天草天天草 | 亚洲欧美日韩国产精品一区午夜 | 黄色aaa毛片| 久久一线 | 国产精品一区专区欧美日韩 | 黄色大片免费网站 | 天天操天天操天天操天天操天天操天天操 | 欧美91在线 | 久草在线中文888 | 日本精品在线视频 | 久久福利影视 | 黄色亚洲在线 | 麻豆系列在线观看 | 亚洲精品久久久久www | 九九免费在线观看视频 | 久草电影免费在线观看 | 婷婷综合 | 中文字幕精品一区二区精品 | 久久艹久久 | 欧美一进一出抽搐大尺度视频 | 国产福利av| 国产免费观看久久 | 狠狠色噜噜狠狠狠狠 | 久久精品视频18 | 亚洲午夜av | 九九九电影免费看 | 女人18片| 免费看91的网站 | 91视频电影 | 亚洲日韩精品欧美一区二区 | 一区二区三区电影在线播 | 五月激情六月丁香 | 国产麻豆精品一区二区 | 狠狠ri| 超碰av免费| 欧美在线视频精品 | 国产精品美女免费看 | 国产色在线 | 玖玖玖在线| 国产精品久久久久三级 | 精品久久影院 | 亚洲精色 | 国产又粗又猛又爽又黄的视频免费 | 免费在线观看的av网站 | 天天操夜夜曰 | 国产一级免费电影 | 日韩免费二区 | 中文字幕在线视频免费播放 | 手机看片福利 | 丁香视频全集免费观看 | 香蕉色综合 | 免费看的黄色片 | 在线视频免费观看 | av在线收看 | 久久久久久久久久久免费av | 国产精品久久久一区二区三区网站 | 成人三级黄色 | av片无限看 | 欧美日韩视频免费 | 九九视频在线 | 亚洲美女在线国产 | 亚洲日本va中文字幕 | 国产日韩高清在线 | 国产成人一区二区啪在线观看 | 亚洲综合网站在线观看 | www.午夜| 日韩在线观看一区 | 一区二区三区日韩视频在线观看 | www.狠狠操.com| 蜜桃视频在线观看一区 | 激情五月婷婷综合网 | 在线观看视频日韩 | 欧美a视频 | 日韩精品视频在线免费观看 | 亚洲激情国产精品 | 亚洲精品国产精品国自产观看浪潮 | 黄色小说视频网站 | 国产精品久久av | 日韩欧美一区二区在线观看 | 一区二区在线电影 | 亚洲激情在线播放 | 亚洲综合激情 | 亚洲理论视频 | 欧美二区三区91 | 国产黄色高清 | 91人人网 | 天天操夜夜操国产精品 | 国产精品精品国产 | 婷婷丁香自拍 | 黄色亚洲在线 | 五月综合激情网 | 久久精品看| 成人教育av | 婷婷av色综合 | 国产福利91精品一区二区三区 | 玖玖999 | 91人人在线 | 高清国产在线一区 | 成年人在线免费视频观看 | 97精品视频在线 | 天堂视频中文在线 | 91精品999| 欧美日韩久久一区 | 激情五月婷婷综合网 | 在线а√天堂中文官网 | 182午夜在线观看 | 亚洲国产成人在线播放 | 91最新网址在线观看 | 精品久久久久久国产偷窥 | 97在线免费视频 | 中文在线资源 | 久久99精品久久久久蜜臀 | 欧美91片| 国产精品欧美久久久久三级 | 99精品成人 | 国产欧美久久久精品影院 | 国产精品久久久久久久久久免费看 | 日韩乱码中文字幕 | 亚洲精品永久免费视频 | www黄在线| 久久久国产一区二区三区 | 久久久黄色免费网站 | 久久色视频 | 欧美日韩亚洲精品在线 | 久久久免费 | 亚洲视频免费视频 | 在线免费视频你懂的 | 美女一区网站 | 免费观看成人 | 黄色视屏在线免费观看 | 日韩免费av网址 | 国产 在线 高清 精品 | 久久九九影视 | 精品高清视频 | 国产精品岛国久久久久久久久红粉 | 日韩欧美视频一区二区 | 中文视频一区二区 | 国产麻豆剧果冻传媒视频播放量 | 日韩一区二区免费播放 | 久久优 | 在线中文字幕视频 | 日韩欧美在线免费 | 久久av免费 | 成人9ⅰ免费影视网站 | 久草精品视频 | 91中文视频 | 五月婷婷综合久久 | 中文字幕欧美日韩va免费视频 | 在线免费精品视频 | 婷婷网在线 | 国产精品2020 | 欧美日本高清视频 | 五月天婷亚洲天综合网精品偷 | 开心综合网 | 亚洲精品美女在线观看播放 | 国内精品久久久久久久久久 | 最近日本韩国中文字幕 | 国内精品久久久精品电影院 | 日本中文字幕在线免费观看 | 99re国产 | 欧美一二三区在线观看 | 免费看片成年人 | 美女免费电影 | 久久久国产精品一区二区中文 | 中文字幕av影院 | 免费黄色在线播放 | 免费av网站观看 | 在线观看91 | 韩日成人av| 久久九九精品 | 成年人三级网站 | 在线观看的av网站 | 欧美色久 | 国产伦精品一区二区三区免费 | 欧美久久久一区二区三区 | 一区中文字幕电影 | а天堂中文最新一区二区三区 | 久久国内视频 | 欧美成人在线免费 | 91免费观看视频网站 | 亚洲电影久久久 | 一区二区三区在线电影 | 午夜精品一区二区国产 | 午夜体验区 | 精品国产一区二区三区久久久久久 | 免费色视频在线 | 久草在线视频在线观看 | 久久久久久久久久久久国产精品 | 国内精品免费久久影院 | 亚洲国产精品第一区二区 | 99精品在线视频播放 | 夜夜夜夜爽| 国产精品999久久久 久产久精国产品 | 日韩中文字幕免费 | 国产v欧美| 开心激情五月网 | 天天干天天综合 | 国产亚洲精品女人久久久久久 | 久久久资源网 | 久久综合久久久 | 特级西西www44高清大胆图片 | 日韩r级电影在线观看 | 一区二区三区在线免费 | 成人久久18免费网站麻豆 | 中文字幕精品一区二区三区电影 | 18国产精品福利片久久婷 | 亚洲欧洲国产日韩精品 | 激情五月婷婷网 | 久久成人欧美 | a级国产乱理论片在线观看 特级毛片在线观看 | 97视频在线看 | 亚洲少妇久久 | 在线观看日本高清mv视频 | 精品国产乱码久久久久久久 | 日韩欧美精品在线 | 成人一级片免费看 | 四川bbb搡bbb爽爽视频 | 狠狠狠狠狠狠天天爱 | 久久高清片| 在线看片中文字幕 | 精品久久久久一区二区国产 | 日本xxxxav | 色狠狠综合 | 正在播放国产一区二区 | 午夜三级影院 | 日b视频在线观看网址 | 国产经典av | 国产不卡片 | 激情综合网五月 | 国内精品国产三级国产aⅴ久 | 麻豆免费观看视频 | 中文字幕在线观看一区 | 成年人在线免费视频观看 | 美女黄久久| 精品在线观看一区二区 | 免费日韩一级片 | 337p日本欧洲亚洲大胆裸体艺术 | 亚洲综合爱 | 精品亚洲午夜久久久久91 | 亚州av网站大全 | 六月丁香伊人 | 久草久| 九九九九九国产 | 色欧美88888久久久久久影院 | 成人免费观看a | 国产精品久久久久久欧美 | 日韩av电影国产 | 国产成人性色生活片 | 亚洲精品免费视频 | 欧美日韩在线视频一区二区 | 国产精品美女免费看 | 久保带人| 国产大片黄色 | 麻豆视频免费看 | 网站免费黄色 | 久久免费视频1 | 日批视频国产 | 99色免费视频 | 成人精品久久 | 在线视频日韩一区 | 毛片基地黄久久久久久天堂 | 色偷偷网站视频 | 免费99| 天天操综合 | 国产精品video爽爽爽爽 | 亚洲国产精品视频在线观看 | 99精品一区 | a黄在线观看| 国产日韩欧美在线一区 | 日韩专区视频 | 久久免费看| 中文字幕在线看视频国产 | 丁香视频免费观看 | 欧美日韩一二三四区 | 免费精品 | 99re中文字幕 | 国产喷水在线 | 狠狠五月婷婷 | 久久久久久网址 | 在线久草视频 | 国产日韩欧美在线观看视频 | 日本中文字幕在线 | 亚洲第一色 | 天天操综合网站 | 2021久久| 久久99精品久久久久婷婷 | 日韩成人xxxx| 久久久久久免费视频 | 美女精品网站 | 久久国产免费看 | 在线午夜电影神马影院 | 精品在线观看国产 | 91精品国产91热久久久做人人 | 国产精品福利在线播放 | 日本特黄特色aaa大片免费 | 国产免费精彩视频 | 免费福利片2019潦草影视午夜 | 日本三级不卡视频 | 国产破处在线视频 | 久久久久黄 | 日韩和的一区二在线 | 四虎影院在线观看av | 久久电影日韩 | 日韩特级黄色片 | 欧美一级网站 | 国产精品久久久久久久免费大片 | 国产精品18久久久久久首页狼 | 日韩夜夜爽 | 久久久久国产视频 | 91大神精品视频 | 97视频人人 | 久久精品伊人 | 久久国产品 | www.色婷婷.com| 99精品国产一区二区三区麻豆 | 福利视频入口 | 国产日韩精品在线 | 黄色一级大片在线免费看产 | 日韩资源视频 | 国产午夜三级一区二区三 | 国产亚洲成av人片在线观看桃 | www.福利视频| 成年人免费在线观看网站 | 国产成人精品久久亚洲高清不卡 | 97福利社 | 一区二区高清在线 | 国产精品色 | 91精品国产99久久久久 | 久久久精品高清 | 国产精品完整版 | 西西444www | 亚洲免费成人 | 国产99久久久国产精品成人免费 | 亚洲片在线 | 成人av电影在线 | 九九视频在线观看视频6 | 伊人电影在线观看 | 国产免费观看久久 | 亚洲一区二区视频在线播放 | 久草在线这里只有精品 | 美女国产免费 | 亚洲一区av | 日韩免费精品 | 97超碰在线资源 | 开心综合网 | 久久手机视频 | 国产精品成人a免费观看 | 国产不卡网站 | 天天搞天天干 | 伊人干综合| 国产最新视频在线观看 | www.av小说| 国产视频18 | 欧美一区二区三区在线播放 | 日韩中文字幕在线不卡 | 欧美日韩在线播放 | 国产手机av | 有没有在线观看av | 日韩色高清 | 亚洲最新精品 | 国产精品免费久久久久久久久久中文 | 日韩欧美在线中文字幕 | 在线观影网站 | 国产精品久久精品 | 日韩国产精品久久久久久亚洲 | 99精品久久久久久久 | 国产精品久久99综合免费观看尤物 | 久久精品免视看 | 色婷婷色 | 久久视频免费在线 | av福利在线导航 | 中文在线a∨在线 | 区一区二区三区中文字幕 | 一区二区三区四区五区在线视频 | 麻豆免费精品视频 | 精品国产一区二区三区蜜臀 | 国产精品九色 | 成人黄色电影视频 | 国产区精品在线观看 | 国产99精品 | 国产视频高清 | 天天天天天天天天操 | 天天综合视频在线观看 | 人人爽人人香蕉 | 国产精品不卡在线播放 | 国产成人精品一区二区三区福利 | 国产群p视频 | 欧美日韩裸体免费视频 | 在线观看国产91 | 国产手机在线视频 | 欧美乱大交 | 国外成人在线视频网站 | 91免费的视频在线播放 | 91av视频播放 | 69精品在线| 婷婷爱五月天 | 久久午夜视频 | bbbbb女女女女女bbbbb国产 | 成人av在线直播 | 欧美午夜性 | 国产精品成人aaaaa网站 | 69视频国产| 亚洲国产久| 色99导航 | 成人中心免费视频 | 国产97色 | av在线8| 97超碰国产在线 | 亚洲a资源 | 99精品免费久久久久久日本 | 久久69av| 日本爽妇网 | 亚洲国产午夜精品 | 婷婷色5月 | 久久久久一区二区三区四区 | 天天操网址| 国产伦理精品一区二区 | 亚洲国产精品成人综合 | 亚洲桃花综合 | 日本少妇久久久 | 久久99视频免费观看 | 亚洲精品麻豆视频 | www99久久 | 久久国产精品99久久久久久丝袜 | 日本丶国产丶欧美色综合 | 久草在线99 | 亚洲不卡av一区二区三区 | www五月天com| 久久在线播放 | 午夜丁香网 | 操少妇视频 | 婷婷 中文字幕 | 狠狠干夜夜爱 | 日韩欧美专区 | 国产一级片播放 | 99久精品 | 婷婷视频在线播放 | 亚洲人在线视频 | 欧美精品在线一区二区 | 日本不卡123 | 久久精品一 | 日本久久久久久科技有限公司 | 奇米影视777四色米奇影院 | 天天色综合久久 | 亚洲在线网址 | 国产精品久久久久永久免费 | av中文字幕av | www五月| 在线精品视频免费播放 | 久久99精品久久久久久三级 | 色av网站 | 欧美a级免费视频 | 玖玖综合网 | av免费在线播放 | 精品99免费 | 国产福利小视频在线 | se视频网址 | 欧美日韩国产精品一区二区亚洲 | 日本三级久久久 | 韩国av免费在线 | 国产日韩精品一区二区 | 在线黄色免费 | 黄色av一级| 18久久久久久| 欧美一二三专区 | 久久a免费视频 | 国产不卡在线视频 | 国产亚洲成人精品 | 亚洲国产精品第一区二区 | 国产一区欧美一区 | 国产高清av免费在线观看 | 久久99亚洲网美利坚合众国 | 精品91久久久久 | 又黄又刺激又爽的视频 | 色婷婷88av视频一二三区 | 在线综合色 | 欧美日韩视频在线 | 91亚州| 国产色资源 | 一区二区三区播放 | 精品一区二区综合 | 中文字幕免费国产精品 | 亚洲 欧洲 国产 日本 综合 | 视频一区二区三区视频 | 欧美激情综合五月色丁香 | 亚洲国产成人av网 | 日本精品一区二区三区在线播放视频 | 日本中文字幕网 | 久久精品高清 | 中文字幕欧美日韩va免费视频 | 亚洲精品字幕 | av丝袜制服| 国产69久久精品成人看 | 中文字幕免费观看 | 欧美 日韩 性 | 色丁香久久 | 久久久久久久99 | 国产美女视频免费 | 欧美影片 | 成人在线播放av | 日韩电影一区二区三区在线观看 | 久久久综合九色合综国产精品 | 黄色片亚洲| 亚洲综合狠狠干 | 成人黄色小说视频 | 不卡的av电影| 黄色avwww| 国产系列在线观看 | 国产精品69久久久久 | 日韩电影一区二区在线 | 91探花在线视频 | 国内揄拍国内精品 | 91精品视频导航 | 亚洲 综合 国产 精品 | 国产成人在线一区 | 一 级 黄 色 片免费看的 | 国产精品mv| 免费看久久| 超碰在线日韩 | 久久综合中文字幕 | 日韩高清一区在线 | 美国av片在线观看 | 在线99| 亚洲另类在线视频 | 91mv.cool在线观看 | 人人草在线视频 |