青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-80  評論-24  文章-0  trackbacks-0
面試經典問題:
“逆置一個單鏈表”
鏈表結構為:
 
1 typedef struct node
2 {
3       int data;
4       struct node *next;
5 } NODE;

由于題目限制比較少,所以就需要仔細考慮,鏈表是否有環?如果鏈表有小環那么鏈表將不可逆置,因為環的入口節點有兩個前驅節點。所有首先應該判斷鏈表是否有小環,如果沒有小環才能對鏈表進行逆置。而如何判斷鏈表是否有環?一種方法是用一個指針遍歷鏈表,每遍歷一個節點便對節點做標記,如果節點走到NULL,則說明沒有環,如果遇到了已經做過標記的節點,則說明有環,且這個做標記的節點就是入口。但是如果不允許對節點做標記該怎么辦呢?另外一種方法是對每個節點的地址做hash,每次訪問一個節點的時候都查看hash表,如果該節點的地址不在hash表中,則說明該節點未被訪問,直到遇到NULL或者遇到某個節點在hash表中有記錄,則該節點則是環的入口。該算法同樣有很大的弊病,需要大量內存,因為節點的地址是32位的。下面提供第三種方法:采用兩個指針(假設為p1,p2),初始情況下都指向鏈表頭,之后p2每次走2步,p1每次走1步,當p1和p2相交的時候則說明有環,否則當p2走到NULL的時候則說明無環,證明也比較簡單。那么如何找到環的入口點呢?這里提供一種方法:當確定有環后,p2在相交處,p1重新指向鏈表開頭,然后每次兩個指針都各走一步,這樣兩個指針再次相遇的時候便是環的入口處。證明如下:
假設從鏈表頭到環的入口長度為l,環的周長為r,p1和p2相遇的點距離環入口為x
則我們有以下結論:
1、第一次相交的時候p1還沒有走完整條鏈表,而p2則在鏈表的環內轉了n圈
2、第一次相交的時候p2走的距離是p1的兩倍,因為p2每次走兩步而p1每次走一步
這樣我們就得到如下公式:
2(x + l) = l + x + nr
則可以得到l = nr - x
這樣我們將p1重新放到鏈表頭開始走,那么當p1節點走了l距離的時候,可以知道p2也走了l距離,而l = nr - x,所以p2走了nr - x,而p2從相交點開始走的,該點距離環入口處為x,這樣可以知道當p2走了nr - x步后正好就到了環的入口,而p1此時也正在環的入口,可以知道p1和p2正好相遇,證畢。

下面一段代碼是用來判斷鏈表是否有環的,包括大環和小環:

 1 node *list_isloop(node *head) {
 2     if (head == NULL) return head;
 3     node *p1 = head, *p2 = head;
 4     do {
 5         p2 = p2->next;
 6         if (p2 == NULL || p2 == head) return p2;
 7         p2 = p2->next;
 8         if (p2 == NULL || p2 == head) return p2;
 9         p1 = p1->next;
10     } while (p1 != p2);
11     p1 = head;
12     while (p1 != p2) { p1 = p1->next; p2 = p2->next; }
13     return p2;
14 }

其實對于單鏈表的操作,絕大部分都需要先判斷鏈表是否為空,然后判斷鏈表是否呦環,有大環和有小環在有寫問題的處理方式未必一樣,比如對于鏈表逆置,鏈表為空、或者鏈表有大環,鏈表都可以正常被逆置,而如果是有小環的鏈表,則鏈表不可被逆置。
下面看鏈表逆置的代碼,其中調用了上面判斷鏈表是否有環的函數:

 1 node *list_reverse(node *head) {
 2     if (head == NULL || head->next == NULL) return head;
 3     node *entry = list_isloop(head);
 4     if (entry != NULL && entry != head) return NULL;
 5     node *p1 = head, *p2 = p1->next, *p3 = p2->next;
 6     p1->next = NULL;
 7     while (p3 && p3 != head) {
 8         p2->next = p1; 
 9         p1 = p2;
10         p2 = p3;
11         p3 = p3->next;
12     }
13     p2->next = p1;
14     return p2;
15 }

