遞歸實現單鏈表的各種基本操作
阿新 • • 發佈:2018-04-04
name node erro 入棧 get find 比較 spa 遞歸循環
1 #include<iostream> 2 using namespace std; 3 4 #define OK 1 5 #define ERROR 0 6 typedef int Status; 7 8 typedef struct LNode 9 { 10 int data; //結點的數據域 11 struct LNode *next; //結點的指針域 12 }LNode, *LinkList; //LinkList為指向結構體LNode的指針類型 13 14 void create_List(LinkList &L, intn){ //法1:遞歸初始化創建n個節點 15 if (n == 0)return;//創建n個節點 16 else{ //此時傳進來的是第一個節點的指針 17 L = new LNode; //指針指向新生成的節點 18 cin >> L->data; //輸入數據,將其壓棧 19 L->next = NULL; //尾插法,先將下一個指針域賦為NULL 20 create_List(L->next, n - 1); //遞歸創建n個節點 21 } 22 } 23 24Status Creat_LinkList(LinkList &L){ //法2:創建鏈表,當輸入數字為-1時,令當前指針為空 25 int num; 26 cout << "請每行輸入一個數據元素並按回車(直到-1退出):"; 27 cin >> num;//輸入數據 28 if (num == -1){ L = NULL; return OK; } //結束 29 else{ 30 L = new LNode; //申請新的節點,指針指向結構體 31 L->data = num; //先將數據放到數據域 32 return Creat_LinkList(L->next); //遞歸創建節點 33 } 34 } 35 36 int count_LNode(LinkList L){ //統計節點個數,傳入鏈表首地址 37 if (L == NULL)return 0; //遞歸結束條件,遞歸到尾節點的下一個節點,直接返回 38 else return count_LNode(L->next) + 1; //否則繼續指向下一個節點,表長加1 39 } 40 41 void lprint_LNode(LinkList L){ //正序打印鏈表 42 if (L == NULL)return; //遞歸的結束條件 43 else{ 44 cout << L->data << ‘ ‘; //先打印當前節點的數據 45 lprint_LNode(L->next); //再遞歸循環鏈表 46 } 47 } 48 49 void bprint_LNode(LinkList L){ //反序打印鏈表 50 if (L == NULL)return; //遞歸的結束條件 51 else{ 52 bprint_LNode(L->next); //先遞歸循環鏈表,將數據域壓入棧中 53 cout << L->data << ‘ ‘; //講數據出棧並打印 54 } 55 } 56 57 int maxVal_List(LinkList L) //求表中元素的最大值 58 { 59 int maxVal; 60 if (L->next == NULL) //如果到尾節點,就把當前節點的值賦值為maxVal 61 return L->data; //遞歸結束條件,出棧比較 62 else{ 63 maxVal = maxVal_List(L->next);//先把一個個數據壓棧 64 if (L->data > maxVal) 65 maxVal = L->data; 66 return maxVal; 67 } 68 69 } 70 71 int minVal_List(LinkList L) //求表中元素的最大值 72 { 73 int minVal; 74 if (L->next == NULL) //如果到尾節點,就把當前節點的值賦值為maxVal 75 return L->data; //返回末尾的值賦給尾節點 76 else{ 77 minVal = minVal_List(L->next);//先把一個個數據壓棧 78 if (L->data < minVal) 79 minVal = L->data; 80 return minVal; //返回上一層 81 } 82 } 83 84 int getSum_List(LinkList L){ //遞歸求該表中所有元素的和 85 if (L == NULL)return 0; //遞歸結束條件:當p指向空時,返回0 86 else //否則將當前指針指向的數據域壓入棧中,遞歸到鏈表尾 87 return getSum_List(L->next) + L->data; 88 } 89 90 bool found = false; 91 void Print_List(LinkList L, int val){ //12.打印單鏈表中從某節點元素開始後的所有節點 92 if (!L)return; //遞歸結束條件 93 else{ 94 if (L->data == val)found = true; 95 if (found)cout << L->data << ‘ ‘; //只要從滿足那一節點之後,打印該點之後的所有節點 96 Print_List(L->next, val); //遞歸 97 } 98 } 99 100 bool flag = false;//用來標記是否查找成功 101 void PriorElem_List(LinkList L, int val,int &preVal){ //9.求某元素的前驅元素,引用前驅元素 102 if (!L || L->data == val){ //當輸入val剛好是第一個節點的時候,直接返回 103 preVal = val; 104 return; 105 } 106 else { 107 if (L->next->data == val){ 108 preVal = L->data; 109 flag = true; 110 } 111 else 112 PriorElem_List(L->next, val, preVal);//遞歸查找 113 } 114 } 115 116 LinkList pre =NULL; 117 Status IsOrder_List(LinkList L){ //10.判斷單鏈表是否遞增有序 118 if (!L)return OK; //當遍歷到尾節點的下一個位置,返回正確,表示遞增有序 119 if (pre && (pre->data > L->data))return ERROR; 120 pre = L; //將當前節點作為前驅pre節點 121 return IsOrder_List(L->next); //遞歸遍歷每個節點 122 } 123 124 int j = 1; // 125 bool flag_insert = false; 126 void insert_List(LinkList &L, int i, int e){ //11.在單鏈表的第i個位置插入元素e 127 LinkList q; 128 if (i == 1){ 129 q = new LNode; 130 q->data = e;//賦值 131 q->next = L; 132 L = q; 133 flag_insert = true; 134 } 135 if (!L || flag_insert)return; //遞歸終止條件 136 else { 137 if (j == i-1){ 138 q = new LNode; //申請一個新的節點 139 q->data = e; //接下來的操作按常規來 140 q->next = L->next; 141 L->next = q; 142 flag_insert = true;//表示插入成功 143 } 144 else{ 145 j++; //表長先加1,再遞歸循環鏈表 146 insert_List(L->next, i, e); 147 } 148 } 149 } 150 151 bool findVal_list = false; 152 void check_List(LinkList L,int val){//檢查val元素是否在表中 153 if (L == NULL || findVal_list)return; //遞歸出口,若找到的話就不用遞歸了 154 else{ 155 if (L->data == val)findVal_list=true; //此時已經找到 156 else check_List(L->next, val); //繼續遞歸查找 157 } 158 } 159 160 int k = 1; 161 bool delNodeflag = false; 162 void delNode_List(LinkList &L,int i,int &e){ //13.刪除單鏈表的第i個元素 163 if (!L || delNodeflag)return; 164 else{ 165 LinkList q; 166 if (i == 1){ 167 q = L; 168 e = q->data; 169 L = L->next; 170 delete q; 171 delNodeflag = true; 172 } 173 else if (k == i-1){ //找到要刪除節點的前驅 174 q= L->next; //基本操作 175 e = q->data; 176 L->next = q->next; 177 delete q; 178 delNodeflag = true; //標記刪除成功 179 } 180 else { 181 k++; //循環鏈表 182 delNode_List(L->next,i,e); //遞歸鏈表 183 } 184 } 185 } 186 int main() 187 { 188 int i,e; 189 int choose; 190 191 LinkList L; 192 choose = -1; 193 while (choose != 0) 194 { 195 cout << "******************************************************************************\n"; 196 cout << " 1. 建立空鏈表; 2. 輸入指定個數的數據元素創建鏈表\n"; 197 cout << " 3. 正序打印表中元素 ; 4. 逆序打印表中元素\n"; 198 cout << " 5. 求表中元素的最大值; 6. 求表中元素的最小值\n" ; 199 cout << " 7. 返回單鏈表的長度; 8. 遞歸求該表中所有節點元素的和\n"; 200 cout << " 9. 查找某元素的前驅元素; 10.判斷單鏈表是否遞增有序 \n"; 201 cout << " 11.在單鏈表的第i個位置插入元素e 12.打印單鏈表中從某節點元素開始後的所有節點\n"; 202 cout << " 13.刪除單鏈表的第i個元素 0. 退出\n"; 203 cout << "*******************************************************************************\n"; 204 205 cout << "請選擇:"; 206 cin >> choose; 207 switch (choose) 208 { 209 case 1: //建立空鏈表 210 L =NULL;//這裏不帶頭結點,建立空鏈表 211 cout << "成功建立空鏈表" << endl << endl; 212 break; 213 case 2: //輸入指定個數的數據元素創建鏈表 ,這裏也可以調用當輸入不為-1的函數 214 /*cout << "請輸入一個數,代表元素的個數:"; 215 cin >> i; 216 if (i == 0) 217 cout << "此時創建的是空鏈表" << endl<<endl; 218 else{ 219 cout << "請輸入" << i << "個數據元素,之間用空格隔開:"; 220 create_List(L, i); 221 cout << "成功建立單鏈表" << endl << endl; 222 } */ 223 if (Creat_LinkList(L)) //也可以用第2中創建節點的方法創建單鏈表,此時實參傳入第一個節點的指針 224 cout << "成功創建單鏈表" << endl; 225 else 226 cout << "創建單鏈表失敗" << endl; 227 break; 228 case 3: //正序打印表中元素 229 if (count_LNode(L)){ 230 cout << "當前表中一共有" << count_LNode(L) << "個元素,正序輸出依次為"; 231 lprint_LNode(L); 232 cout << endl<<endl; 233 } 234 else 235 cout << "當前為空鏈表" << endl << endl; 236 break; 237 case 4: //逆序打印表中元素 238 if (count_LNode(L)){ 239 cout << "當前表中一共有" << count_LNode(L) << "個元素,逆序輸出依次為"; 240 bprint_LNode(L); 241 cout << endl << endl; 242 } 243 else 244 cout << "當前為空鏈表" << endl << endl; 245 break; 246 case 5: //求表中元素的最大值 247 if (count_LNode(L)){ 248 cout << "表中最大的元素為:" << maxVal_List(L) << "。\n" << endl; 249 } 250 else 251 cout << "當前為空鏈表" << endl << endl; 252 break; 253 case 6: //求表中元素的最小值 254 if (count_LNode(L)){ 255 cout << "表中最小的元素為:" << minVal_List(L) << "。\n" << endl; 256 } 257 else 258 cout << "當前為空鏈表" << endl << endl; 259 break; 260 case 7: //返回單鏈表的長度 261 if (count_LNode(L)) 262 cout << "當前單鏈表表長為" << count_LNode(L) << "。\n" << endl; 263 else 264 cout << "當前為空表" << endl << endl; 265 break; 266 case 8: //遞歸求該表中所有元素的和 267 if (count_LNode(L)) 268 cout << "當前表中所有元素的和為" << getSum_List(L) << "。\n" << endl; 269 else 270 cout << "當前為空表" << endl << endl; 271 break; 272 case 9: //查找某元素的前驅元素 273 if (!L) 274 cout << "當前為空表" << endl<<endl; 275 else { 276 int val,preVal; 277 cout << "請輸入一個待查找前驅元素的元素:"; 278 cin >> val; 279 flag = false; 280 PriorElem_List(L, val, preVal); 281 if (flag) 282 cout << "待查找元素" << val << "的前驅元素為" << preVal << "。\n" << endl; 283 else 284 cout << "找不到" << val << "的前驅元素" << endl << endl; 285 } 286 break; 287 case 10: ///判斷單鏈表是否遞增有序 288 if (IsOrder_List(L)) 289 cout << "該鏈表遞增有序" << endl << endl; 290 else 291 cout << "該鏈表非遞增" << endl << endl; 292 break; 293 case 11: //在單鏈表的第i個位置後面插入元素e,在這裏鏈表長度至少為1,否則插入失敗 294 cout <<"請輸入要插入元素的位置及插入的元素分別為(用空格隔開):"; 295 cin >> i>> e; 296 if (i<1 || (i>count_LNode(L)+1)) 297 cout << "輸入" << i << "不在節點位置範圍內。" << endl << endl; 298 else{ 299 flag_insert = false, j = 1; 300 insert_List(L, i, e); 301 if (flag_insert) 302 cout << "成功在第" << i << "個位置插入元素" << e << "。\n" << endl; 303 else 304 cout << "插入失敗" << endl << endl; 305 } 306 break; 307 case 12: //打印單鏈表中從某節點元素開始後的所有節點 308 if (!L) 309 cout << "當前為空表" << endl << endl; 310 else{ 311 int val; 312 findVal_list=found = false; 313 cout << "請輸入打印的起始元素:"; 314 cin >> val; 315 check_List(L, val); 316 if (findVal_list){ 317 cout << "鏈表元素依次為:"; 318 Print_List(L, val); 319 cout << endl << endl; 320 } 321 else 322 cout << "該表中沒有" << val << "這個元素。" << endl << endl; 323 } 324 break; 325 case 13: //刪除單鏈表的第i個元素 326 if (!L) 327 cout << "當前鏈表為空。" << endl << endl; 328 else{ 329 cout << "請輸入要刪除節點的位置:"; 330 cin >> i; 331 if (i<1 || i>count_LNode(L)) 332 cout << "輸入" << i << "不在節點位置範圍內。" << endl<< endl; 333 else{ 334 delNodeflag = false,k=1; 335 delNode_List(L, i, e); 336 if (delNodeflag) 337 cout << "成功刪除第" << i << "個位置的元素" << e << "。\n" << endl; 338 else 339 cout << "刪除失敗。" << endl << endl; 340 } 341 } 342 break; 343 } 344 } 345 return 0; 346 }
花了差不多一天時間終於搞懂了遞歸實現單鏈表的操作,寫代碼1h,測試找bug半天。。。~_~"||好好紀念一下。
遞歸實現單鏈表的各種基本操作