遞歸實現單鏈表的各種基本操作


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM