這次主要是利用結構體實現一個長度可變數組的增刪改查等各個操作。因為這里郝斌老師還沒講typedefy的使用,所以我也是跟着他使用了最原始的方法,一個個敲,發現這樣敲下來,也給自己鞏固了很多淡忘的知識。
自己基本是在視頻里說了方法后自己先思考然后實現的,結果犯了兩個低級錯誤:1、錯誤的使用函數值傳遞來改變值 2、貪圖簡便沒用大括號導致else與if結合錯誤,如果沒有大括號干擾,else總是與自己上面最近的一個if結合。
這里是使用結構體Arr來模擬這個數組的,結構體Arr中有三個成員變量,分別是數組的首元素地址、當期數組長度、當前數組中有效元素個數
1 struct Arr 2 { 3 int *pBase;//存儲的是數組第一個元素的地址,可以動態分配一塊內存空間給它,讓它指向第一個元素。 4 int len;//數組所能容納的最大元素個數 5 int cnt;//當前數組有效元素的個數 6 };
這里主要是實現了增加、插入、刪除、排序、倒置的功能。
增加:如果滿了則提示錯誤,返回false。成功則返回true
1 bool append_arr(struct Arr* pArr, int val) 2 { 3 if (true == is_full(pArr)) 4 { 5 printf("該數組已經滿了。追加失敗!\n"); 6 return false; 7 } 8 else 9 { 10 //pArr->pBase[pArr->cnt] = val; 11 *(pArr->pBase + pArr->cnt) = val; 12 pArr->cnt++; 13 return true; 14 } 15 }
插入:將一個值val插入到pArr指向的結構體變量的數組第pos個值的前面.如果該位置前面沒有值,或者該數組滿了,均提示錯誤,返回false。如果插入成功返回true
1 bool insert_arr(struct Arr* pArr,int pos,int val) 2 { 3 int i,temp; 4 if (true == is_full(pArr) || pos < 1 || pos > pArr->cnt+1) 5 { 6 printf("插入失敗!\n"); 7 return false; 8 } 9 else 10 { 11 for (i = pArr->cnt-1;i >= pos-1;i--) 12 pArr->pBase[i + 1] = pArr->pBase[i]; 13 pArr->pBase[pos-1] = val; 14 pArr->cnt++; 15 return true; 16 } 17 }
刪除:刪除pArr指向的結構體變量的數組第pos個的值,如果成功,將這個值放到pVal指向的變量里,返回true,如果數組為空或者這個位置沒有值,返回false
1 bool delete_arr(struct Arr* pArr,int pos,int * pVal) 2 { 3 int i; 4 if (true == is_empty(pArr) || pos<1 || pos>pArr->cnt) 5 { 6 printf("刪除失敗!\n"); 7 return false; 8 } 9 else 10 { 11 *pVal = pArr->pBase[pos - 1]; 12 for (i = pos;i <= pArr->cnt - 1;i++) 13 pArr->pBase[i - 1] = pArr->pBase[i]; 14 pArr->cnt--; 15 return true; 16 } 17 }
排序:這里使用的是冒泡排序,當flag為0則表示降序,其他值則為升序
1 void sort_arr(struct Arr* pArr,int flag) 2 { 3 int i, j; 4 if (true == is_empty(pArr)) 5 return; 6 for(i = 0;i < pArr->cnt-1;i++) 7 for (j = i + 1;j < pArr->cnt;j++) 8 { 9 if (0 == flag) 10 { 11 if (pArr->pBase[i] < pArr->pBase[j]) 12 exchange(&(pArr->pBase[i]), &(pArr->pBase[j])); 13 } 14 else 15 if (pArr->pBase[i] > pArr->pBase[j]) 16 exchange(&(pArr->pBase[i]), &(pArr->pBase[j])); 17 } 18 }
倒置:將整個數組倒置。比如 3 12 45 6 —–>> 6 45 12 3 這里我使用了兩種方法倒置:
第一種:直接不斷調換前后的值,直至全部被調換。(時間復雜度相對較高)
1 void inversion_arr(struct Arr* pArr) 2 { 3 int length,leftIndex,rightIndex; 4 if (true == is_empty(pArr)) 5 { 6 printf("倒置失敗!\n"); 7 return; 8 } 9 length = pArr->len; 10 //第一種 11 for (leftIndex = 0, rightIndex = pArr->cnt - 1;leftIndex < rightIndex;leftIndex++, rightIndex--) 12 exchange(&(pArr->pBase[leftIndex]),&(pArr->pBase[rightIndex])); 13 }
第二種:重新申請一塊內存,將值一一復制過來,然后改變結構體變量中指針的指向。最后將原地址的內存釋放(空間復雜度相對較高)
1 void inversion_arr(struct Arr* pArr) 2 { 3 int length,leftIndex,rightIndex; 4 if (true == is_empty(pArr)) 5 { 6 printf("倒置失敗!\n"); 7 return; 8 } 9 length = pArr->len; 10 //第二種 11 int * pTest = (int *)malloc(sizeof(int)*length); 12 int * freeP; 13 int i; 14 for (i = 0;i < pArr->cnt;i++) 15 pTest[pArr->cnt-i-1] = pArr->pBase[i]; 16 freeP = pArr->pBase;//先將原地址拿到 17 pArr->pBase = pTest;//再更換指向的地址 18 free(freeP);//將之前拿到的原地址內存釋放掉 19 }
下面是完整的程序:

1 #include<stdio.h> 2 #include<windows.h> 3 //定義了一個復合數據類型,該數據名字叫 struct Arr,它包含了三個基礎數據類型 4 struct Arr 5 { 6 int *pBase;//存儲的是數組第一個元素的地址,可以動態分配一塊內存空間給它,讓它指向第一個元素。 7 int len;//數組所能容納的最大元素個數 8 int cnt;//當前數組有效元素的個數 9 }; 10 11 void init_arr(struct Arr* pArr,int length);//初始化 12 bool append_arr(struct Arr* pArr,int val);//追加 13 bool insert_arr(struct Arr* pArr,int pos,int val);//將val插入到pArr指向的結構體變量的數組第pos個的值的前面. 14 bool delete_arr(struct Arr* pArr,int pos,int *pVal);//刪除函數,刪除pArr指向的結構體變量的數組第pos個的值,如果成功,將這個值放到pVal指向的變量里 15 bool is_empty(struct Arr* pArr);//判斷數組是否為空 16 bool is_full(struct Arr* pArr);//判斷數組是否已經滿了 17 void sort_arr(struct Arr* pArr,int flag);//冒泡排序,flag為0則表示降序,其他值則為升序 18 void show_arr(struct Arr* pArr);//顯示數組的值 19 void inversion_arr(struct Arr* pArr);//倒置數組 20 21 void exchange(int* a, int* b);//更換兩個整型變量的值 22 23 int main(void) 24 { 25 int val; 26 struct Arr arr;//整出了一個struct Arr類型的對象,不過未賦值,里面目前都是垃圾數值 27 init_arr(&arr,6); 28 29 //追加值,然后插入值,最后顯示 30 append_arr(&arr, 2); 31 append_arr(&arr, 13); 32 append_arr(&arr, 7); 33 insert_arr(&arr, 4, 45); 34 show_arr(&arr); 35 36 //刪除一個值,然后顯示 37 if (delete_arr(&arr, 4, &val)) 38 printf("你刪除的元素為%d\n",val); 39 show_arr(&arr); 40 41 //倒置整個數組,然后顯示 42 inversion_arr(&arr); 43 show_arr(&arr); 44 45 //排序后顯示 46 sort_arr(&arr,1); 47 show_arr(&arr); 48 49 50 system("pause"); 51 return 0; 52 } 53 54 //初始化 55 void init_arr(struct Arr* pArr,int length) 56 { 57 //通過結構體變量指針訪問結構體變量中的成員有兩種方式:1、通過(*probe).valuable 2、通過probe->valuable 58 59 pArr->pBase = (int *)malloc(sizeof(int)*length); 60 if (NULL == pArr->pBase)//如果分配內存失敗 61 { 62 printf("動態內存分配失敗!\n"); 63 exit(-1);//終止整個程序 64 } 65 else 66 { 67 (*pArr).len = length; 68 pArr->cnt = 0; 69 } 70 return; 71 } 72 73 void show_arr(struct Arr* pArr) 74 { 75 int i; 76 //如果為空,直接提示為空。否則輸出有效內容 77 if (true == is_empty(pArr)) 78 { 79 printf("該數組為空\n"); 80 } 81 else 82 { 83 for (i = 0;i < pArr->cnt;i++) 84 { 85 //下面兩種方法皆可以 86 printf("%d ",pArr->pBase[i]); //數組的地址存在pArr->pBase中,這個東西可以當成數組名來使用 87 //printf("%d\n",*(pArr->pBase+i)); //將地址加i,即指向的地址往后移多少,然后通過*取出值 88 } 89 printf("\n"); 90 } 91 } 92 93 bool is_empty(struct Arr* pArr) 94 { 95 //判斷結構體變量中的有效個數是否為0,如果為零則表示這個數組為空,返回true 96 if (0 == pArr->cnt) 97 return true; 98 else 99 return false; 100 } 101 102 bool is_full(struct Arr* pArr) 103 { 104 if (pArr->len == pArr->cnt)//如果長度和有效個數相等,則滿了 105 return true; 106 else 107 return false; 108 } 109 110 bool append_arr(struct Arr* pArr, int val) 111 { 112 //判斷是否滿了,如果滿了,則追加失敗,返回false 113 //否則將值添加到數組里,將有效個數加1 114 if (true == is_full(pArr)) 115 { 116 printf("該數組已經滿了。追加失敗!\n"); 117 return false; 118 } 119 else 120 { 121 //兩種賦值方法都可以 122 //pArr->pBase[pArr->cnt] = val; 123 *(pArr->pBase + pArr->cnt) = val; 124 pArr->cnt++; 125 return true; 126 } 127 128 } 129 130 bool insert_arr(struct Arr* pArr,int pos,int val) 131 { 132 int i,temp; 133 //先判斷是否能夠插入值。如果不能插入值,則返回false:判斷是否滿了,以及pos是否合理 134 //如果能夠插入值,則先將這個下標的值及后面的值都往后移一位。 135 //移動方法:先通過數組有效元素個數,將最后的一個值往后移一位,然后再將前面一個的值往后移一位。直到pos 136 //然后將pos位置的值變成val,將有效個數加1,返回true; 137 if (true == is_full(pArr) || pos < 1 || pos > pArr->cnt+1) 138 { 139 printf("插入失敗!\n"); 140 return false; 141 } 142 else 143 { 144 for (i = pArr->cnt-1;i >= pos-1;i--) 145 { 146 pArr->pBase[i + 1] = pArr->pBase[i]; 147 } 148 pArr->pBase[pos-1] = val; 149 pArr->cnt++; 150 return true; 151 } 152 } 153 154 155 bool delete_arr(struct Arr* pArr,int pos,int * pVal) 156 { 157 //如果數組為空則失敗 158 //如果pos的值不合理,也返回失敗。 159 //否則,將第pos位的值給pVal指向的變量 160 //並將pos后面的值依次賦給前面的一位,直到有效個數的值也賦給了前面一位,讓有效位數減1,返回成功 161 int i; 162 if (true == is_empty(pArr) || pos<1 || pos>pArr->cnt) 163 { 164 printf("刪除失敗!\n"); 165 return false; 166 } 167 else 168 { 169 *pVal = pArr->pBase[pos - 1]; 170 for (i = pos;i <= pArr->cnt - 1;i++) 171 pArr->pBase[i - 1] = pArr->pBase[i]; 172 pArr->cnt--; 173 return true; 174 } 175 } 176 void inversion_arr(struct Arr* pArr) 177 { 178 //倒置整個數組 179 //先判斷數組是否為空,如果為空,直接返回 180 //如果不為空,兩種方案。 181 //第一種:引入一個中間變量、一個左下標、一個右下標。左右下標初始分別為0和有效個數減1.通過中間變量交換值,左右下標往中間靠。時間復雜度相對高一些。 182 //第二種,重新開辟一個同樣長度的數組,從后往前依次給新數組賦值,然后直接改變結構體變量中數組的地址,即pBase的指向.此方法空間復雜度相對高一些。 183 int length,leftIndex,rightIndex; 184 if (true == is_empty(pArr)) 185 { 186 printf("倒置失敗!\n"); 187 return; 188 } 189 length = pArr->len; 190 //第一種 191 /*for (leftIndex = 0, rightIndex = pArr->cnt - 1;leftIndex < rightIndex;leftIndex++, rightIndex--) 192 exchange(&(pArr->pBase[leftIndex]),&(pArr->pBase[rightIndex]));*/ 193 194 //第二種 195 int * pTest = (int *)malloc(sizeof(int)*length); 196 int * freeP; 197 int i; 198 for (i = 0;i < pArr->cnt;i++) 199 pTest[pArr->cnt-i-1] = pArr->pBase[i]; 200 freeP = pArr->pBase;//先將原地址拿到 201 pArr->pBase = pTest;//再更換指向的地址 202 free(freeP);//將之前拿到的原地址內存釋放掉 203 } 204 205 void sort_arr(struct Arr* pArr,int flag) 206 { 207 //如果為空,直接返回。 208 //否則,根據flag的值,使用冒泡排序。升序或者是降序 209 int i, j; 210 if (true == is_empty(pArr)) 211 { 212 return; 213 } 214 for(i = 0;i < pArr->cnt-1;i++) 215 for (j = i + 1;j < pArr->cnt;j++) 216 { 217 //2018年3月27日 20:08:07 218 //這里犯了個很低級的錯誤。。。如果沒有大括號干擾,else總是與自己上面最近的一個if結合起來。 219 //所以這里相當於是 如果flag不為0,則不做處理,如果為0,且前面的小於后面的,則交換位置。 220 221 /*if (0 == flag) 222 if (pArr->pBase[i] < pArr->pBase[j]) 223 exchange(&(pArr->pBase[i]),&(pArr->pBase[j])); 224 else 225 if (pArr->pBase[i] > pArr->pBase[j]) 226 exchange(&(pArr->pBase[i]), &(pArr->pBase[j]));*/ 227 228 if (0 == flag) 229 { 230 if (pArr->pBase[i] < pArr->pBase[j]) 231 exchange(&(pArr->pBase[i]), &(pArr->pBase[j])); 232 } 233 else 234 if (pArr->pBase[i] > pArr->pBase[j]) 235 exchange(&(pArr->pBase[i]), &(pArr->pBase[j])); 236 } 237 238 } 239 240 //更換兩個整型變量的值!一定記得需要通過指針改變值,傳遞值是無法修改原來的變量值的 241 void exchange(int* a, int* b) 242 { 243 int temp; 244 temp = *a; 245 *a = *b; 246 *b = temp; 247 }