最近博主離職找工做了,正好遇上最美離職信。呵呵,小夥伴紛紛藉着這個東風給予鼓勵。在此表示無限次的感謝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 }
運行結果以下圖:排序