下面一段代碼是用來對單鏈表測長的,也許要對單鏈表判斷是否有環:

 1 int list_len(node *head) {
 2     int len = 0;
 3     node *p = head, *entry = NULL;
 4     if (head == NULL) return 0;
 5     entry = list_isloop(head);
 6     while (p != entry) { ++len; p = p->next; }
 7     if (entry != NULL)
 8         do { ++len; p = p->next; } while (p != entry);
 9     return len;
10 }

而下面一段代碼是用來判斷兩個單鏈表是否相交的,該問題有點復雜:
首先,如果其中任意一條鏈表為空,則不可能相交
其次,如果兩個鏈表都沒有環,則判斷鏈表的尾元素是否相同
再次,如果兩個鏈表一個呦環,一個無環,則不可能相交
最后,如果兩個鏈表均有環,則從其中一個入口處開始走一圈,如果中間和另一環的入口相遇則說明兩鏈表相交

 1 int list_intersecting(node *head1, node *head2) {
 2     if (head1 == NULL || head2 == NULL) return 0;
 3     node *entry1 = list_isloop(head1);
 4     node *entry2 = list_isloop(head2);
 5     //兩個鏈表都沒有環
 6     if (entry1 == NULL && entry2 == NULL) {
 7         while (head1->next != NULL) head1 = head1->next;
 8         while (head2->next != NULL) head2 = head2->next;
 9         if (head1 == head2) return 1;
10         return 0;
11     }
12     //兩個鏈表都有環
13     else if (entry1 != NULL && entry2 != NULL) {
14         node *tmp = entry1;
15         while (tmp->next != entry1) {
16             if (tmp == entry2) return 1;
17             tmp = tmp->next;
18         }
19         if (tmp == entry2) return 1;
20     }
21     //一個有環一個無環
22     return 0;
23 }

下面是合并兩個有序鏈表,該問題也需要考慮全面,既然有序,則不需要考慮是否有環,但是兩個鏈表是否都是遞增或者遞減則需要考慮,我們在此不判斷兩個鏈表一個一個遞增一個遞減的情況。下面代碼第三個參數代表鏈表單調性,flag = 0代表遞增,flag != 0代表遞減:

 1 node *list_merge(node *head1, node *head2, int flag) {
 2     if (head1 == NULL) return head2;
 3     if (head2 == NULL) return head1;
 4     flag = !!flag;
 5     node *head = NULL;
 6     if (flag == 0) {
 7         if (head1->data < head2->data) {
 8             head = head1;
 9             head->next = list_merge(head1->next, head2, flag);
10         }
11         else {
12             head = head2;
13             head->next = list_merge(head1, head2->next, flag);
14         }
15     }
16     else {
17         if (head1->data > head2->data) {
18             head = head1;
19             head->next = list_merge(head1->next, head2, flag);
20         }
21         else {
22             head = head2;
23             head->next = list_merge(head1, head2->next, flag);
24         }
25         return head;
26     }
27 }

對于將鏈表排序也有一個非常巧妙的地方,我們知道普通數組排序一般采用快排、堆排或者歸并排序,而在鏈表上卻不那么容易,因為鏈表不能直接用索引來尋址,而是采用指針地址索引,所以快排、堆排都失去了優勢,但是歸并排序卻如魚得水,而且在數組歸并排序當中被詬病的空間復雜度O(n)在鏈表排序當中也降為O(1)。這里面還用到了一個小技巧,就是如何找到鏈表的中間元素,這里采用兩個指針一快一慢的方法:

 1 node *list_sort(node *head, int flag) {
 2     if (head == NULL || head->next == NULL) return head;
 3     flag = !!flag;
 4     node *p1 = head, *p2 = head;
 5     while (p2 != NULL) {
 6         if ((p2 = p2->next) == NULL) break;
 7         if ((p2 = p2->next) == NULL) break;
 8         p1 = p1->next;
 9     }
10     p2 = p1->next;
11     p1->next = NULL;
12     p1 = list_sort(head, flag);
13     p2 = list_sort(p2, flag);
14     return list_merge(p1, p2, flag);
15 }

找到無環鏈表倒數第k個節點,該問題比較簡單,只需要先設一個指針p2預先走k步,然后再讓p2每次走一步,同時在鏈表開頭也有一指針p1每次走一步,這樣,當p2走到尾部的時候p1則恰好是倒數第k個節點:

 1 node *list_ktailed(node *head, int k) {
 2     if (k < 0) return NULL;
 3     int i = 0;
 4     node *p1 = head, *p2 = head;
 5     for (; i < k; ++i) {
 6         if (p2 == NULL) return NULL;
 7         p2 = p2->next;
 8     }
 9     while (p2 != NULL) { p2 = p2->next; p1 = p1->next; }
10     return p1;
11 }

關于鏈表問題暫時寫到此。
posted on 2012-02-10 15:43 myjfm 閱讀(442) 評論(0)  編輯 收藏 引用 所屬分類: 筆試+面試總結
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲一区欧美一区| 99re成人精品视频| 欧美在线看片| 欧美一区二区日韩| 国产一区日韩一区| 美女主播一区| 欧美va天堂| 亚洲视频在线观看三级| 一区二区国产精品| 国产亚洲女人久久久久毛片| 久久久精彩视频| 美女日韩欧美| 亚洲视频在线观看视频| 亚洲一区在线直播| 在线观看不卡av| 日韩亚洲视频在线| 国产欧美一区二区三区久久| 欧美1区2区| 欧美午夜精品久久久久久人妖| 欧美在线一级va免费观看| 久久久免费精品视频| 亚洲欧洲另类| 亚洲欧美视频在线观看视频| 亚洲国产天堂久久综合网| 亚洲精品一二三| 国产主播精品| 日韩午夜在线视频| 一区二区亚洲精品国产| 日韩特黄影片| 亚洲高清免费视频| 亚洲专区一二三| 日韩亚洲国产精品| 久久国产精品99久久久久久老狼| 亚洲免费观看在线观看| 亚洲欧美日韩在线观看a三区| 亚洲欧洲精品一区二区精品久久久| 亚洲午夜精品网| 亚洲国产裸拍裸体视频在线观看乱了| 亚洲视频欧洲视频| 亚洲精品免费观看| 久久精品av麻豆的观看方式 | 欧美亚洲尤物久久| 99riav国产精品| 久久综合狠狠| 久久精品夜夜夜夜久久| 欧美日韩一区二区三区在线观看免 | 欧美日韩国产精品| 欧美xx69| 樱桃视频在线观看一区| 亚洲欧美日本日韩| 亚洲一区二区三区涩| 欧美高清在线观看| 免费试看一区| 在线成人性视频| 久久久久久91香蕉国产| 久久精品国产999大香线蕉| 欧美亚州一区二区三区| 亚洲乱码视频| 99国产一区二区三精品乱码| 欧美a级在线| 欧美成人中文字幕| 亚洲二区视频| 蜜臀av在线播放一区二区三区| 久久久999精品免费| 国产日韩免费| 久久久www成人免费无遮挡大片| 欧美在线三区| 国产一区再线| 久久综合九色综合网站| 欧美福利一区二区| 最新中文字幕亚洲| 欧美激情国产日韩精品一区18| 欧美激情一区二区三区| 亚洲成人在线| 欧美日本三区| 中文日韩在线| 久久久久久久久岛国免费| 国产在线视频欧美| 久久中文在线| 亚洲精品你懂的| 中文一区在线| 国产欧美精品日韩| 午夜欧美大片免费观看| 久久一区视频| 99国产精品一区| 国产精品xxxav免费视频| 亚洲免费影视| 欧美成人一区在线| 99热免费精品在线观看| 国产精品毛片va一区二区三区 | 日韩视频不卡| 欧美一区二区三区四区在线观看| 国产丝袜一区二区三区| 久久综合网hezyo| 亚洲美女91| 久久精视频免费在线久久完整在线看| 一区二区在线视频| 欧美深夜福利| 欧美一区激情视频在线观看| 亚洲国产日本| 欧美日韩国产精品| 永久91嫩草亚洲精品人人| 亚洲成色999久久网站| 亚洲精品在线二区| 久久精品成人一区二区三区蜜臀| 狠狠色狠色综合曰曰| 欧美精品久久一区| 久久成人人人人精品欧| 亚洲精品日本| 麻豆成人av| 欧美一区二区三区四区在线观看| 在线观看亚洲视频啊啊啊啊| 国产精品99一区二区| 久久久久久久久伊人| 这里是久久伊人| 亚洲国内自拍| 噜噜噜久久亚洲精品国产品小说| 在线视频精品一区| 在线播放视频一区| 国产精品制服诱惑| 欧美日韩综合视频| 欧美激情中文字幕一区二区| 欧美在线视频二区| 亚洲一区二区三区精品在线观看| 亚洲黄色影院| 欧美高清一区| 女女同性女同一区二区三区91| 亚洲欧洲99久久| 一区二区三区四区国产精品| 亚洲精品国产系列| 精品福利电影| 黑人一区二区三区四区五区| 国产精品主播| 国产精品自拍一区| 国产精品免费一区豆花| 国产精品久久久久久亚洲毛片 | 亚洲免费在线| 一本久久a久久精品亚洲| 欧美成人一区二区三区在线观看| 久久免费视频网站| 久久久蜜臀国产一区二区| 校园春色国产精品| 欧美一区二区啪啪| 久久精品99无色码中文字幕| 欧美一级二区| 久久精品国产久精国产爱| 欧美一区二区三区婷婷月色| 午夜精品久久久久久久久久久久久| 国产精品99久久久久久白浆小说 | 亚洲欧洲另类| 亚洲蜜桃精久久久久久久| 亚洲美女在线一区| 在线亚洲观看| 欧美一区二区三区的| 欧美一区视频在线| 久久在线精品| 亚洲国产合集| 一本色道久久综合精品竹菊| 在线视频亚洲欧美| 亚洲在线成人精品| 久久久亚洲一区| 欧美激情偷拍| 国产欧美日韩三级| 亚洲国产精品成人精品 | 欧美午夜大胆人体| 国产精品免费福利| 激情综合中文娱乐网| 亚洲国产精品尤物yw在线观看 | 影音先锋日韩资源| 亚洲欧洲中文日韩久久av乱码| 99视频精品免费观看| 香蕉久久国产| 欧美a级一区| 一区二区三区|亚洲午夜| 午夜精品在线看| 欧美国产激情| 国产视频在线观看一区| 亚洲精品乱码久久久久| 香蕉乱码成人久久天堂爱免费 | 亚洲精品中文字幕在线| 亚洲一区二区网站| 鲁大师成人一区二区三区| 国产精品jvid在线观看蜜臀 | 欧美三级欧美一级| 国产一区二区久久久| 99在线热播精品免费99热| 久久久久久久91| 99热在这里有精品免费| 久久久亚洲人| 国产精品羞羞答答| 亚洲乱码国产乱码精品精可以看| 性做久久久久久久免费看| 欧美激情中文字幕乱码免费| 亚洲欧美日韩综合一区| 欧美久久久久久久久| 在线观看视频欧美| 午夜综合激情| 99国产一区| 欧美激情精品久久久久久蜜臀| 国产日韩欧美三区|