有序鏈表(或無序鏈表)的合併

最近博主離職找工做了,正好遇上最美離職信。呵呵,小夥伴紛紛藉着這個東風給予鼓勵。在此表示無限次的感謝ing。數組

其實離職,對於非計算機科班出身,過了30歲,有了家庭,還有了小孩,還要還房貨。壓力是可想而知的。無論壓力多大,是否是能堅持到黎明,看見曙光;仍是要走出去試一試。看一看。如今有一部分公司,對技術過於不承認。老闆和領導常常說,你不要跟我講技術,我只關心這個軟件或項目有沒有亮點,能不能掙錢。只有你有亮點,能掙錢,技術不是問題。函數

唉,這種想法試問一下,造時速5000千米的動車能掙錢,還有亮點,國家還有政策支持,那也得有這個技術實力才行對吧。如今流行大數據,雲時代,假設給咱們1000萬條數據,咱們如何加工成客戶須要的,若是沒有這個實力,仍是先修煉內功。把技術作好吧。大數據

世界那麼大,我想找一個稍微看得起技術的環境。扯遠了,回到正題了。spa

上次在寫鏈表逆序的時候,收了一個園友的回覆說,遞歸要比while循環看着直觀。本人感謝這位園友的回覆,其實我的以爲遞歸代碼簡單,邏輯性較好,代碼跟蹤與調試要求較高。指針

但在生產過程當中,結合必定的業務邏輯進行處理時,給維護增長了一些複雜度。寫個while死循環倒也是簡單明瞭。呵呵,關因而不是用遞歸,什麼時候用遞歸這是一個無解的問題。望你們勿噴。調試

上代碼了:qt,c語言。code

代碼裏面包含了遞歸和非遞歸的對比。以及鏈表的排序,插入、隨機key值的生成等。本代碼中,遞歸合併節點的關鍵是要記錄前一個節點,同時再比較兩個鏈表的頭節點,節點pPrev的next指針,指向key值小的節點。同時將key值小的鏈表頭向後移動一個位置,而後再進行下一次的遞歸合併。直到其中的一個鏈表爲空。blog

  1 #include <QCoreApplication>
  2 #include <time.h>
  3 
  4 const int MAX_CHAR = 30;
  5 const int MAX_VALUE = 100;
  6 //類型
  7 enum lsType{
  8     Composite,
  9     Prime
 10 };
 11 
 12 //節點
 13 typedef struct Node{
 14     int key;
 15     char value[MAX_CHAR];
 16     struct Node *next;
 17 }NodeList;
 18 
 19 //生成鏈表
 20 Node* generateList(lsType type, int num);
 21 //生成鏈表(按遞歸方式)
 22 Node* generateListByRecursion(lsType type, int num);
 23 
 24 //鏈表的合併
 25 Node* mergeList(Node *list1, Node* list2);
 26 //鏈表的遞歸合併
 27 Node* recursionMergeList(Node* pPrev, NodeList *list1, NodeList* list2);
 28 //打印鏈表
 29 void printList(Node *pNode);
 30 //判斷一個數是否爲質數
 31 bool isPrime(unsigned long n);
 32 //得到隨機質數
 33 int getRandPrime(int Max);
 34 //釋放鏈表
 35 void freeList(Node *pList);
 36 //鏈表的插入(while循環)
 37 Node* InsertNode(NodeList* list, Node *pNode);
 38 //鏈表的插入(遞納入口)
 39 Node* InsertNodeRecMain(NodeList* list, Node *pNode);
 40 //鏈表的插入(遞歸體)
 41 Node* InsertNodeByRecursion(Node* list, Node* pInsert, Node* pPrev);
 42 
 43 
 44 int main(int argc, char *argv[])
 45 {
 46     QCoreApplication a(argc, argv);
 47     //隨機數的種子值
 48     srand((unsigned)time(NULL));
 49     //普通生成方式
 50     //Node* pList1 = generateList(Composite, 10);
 51     //Node* pList2 = generateList(Prime, 10);
 52     printf("節點列表1(插入過程進行排序)\r\n");
 53     //遞歸生成方式
 54     Node* pList1 = generateListByRecursion(Composite, 5);
 55     Node* pList2 = generateListByRecursion(Prime, 5);
 56     printList(pList1);    
 57     printf("節點列表2(插入過程進行排序)\r\n");
 58     printList(pList2);
 59     Node* pList3 = mergeList(pList1, pList2);
 60     printf("合併後的節點列表爲:\r\n");
 61     printList(pList3);
 62     return a.exec();
 63 }
 64 
 65 /**
 66   * @函數名:generateList
 67   * @參數:type:根據不一樣的狀態碼,生成對應的鏈表
 68   *       num:鏈表的個數
 69   * @返回值:生成的鏈表
 70   * @用途: 生成鏈表
 71   * @做者:yangfy
 72   */
 73 Node* generateList(lsType type, int num)
 74 {
 75     int nrand;
 76     //下一節點
 77     Node* pHead = NULL, *pPrev = NULL;
 78     if(type == Composite){
 79         //生成頭節點
 80         pHead = (Node*)malloc(sizeof(struct Node));
 81         nrand = rand() % MAX_VALUE + 2;
 82         pHead->key = nrand % 2 ? nrand - 1 : nrand;
 83         snprintf(pHead->value, MAX_CHAR - 1, "值爲:%c元素", 65);
 84         pHead->next = NULL;
 85         pPrev = pHead;
 86         //生成數組
 87         for(int i = 1; i < num; i++){
 88             Node* pNode = (Node*)malloc(sizeof(struct Node));
 89             pNode->next = NULL;
 90             //100之內的合數
 91             nrand = rand() % MAX_VALUE + 2;
 92             pNode->key = nrand % 2 ? nrand - 1 : nrand;            
 93             snprintf(pNode->value, MAX_CHAR - 1, "值爲:%c元素", 65 + i);
 94             pHead = InsertNode(pHead, pNode);
 95             //next節點的指定
 96             pPrev->next = pNode;
 97             pPrev = pNode;
 98         }
 99         return pHead;
100 
101     } else if(type == Prime){
102         //生成頭節點
103         pHead = (Node*)malloc(sizeof(struct Node));
104         pHead->key = getRandPrime(MAX_VALUE);
105         pHead->next = NULL;
106         snprintf(pHead->value, MAX_CHAR - 1, "值爲:%c元素", 65);
107         pPrev = pHead;
108         //生成數組
109         for(int i =1; i < num; i++){
110             Node* pNode = (Node*)malloc(sizeof(struct Node));
111             pNode->next = NULL;
112             //得到質數
113             pNode->key = getRandPrime(MAX_VALUE);
114             snprintf(pNode->value, MAX_CHAR - 1, "值爲:%c元素", 65 + i);
115             pHead = InsertNode(pHead, pNode);
116             //next節點的指定
117             pPrev->next = pNode;
118             pPrev = pNode;
119         }
120         return pHead;
121     }
122     return NULL;
123 }
124 
125 /**
126   * @函數名:generateListByRecursion
127   * @參數:type 生成類型(質數、合數之分)
128   *       num 節點數量
129   * @返回值:生成的鏈表
130   * @用途:生成指定數量、指定用途的鏈表
131   * @做者:yangfy
132   */
133 Node* generateListByRecursion(lsType type, int num)
134 {
135     int nrand;
136     //下一節點
137     Node* pHead = NULL;
138     if(type == Composite){
139         //生成頭節點
140         pHead = (Node*)malloc(sizeof(struct Node));
141         nrand = rand() % MAX_VALUE + 2;
142         pHead->key = nrand % 2 ? nrand - 1 : nrand;
143         snprintf(pHead->value, MAX_CHAR - 1, "值爲:%c1元素", 65);
144         pHead->next = NULL;
145         //生成數組
146         for(int i = 1; i < num; i++){
147             Node* pNode = (Node*)malloc(sizeof(struct Node));
148             pNode->next = NULL;
149             //100之內的合數
150             nrand = rand() % MAX_VALUE + 2;
151             pNode->key = nrand % 2 ? nrand - 1 : nrand;
152             snprintf(pNode->value, MAX_CHAR - 1, "值爲:%c1元素", 65 + i);
153             pHead = InsertNodeRecMain(pHead, pNode);
154         }
155         return pHead;
156 
157     } else if(type == Prime){
158         //生成頭節點
159         pHead = (Node*)malloc(sizeof(struct Node));
160         pHead->key = getRandPrime(MAX_VALUE);
161         snprintf(pHead->value, MAX_CHAR - 1, "值爲:%c2元素", 65);
162         pHead->next = NULL;
163         //生成數組
164         for(int i =1; i < num; i++){
165             Node* pNode = (Node*)malloc(sizeof(struct Node));
166             pNode->next = NULL;
167             //得到質數
168             pNode->key = getRandPrime(MAX_VALUE);
169             snprintf(pNode->value, MAX_CHAR - 1, "值爲:%c2元素", 65 + i);
170             pHead = InsertNodeRecMain(pHead, pNode);
171         }
172         return pHead;
173     }
174     return NULL;
175 }
176 
177 /**
178   * @函數名:isPrime
179   * @參數:n:要判斷的數
180   * @返回值:是否爲質數
181   * @用途:判斷一個數是否爲質數
182   * @做者:yangfy
183   */
184 bool isPrime(unsigned long n)
185 {
186     if (n <= 3){
187         return n > 1;
188     } else if (n % 2 == 0 || n % 3 == 0) {
189         return false;
190     } else {
191         for (unsigned short i = 5; i * i <= n; i += 6) {
192             if (n % i == 0 || n % (i + 2) == 0) {
193                 return false;
194             }
195         }
196         return true;
197     }
198 }
199 /**
200   * @函數名:getRandPrime
201   * @參數:nMax:隨機的最大數
202   * @返回值:隨機生成的質數
203   * @用途:隨機生成MAX之內的質數
204   * @做者:yangfy
205   */
206 int getRandPrime(int Max)
207 {
208     int nRand;
209     while (1) {
210         //獲取100之內的質數
211         nRand = rand() % Max + 1;
212         if (isPrime(nRand))
213             return nRand;
214     }
215 }
216 
217 /**
218   * @函數名:InsertNode
219   * @參數:list要插入節點的鏈表
220   *       pNode要插入的節點
221   * @返回值:插入完成後的鏈表
222   * @用途:將指定節點插入到鏈表中
223   * @做者:yangfy
224   */
225 Node* InsertNode(NodeList* list, Node *pNode)
226 {
227     Node* pHead = list;
228     //異常判斷
229     if(list == NULL)
230         return NULL;
231     if(pNode == NULL)
232         return pHead;
233     //頭節點處理
234     if(pHead->key > pNode->key){
235         pNode->next = pHead;
236         return pNode;
237     }
238     //節點插入
239     while (true) {
240         if(pHead == NULL){
241             break;
242         }
243         //尾節點
244         if(pHead->next == NULL){
245             pHead->next = pNode;
246             break;
247         }
248         else if(pHead->next->key > pNode->key){
249            pNode->next = pHead->next;
250            pHead->next = pNode;
251            break;
252         }
253         pHead = pHead->next;
254     }
255     return list;
256 }
257 
258 /**
259   * @函數名:InsertNodeRecMain
260   * @參數:list要插入節點的鏈表
261   *       pNode要插入的節點
262   * @返回值:插入完成後的鏈表
263   * @用途:經過遞歸方式將節點插入鏈表
264   *       將遞歸中不通用的部分分離出來,遞歸鏈表的通用部分
265   * @做者:yangfy
266   */
267 Node* InsertNodeRecMain(NodeList *list, Node *pNode)
268 {
269     //節點判斷
270     if(list == NULL) return pNode;
271     if(pNode == NULL) return list;
272     if(list->key > pNode->key){
273         pNode->next = list;
274         return pNode;
275     }
276     return InsertNodeByRecursion(list, pNode, NULL);
277 }
278 /**
279   * @函數名:InsertNodeByRecursion
280   * @參數:list要插入節點的鏈表
281   *       pInsert:要插入的節點
282   *       pPrev:插入位置的前一個節點(要把本節點next指向爲插入節點)
283   * @返回值:插入成功的鏈表
284   * @用途:遞歸查找能夠插入的節點位置,插入節點
285   * @做者:yangfy
286   */
287 Node* InsertNodeByRecursion(Node *list, Node *pInsert, Node *pPrev)
288 {
289     Node* pResult = list;
290     if(list != NULL){
291         if(list->key > pInsert->key){
292             pInsert->next = list;
293             pPrev->next = pInsert;
294         }
295         else{
296             InsertNodeByRecursion(list->next, pInsert, list);
297         }
298     } else{
299         if(pPrev != NULL){
300             pPrev->next = pInsert;
301         }
302     }
303     return pResult;
304 }
305 /**
306   * @函數名:mergeList
307   * @參數:list1:要合併的鏈表1
308   *       list2:要合併的鏈表2
309   * @返回值:合併成功的鏈表
310   * @用途:肯定鏈表合併的開始位置(合理),是否是能夠理解爲肯定始基
311   *       調用遞歸函數合併節點
312   * @做者:yangfy
313   */
314 Node* mergeList(Node *list1, Node* list2){
315     Node* pPrev = NULL;
316     if(list1->key < list2->key){
317         pPrev = list1;
318         list1 = list1->next;
319     }else{
320         pPrev = list2;
321         list2 = list2->next;
322     }
323     return recursionMergeList(pPrev, list1, list2);
324 }
325 /**
326   * @函數名:recursionMergeList
327   * @參數:pPrev:要合併的前一個節點
328   *       list1:鏈表1
329   *       list2:鏈表2
330   * @返回值:前一個節點
331   * @用途:遞歸調用進行鏈表的合併
332   * @做者:yangfy
333   */
334 Node* recursionMergeList(Node *pPrev, NodeList *list1, NodeList *list2)
335 {
336     if(list1 == NULL){
337         pPrev->next = list2;
338         return pPrev;
339     }
340     if(list2 == NULL){
341         pPrev->next = list1;
342         return pPrev;
343     }
344     if(list1->key < list2->key){
345         pPrev->next = list1;
346         list1 = list1->next;
347         recursionMergeList(pPrev->next, list1, list2);
348     } else {
349         pPrev->next = list2;
350         list2 = list2->next;
351         recursionMergeList(pPrev->next, list1, list2);
352     }
353     return pPrev;
354 }
355 /**
356   * @函數名:printList
357   * @參數:pNode:要打印的鏈表頭
358   * @返回值:無
359   * @用途:打印鏈表
360   * @做者:yangfy
361   */
362 void printList(Node *pNode)
363 {
364     while (pNode != NULL) {
365         if (pNode->next != NULL)
366             printf("當前節點key爲:%d, -->%s; (下一節點key爲%d, -->%s)\r\n", pNode->key, pNode->value, pNode->next->key, pNode->next->value);
367         else
368             printf("當前節點key爲:%d, -->%s; 下一節點爲NULL\r\n", pNode->key, pNode->value);
369         pNode = pNode->next;
370     }
371 }
372 /**
373   * @函數名:freeList
374   * @參數:pList:要釋放的鏈表
375   * @返回值:無
376   * @用途:釋放鏈表
377   * @做者:yangfy
378   */
379 void freeList(Node *pList)
380 {
381     Node *pNode = NULL;
382     while (pList != NULL) {
383         pNode = pList;
384         pList = pList->next;
385         free(pNode);
386         pNode = NULL;
387     }
388 }

運行結果以下圖:排序

相關文章
相關標籤/搜索