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

隨筆-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 閱讀(439) 評論(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>
            一二三区精品| 国产精品久久久久天堂| 老司机午夜免费精品视频 | 欧美gay视频| 欧美日韩一二三区| 老司机凹凸av亚洲导航| 午夜精彩国产免费不卡不顿大片| 欧美日本三级| 亚洲一区精彩视频| 久久青青草综合| 亚洲国产精品国自产拍av秋霞| 久久综合久色欧美综合狠狠| 国产视频丨精品|在线观看| 欧美电影在线播放| 亚洲天堂av电影| 国内精品久久久久久久影视蜜臀| 美玉足脚交一区二区三区图片| 99国产精品久久久久久久成人热| 久久久蜜桃精品| 欧美成人精精品一区二区频| 香蕉久久精品日日躁夜夜躁| 亚洲国内高清视频| 国产精品v欧美精品v日韩| 久久久久国产精品www| 亚洲日本aⅴ片在线观看香蕉| 午夜伦欧美伦电影理论片| 久热精品在线| 91久久国产综合久久91精品网站| 久久久99国产精品免费| 亚洲精品影视| 亚洲国产精品久久久久秋霞不卡| 日韩视频三区| 久久另类ts人妖一区二区| 欧美一区三区三区高中清蜜桃| 国产精品videosex极品| 国产午夜精品麻豆| 亚洲精品一区二区三区av| 国产一区二区欧美| 国产一区二区精品久久91| 在线成人激情黄色| 国产精品女主播| 亚洲国产精品视频| 久久国产精品亚洲77777| 亚洲欧美日韩在线播放| 一区二区三区高清| 一本色道久久综合亚洲精品高清 | 国产亚洲制服色| 亚洲精品午夜精品| 久久九九电影| 一区二区三区四区五区精品| 久久久在线视频| 国产日韩欧美一区二区三区在线观看| 一本色道久久综合亚洲精品按摩| 欧美成人在线影院| 久久成人国产精品| 久久综合国产精品| 国产精品视频精品| 国产欧美视频在线观看| 国产精品视频99| 一区二区三区日韩精品| 欧美日韩视频在线观看一区二区三区| 亚洲看片免费| 欧美一级在线视频| 亚洲性线免费观看视频成熟| 亚洲深夜福利| 亚洲国产精品va在看黑人| 亚洲黄色一区二区三区| 久久免费的精品国产v∧| 欧美好吊妞视频| 欧美日韩精品一区二区天天拍小说| 欧美精品电影| 国产精品久久毛片a| 一本久道久久综合婷婷鲸鱼| 欧美电影免费观看| 欧美大片专区| 国产精品一区二区视频 | 可以免费看不卡的av网站| 国内精品99| 欧美成在线视频| 欧美精品一区二区三区很污很色的| 亚洲精选一区二区| 99精品国产在热久久下载| 国产精品成人在线观看| 黄色成人av网| 亚洲午夜一区二区| 亚洲影视九九影院在线观看| 国产欧美 在线欧美| 久久综合福利| 亚洲特级毛片| 久久一区中文字幕| 亚洲人成绝费网站色www| 亚洲自拍高清| 欧美成在线视频| 欧美理论视频| 久久精品国产精品 | 欧美专区日韩专区| 欧美黄色成人网| 亚洲在线成人精品| 在线电影一区| 99re热精品| 欧美一区二区三区另类| 亚洲二区三区四区| 一区二区三区视频在线观看| 国产亚洲精品资源在线26u| 欧美国产精品久久| 国产伦精品一区二区三区高清版| 免费观看一区| 久久精品30| 一区二区三区蜜桃网| 小嫩嫩精品导航| 亚洲美女视频在线观看| 亚洲综合国产| 国产精品ⅴa在线观看h| 久久亚洲午夜电影| 国产精品久久久久久久久久免费 | 99国内精品| 国内自拍一区| 亚洲一二三四区| 亚洲乱码国产乱码精品精98午夜| 亚洲欧美一区二区原创| 久久色在线播放| 香蕉av福利精品导航| 美日韩免费视频| 久久一二三四| 国产精品免费一区二区三区在线观看| 欧美99在线视频观看| 国产日韩欧美黄色| 亚洲网站在线播放| 亚洲一区二区av电影| 免费毛片一区二区三区久久久| 亚洲一二三级电影| 欧美成黄导航| 亚洲国产mv| 欧美日本视频在线| 亚洲欧洲精品天堂一级| 亚洲二区精品| 欧美sm视频| 亚洲第一主播视频| 亚洲国产欧美一区二区三区久久 | 欧美在线中文字幕| 国产精品一区二区三区四区| 一本色道88久久加勒比精品| 艳妇臀荡乳欲伦亚洲一区| 欧美激情亚洲一区| 性久久久久久久久久久久| 一本一本a久久| 中国成人亚色综合网站| 欧美日本精品| 亚洲精品自在久久| 国产精品视频精品视频| 亚洲午夜伦理| 欧美一区免费视频| 国内精品伊人久久久久av一坑| 午夜精品国产更新| 麻豆国产精品777777在线| 在线观看视频欧美| 欧美激情女人20p| 日韩写真在线| 欧美一级视频一区二区| 韩国成人理伦片免费播放| 久久久久久欧美| 亚洲高清激情| 亚洲欧美日韩在线| 亚洲第一页在线| 在线亚洲免费视频| 欧美在线国产| 在线观看日韩精品| 欧美日韩免费区域视频在线观看| 一区二区精品在线观看| 久久国产手机看片| 亚洲精品美女在线| 国产精品免费看| 模特精品裸拍一区| 在线一区视频| 欧美不卡视频一区| 亚洲午夜伦理| 欧美黄色影院| 久久综合久久久| 亚洲人成毛片在线播放| 国产精品久久久久久福利一牛影视| 欧美怡红院视频| 日韩一级视频免费观看在线| 久久精品国产第一区二区三区| 亚洲精品美女在线观看播放| 国产精品麻豆成人av电影艾秋| 久久欧美中文字幕| 亚洲一区欧美一区| 亚洲国产日韩一区| 麻豆av一区二区三区| 亚洲欧美偷拍卡通变态| 91久久久精品| 国内在线观看一区二区三区| 欧美午夜三级| 欧美激情第4页| 久久精品国产免费看久久精品| 一区二区三区不卡视频在线观看| 欧美 亚欧 日韩视频在线| 欧美一区二区三区男人的天堂| 亚洲美女免费精品视频在线观看| 尤物yw午夜国产精品视频明星|