二、鏈表頭插入法工做流程及測試node
3.1調試deleteElementByIndex()函數發現,主函數中的linkPtr通過showlinkList()函數以後已經成爲了NULL空指針程序員
3.2改進算法
四、雙向鏈表數組
(1) 鏈表初始化和建立瀏覽器
5.1++i和i++運算符的測試 m41
(1)本身實現
(2)使用C++庫函數stack
(3)使用兩個站實現一個隊列:參考筆試練習:m12
例子:
1 //01)形參改變,實參並無改變的例子 2 #include <iostream> 3 4 using std::cout; 5 using std::endl; 6 7 /*交換a和b的值子函數*/ 8 void changeParameters(int a, int b) 9 { 10 int temp; 11 temp = a; 12 a = b; 13 b = temp; 14 } 15 16 int main() 17 { 18 int num1 = 12; 19 int num2 = 22; 20 cout << num1 << " , " << num2 << endl; 21 changeParameters(num1, num2); //此時num1和num2知識形參交換,實際參數並無交換 22 cout << num1 << " , " << num2 << endl; 23 24 system("pause"); 25 return 0; 26 }
運行結果:
例子:
1 //02)實參發生改變的例子 2 #include <iostream> 3 4 using std::cout; 5 using std::endl; 6 7 /*交換a和b的值子函數*/ 8 void changeParameters(int* a, int* b) 9 { 10 int temp; //此處改爲int* temp交換地址,而後把*a和*b去掉也是能夠的 11 temp = *a; 12 *a = *b; 13 *b = temp; 14 } 15 16 int main() 17 { 18 int num1 = 12; 19 int num2 = 22; 20 cout << num1 << " , " << num2 << endl; 21 changeParameters(&num1, &num2); //此時是對存儲空間這的兩個數進行交換,因此num1和num2的值會發生交換 22 cout << num1 << " , " << num2 << endl; 23 24 system("pause"); 25 return 0; 26 }
運行結果:
例子:
1 #include <iostream> 2 3 using std::cout; 4 using std::endl; 5 6 /*交換a和b的值子函數(相關解釋見下)*/ 7 void changeParameters(int** a, int** b) 8 { 9 int* temp; 10 temp = *a; //保存*a指向的地址 11 *a = *b; //將*b指向的地址賦給*a指向的地址 12 *b = temp; 13 } 14 15 int main() 16 { 17 int a = 12; 18 int b = 22; 19 int* num1 = &a; 20 int* num2 = &b; 21 cout << *num1 << " , " << *num2 << endl; 22 changeParameters(&num1, &num2); //對指針取地址,即只想指針的指針,或者是地址的地址 23 cout << *num1 << " , " << *num2 << endl; 24 25 system("pause"); 26 return 0; 27 } 28 29 /* 30 int a = 12; //假設存儲a變量的地址是00424A30 31 int* pc = &a; //則pc指向地址00424A30,假設存儲pc的地址是00424A38 32 int** ppc = &pc; //ppc指向pc的地址(00424A38) 33 34 cout << "a的地址是: " << &a << endl; //打印 a的地址是: 00424A30 35 cout << "pc的值是: " << pc << endl; //打印 pc的值是: 00424A30 pc的值就是a的地址 36 cout << "*pc的值是: " << pc << endl; //打印 *pc的值是: 12 37 cout << "pc的地址是: " << &pc << endl; //打印 *pc的值是: 00424A38 38 cout << "ppc的值是: " << ppc << endl; //打印 ppc的值是: 00424A38 (ppc的值就是pc的地址) 39 cout << "*ppc的值是: " << ppc << endl; //打印 ppc的值是: 00424A38 (ppc的值就是pc的地址) 40 cout << "*(*ppc)的值是: " << *(*ppc) << endl; //打印 ppc的值是: 2 41 */
運行結果:
在例子中的一個解析:
1 int a = 12; //假設存儲a變量的地址是00424A30 2 int* pc = &a; //則pc指向地址00424A30,假設存儲pc的地址是00424A38 3 int** ppc = &pc; //ppc指向pc的地址(00424A38) 4 5 cout << "a的地址是: " << &a << endl; //打印 a的地址是: 00424A30 6 cout << "pc的值是: " << pc << endl; //打印 pc的值是: 00424A30 pc的值就是a的地址 7 cout << "*pc的值是: " << pc << endl; //打印 *pc的值是: 12 8 9 cout << "pc的地址是: " << &pc << endl; //打印 *pc的值是: 00424A38 10 cout << "ppc的值是: " << ppc << endl; //打印 ppc的值是: 00424A38 (ppc的值就是pc的地址) 11 12 cout << "*ppc的值是: " << ppc << endl; //打印 ppc的值是: 00424A38 (ppc的值就是pc的地址) 13 cout << "*(*ppc)的值是: " << *(*ppc) << endl; //打印 ppc的值是: 2
參考博客:https://blog.csdn.net/qq_34991245/article/details/81868212
例子:
1 #include <iostream> 2 3 using std::cout; 4 using std::endl; 5 6 /*交換a和b的值子函數(相關解釋見下)*/ 7 void changeParameters(int** a, int** b) 8 { 9 int* temp = *a; 10 int p = 33; 11 temp = &p; //驗證一下實參a的值會不會改變,此句不會改變實參a的值 12 *temp = p; //此句不會改變實參a的值 13 } 14 15 int main() 16 { 17 int a = 12; 18 int b = 22; 19 int* num1 = &a; 20 int* num2 = &b; 21 cout << *num1 << " , " << *num2 << endl; 22 changeParameters(&num1, &num2); //對指針取地址,即只想指針的指針,或者是地址的地址 23 cout << *num1 << " , " << *num2 << endl; 24 25 system("pause"); 26 return 0; 27 }
運行結果:
1 #include <iostream> 2 3 using std::cout; 4 using std::endl; 5 6 /*交換a和b的值子函數(相關解釋見下)*/ 7 void changeParameters(int** a, int** b) 8 { 9 int p = 33; 10 *a = &p; //直接對形參(實參)賦值這樣是會改變實參的值的 11 } 12 13 int main() 14 { 15 int a = 12; 16 int b = 22; 17 int* num1 = &a; 18 int* num2 = &b; 19 cout << *num1 << " , " << *num2 << endl; 20 changeParameters(&num1, &num2); //對指針取地址,即只想指針的指針,或者是地址的地址 21 cout << *num1 << " , " << *num2 << endl; 22 23 system("pause"); 24 return 0; 25 }
運行結果:
01)頭插法工做流程:
1 /*鏈表*/ 2 3 #include <iostream> 4 5 using std::cin; 6 using std::cout; 7 using std::endl; 8 9 typedef int ElementType; 10 11 /*定義一個結構*/ 12 struct linkList 13 { 14 ElementType Element; //定義結構中的一個數據(數據域) 15 linkList* next; //定義指向下一個結構的指針(指針域) 16 }; 17 18 typedef struct linkList *PtrtoNode; //PtrtoNode是一個類型,能夠定義變量,且PtrtoNode是一個指針,指向結構體Node 19 typedef PtrtoNode List; //爲PtrtoNode起別名爲List 20 typedef PtrtoNode Position; //爲PtrtoNode起別名爲Position 21 22 void initlinkList(linkList** head); 23 void destroylinkListByHead(linkList** head); 24 void destroylinkListByTail(linkList** head); 25 void insertDatabyHead(linkList** head); 26 void insertDatabyTail(linkList* head); 27 void showlinkList(linkList** head); 28 linkList* indexof(linkList* head, int index); 29 int deleteElementByIndex(linkList* head, int index);
1 #include "stacktp1.h" 2 3 /* 4 01)鏈表的初始化(給頭節點申請空間),因此在使用改函數的時候,只傳入已建立結構的next指針便可; 5 02)使用指向指針的指針做爲形參的緣由在於要傳入的參數是一個指針(要傳入的參數是結構中的next指針), 6 若是形參定義爲一層指針,那麼就會發生形參改變而實參並無發生任何改變的狀況。 7 */ 8 void initlinkList(linkList** head) 9 { 10 if ((*head) == NULL) //若是結構這的next指針爲空,那麼代表已經初始化完成;剛剛這裏寫成了 != 致使在插入數據的時候head->next訪問不了 11 return; 12 *head = (linkList*)malloc(sizeof(linkList)); //給結構分配足夠的內存空間 13 (*head)->Element = 0; 14 (*head)->next = NULL; //head此時便是頭節點也是尾節點,由於此時head指向了NULL 15 } 16 17 /* 18 01)鏈表的銷燬 19 02)鏈表全部節點包括頭結點都是動態申請的堆空間,使用完畢後必須手動釋放,這裏的銷燬要把全部的節點空間所有釋放; 20 03)方法一:從鏈表頭開始遍歷,也就是從前向後逐個釋放每個節點的空間 21 */ 22 void destroylinkListByHead(linkList** head) 23 { 24 linkList* header = *head; 25 linkList* p; 26 while ( header != NULL) //原來這裏的條件是(*head)!=NULL,致使p->next指向了空指針;或者是循環了無數次 27 { 28 p = header; //講當前數據節點保存下來 29 header = p->next; //將下一個數據節點保存下來 30 free(p); //講當前節點空間釋放 31 } 32 free(header); //釋放頭節點 33 head = NULL; //空間釋放完的指針指向空指針 34 } 35 36 /* 37 01)方法二:從鏈表尾部向頭部開始銷燬,就不用臨時保存 38 02)用遞歸遍歷到最後一個結點,逐層向上返回,銷燬每個節點,順序就是從頭尾向頭結點的順序銷燬。 39 */ 40 void destroylinkListByTail(linkList** head) 41 { 42 if ((*head) == NULL) 43 return; 44 destroylinkListByTail(&((*head)->next)); //遞歸調用 45 free(*head); 46 head = NULL; 47 } 48 49 /* 50 01)向鏈表這插入數據 51 02)頭插法:每次在頭結點H的後面插入一個輸入的數據,鏈表中的數據順序和實際輸入順序相反 52 03)插入的過程主要是:先申請一個新的結點,鏈表不像數組一次性分配指定長度的空間, 53 鏈表是須要增加一個就再申請一份,而後連接起來。申請完了以後給節點賦值,讓新申請的節 54 點指向頭結點的next,也就是node->next = h->next,再讓頭結點指向這個新節點, 55 H->next = node就完成插入操做。 56 04)傳入的參數能夠是頭結點(頭節點指向的是NULL) 57 05)傳入的參數也能夠是一個linkList結構的地址 58 06)覺得此時是要向一個鏈表中插入數據,因此在使用malloc以後並無釋放內存 59 */ 60 void insertDatabyHead(linkList** head) 61 { 62 linkList* node; //新建一個須要插入的節點 63 int x; 64 cout << "請輸入數據(-1結束):" << endl; 65 cin >> x; 66 while (x != -1) 67 { 68 node = (linkList*) malloc(sizeof(linkList)); //爲須要插入的節點分配空間 69 node->Element = x; 70 //若是頭節點指向的是NULL,因此下面這一句node->next換成NULL也能夠 71 node->next = (*head)->next; //使node成爲head指向的一個節點以後的節點 72 (*head)->next = node; //使 73 cout << "請輸入數據(-1結束):" << endl; //接着輸入數據 74 cin >> x; 75 } 76 } 77 78 /* 79 01)向鏈表這插入數據 80 02)尾插法:每次插入新的數據在鏈表的尾部插入就行,鏈表中的數據順序和實際輸入順序相同 81 03)先找到鏈表的尾節點H->next == NULL,就是最後一個節點,一樣插入就行。相比頭插法, 82 尾插法插入數據的時候若是鏈表不是一條空鏈表,得遍歷先找到尾節點。 83 04)傳入的參數的頭結點(頭節點指向的是NULL) 84 05)輸入的參數是一個linkList結構的地址 85 */ 86 87 void insertDatabyTail(linkList* head) 88 { 89 linkList* node; 90 linkList* remove; 91 int x; 92 while (head->next != NULL) //若是head不是尾節點,那麼找到尾節點,並使head成爲尾節點;尾節點指向NULL 93 head = head->next; 94 remove = head; //將head(尾節點)賦給remove,是remove也成爲尾節點 95 cout << "請輸入要插入的數據(-1結束): " << endl; 96 cin >> x; 97 while (x != -1) 98 { 99 node = (linkList*)malloc(sizeof(linkList)); 100 node->Element = x; 101 node->next = remove->next; //此處也可使用head->next,但使用remove是爲了循環大計 102 remove->next = node; //此處也可使用head->next,可是鏈表就是斷的了 103 remove = node; //爲下一次循環作準備 104 cout << "請輸入要插入的數據(-1結束): " << endl; 105 cin >> x; 106 } 107 } 108 109 /* 110 01)打印鏈表 111 02)輸入爲當前節點,或者是一個結構的地址 112 */ 113 114 void showlinkList(linkList** head) 115 { 116 if ((*head)->next == NULL ) //若是當前節點是頭節點,則指向下一個節點;覺得頭節點是沒有數據的 117 (*head) = (*head)->next; 118 (*head) = (*head)->next; //不顯示頭結點中的元素;上面那個if確定不會被執行的,由於傳入的參數是頭結點,頭結點的下一個節點確定不是空(只要有數據) 119 while ((*head) != NULL ) 120 { 121 cout << (*head)->Element << endl; 122 (*head) = (*head)->next; 123 } 124 } 125 126 /* 127 01)刪除第index個節點 128 */ 129 /*返回第index個節點*/ 130 linkList* indexof(linkList* head, int index) 131 { 132 linkList* p; 133 if (head->next == NULL) 134 { 135 cout << "輸入的當前節點爲頭節點" << endl; 136 return NULL; 137 } 138 int j; 139 for (j = 1, p = head->next; p != NULL && j < index; j++) //若是index等於1,則該for循環會忽略p=NULL的狀況 140 p = p->next; 141 return j == index ? p : NULL; 142 } 143 /*刪除第index個節點*/ 144 int deleteElementByIndex(linkList* head, int index) 145 { 146 linkList* p; 147 linkList* temp; 148 p = indexof(head, index); //找到第index個節點 149 if (p == NULL) 150 { 151 cout << "要刪除的爲頭節點" << endl; 152 return false; 153 } 154 temp = index == 1 ? NULL : indexof(head, index - 1); //找到要刪除節點的前一個節點(前驅節點) 155 temp->next = p->next; //讓要刪除節點的前驅節點指向要刪除節點的下一個節點 156 free(p); //釋放要刪除節點的內存 157 return true; 158 }
1 #include "stacktp1.h" 2 3 int main() 4 { 5 linkList* linkPtr; 6 initlinkList(&linkPtr); 7 insertDatabyHead(&linkPtr); 8 showlinkList(&linkPtr); 9 destroylinkListByHead(&linkPtr); 10 11 system("pause"); 12 return 0; 13 }
運行結果:
調試deleteElementByIndex()函數發現,主函數中的linkPtr通過showlinkList()函數以後已經成爲了NULL空指針,緣由在於全部的函數都使用二階指針,一旦子函數中對實參進行了賦值的操做,
那麼主函數中的實參也是會發生變化的,如:05)二階指針做爲形參,一階指針的地址做爲實參,改變子涵數(形參)實參的值會影響實參的值,因此使用二階指針需謹慎~
改進的方法:
01)將實參傳遞給子涵數中的一個一階指針,而後改變該一階指針,這樣就不會改變實參,如 04)二階指針做爲形參,一階指針的地址做爲實參,將形參賦給子函數中的一個變量,改變該便利的值不會影響實參的值
02)將部分函數中的二階形參該爲一階形參
下面附上所有子函數使用二階指針的例子,該例子中的showlinkList()函數會使linPtr成爲NULL空指針,致使接下來繼續調用linkPtr出錯
1 #include "stacktp1.h" 2 3 int main() 4 { 5 linkList* linkPtr; //建立鏈表的頭結點 6 initlinkList(&linkPtr); 7 insertDatabyTail(&linkPtr); 8 //showlinkList(&linkPtr); //此句已經使linkPt成爲了尾節點,因此執行下一句會報錯 9 deleteElementByIndex(&linkPtr,5); //刪除頭結點爲linkPtr,鏈表中第二個數 10 showlinkList(&linkPtr); //此句已經使linkPt成爲了尾節點,因此不會執行下一個函數中的while循環,即不會刪除鏈表 11 destroylinkListByHead(&linkPtr); 12 13 system("pause"); 14 return 0; 15 }
1 #include "stacktp1.h" 2 3 /* 4 01)鏈表的初始化(給頭節點申請空間),因此在使用改函數的時候,只傳入已建立結構的next指針便可; 5 02)使用指向指針的指針做爲形參的緣由在於要傳入的參數是一個指針(要傳入的參數是結構中的next指針), 6 若是形參定義爲一層指針,那麼就會發生形參改變而實參並無發生任何改變的狀況。 7 */ 8 void initlinkList(linkList** head) 9 { 10 if ((*head) == NULL) //若是結構這的next指針爲空,那麼代表已經初始化完成;剛剛這裏寫成了 != 致使在插入數據的時候head->next訪問不了 11 return; 12 *head = (linkList*)malloc(sizeof(linkList)); //給結構分配足夠的內存空間 13 (*head)->Element = 0; 14 (*head)->next = NULL; //head此時便是頭節點也是尾節點,由於此時head指向了NULL 15 } 16 17 /* 18 01)鏈表的銷燬 19 02)鏈表全部節點包括頭結點都是動態申請的堆空間,使用完畢後必須手動釋放,這裏的銷燬要把全部的節點空間所有釋放; 20 03)方法一:從鏈表頭開始遍歷,也就是從前向後逐個釋放每個節點的空間 21 */ 22 void destroylinkListByHead(linkList** head) 23 { 24 linkList* header = *head; 25 linkList* p; 26 while ( header != NULL) //原來這裏的條件是(*head)!=NULL,致使p->next指向了空指針;或者是循環了無數次 27 { 28 p = header; //講當前數據節點保存下來 29 header = p->next; //將下一個數據節點保存下來 30 free(p); //講當前節點空間釋放 31 cout << "刪除數據: " <<p->Element << endl; 32 } 33 free(header); //釋放頭節點 34 head = NULL; //空間釋放完的指針指向空指針 35 cout << "鏈表已被刪除完畢" << endl; 36 } 37 38 /* 39 01)方法二:從鏈表尾部向頭部開始銷燬,就不用臨時保存 40 02)用遞歸遍歷到最後一個結點,逐層向上返回,銷燬每個節點,順序就是從頭尾向頭結點的順序銷燬。 41 */ 42 void destroylinkListByTail(linkList** head) 43 { 44 if ((*head) == NULL) 45 return; 46 destroylinkListByTail(&((*head)->next)); //遞歸調用 47 free(*head); 48 head = NULL; 49 cout << "鏈表已被刪除完畢" << endl; 50 } 51 52 /* 53 01)向鏈表這插入數據 54 02)頭插法:每次在頭結點H的後面插入一個輸入的數據,鏈表中的數據順序和實際輸入順序相反 55 03)插入的過程主要是:先申請一個新的結點,鏈表不像數組一次性分配指定長度的空間, 56 鏈表是須要增加一個就再申請一份,而後連接起來。申請完了以後給節點賦值,讓新申請的節 57 點指向頭結點的next,也就是node->next = h->next,再讓頭結點指向這個新節點, 58 H->next = node就完成插入操做。 59 04)傳入的參數能夠是頭結點(頭節點指向的是NULL) 60 05)傳入的參數也能夠是一個linkList結構的地址 61 06)覺得此時是要向一個鏈表中插入數據,因此在使用malloc以後並無釋放內存 62 */ 63 void insertDatabyHead(linkList** head) 64 { 65 linkList* node; //新建一個須要插入的節點 66 int x; 67 cout << "請輸入數據(-1結束):" << endl; 68 cin >> x; 69 while (x != -1) 70 { 71 node = (linkList*) malloc(sizeof(linkList)); //爲須要插入的節點分配空間 72 node->Element = x; 73 //若是頭節點指向的是NULL,因此下面這一句node->next換成NULL也能夠 74 node->next = (*head)->next; //使node成爲head指向的一個節點以後的節點 75 (*head)->next = node; //使 76 cout << "請輸入數據(-1結束):" << endl; //接着輸入數據 77 cin >> x; 78 } 79 } 80 81 /* 82 01)向鏈表這插入數據 83 02)尾插法:每次插入新的數據在鏈表的尾部插入就行,鏈表中的數據順序和實際輸入順序相同 84 03)先找到鏈表的尾節點H->next == NULL,就是最後一個節點,一樣插入就行。相比頭插法, 85 尾插法插入數據的時候若是鏈表不是一條空鏈表,得遍歷先找到尾節點。 86 04)傳入的參數的頭結點(頭節點指向的是NULL) 87 05)輸入的參數是一個linkList結構的地址 88 */ 89 90 void insertDatabyTail(linkList** head) 91 { 92 linkList* node; 93 linkList* remove; 94 int x; 95 while ((*head)->next != NULL) //若是head不是尾節點,那麼找到尾節點,並使head成爲尾節點;尾節點指向NULL 96 (*head) = (*head)->next; 97 remove = (*head); //將head(尾節點)賦給remove,是remove也成爲尾節點 98 cout << "請輸入要插入的數據(-1結束): " << endl; 99 cin >> x; 100 while (x != -1) 101 { 102 node = (linkList*)malloc(sizeof(linkList)); 103 node->Element = x; 104 node->next = remove->next; //此處也可使用head->next,但使用remove是爲了循環大計 105 remove->next = node; //此處也可使用head->next,可是鏈表就是斷的了 106 remove = node; //爲下一次循環作準備 107 cout << "請輸入要插入的數據(-1結束): " << endl; 108 cin >> x; 109 } 110 } 111 112 /* 113 01)打印鏈表 114 02)輸入爲當前節點,或者是一個結構的地址 115 */ 116 117 void showlinkList(linkList** head) 118 { 119 if ((*head)->next == NULL ) //若是當前節點是頭節點,則指向下一個節點;覺得頭節點是沒有數據的 120 (*head) = (*head)->next; 121 (*head) = (*head)->next; //不顯示頭結點中的元素;上面那個if確定不會被執行的,由於傳入的參數是頭結點,頭結點的下一個節點確定不是空(只要有數據) 122 while ((*head) != NULL ) 123 { 124 cout << (*head)->Element << endl; 125 (*head) = (*head)->next; //注意!!這裏已經將傳入的頭結點變成了NULL!!!!!且實參是頭結點的地址,因此會改變實參的值 126 } 127 } 128 129 /* 130 01)刪除第index個節點 131 */ 132 /*返回第index個節點*/ 133 linkList* indexof(linkList* head, int index) 134 { 135 linkList* p = head; 136 if (head->next == NULL) //(*head)->next == NULL 137 { 138 cout << "輸入的鏈表只有一個節點,且該節點爲尾節點" << endl; 139 return NULL; 140 } 141 int j; 142 for (j = 0; p != NULL && j < index; j++) //若是index等於1,則該for循環會忽略p=NULL的狀況 143 p = p->next; 144 return j == index ? p : NULL; 145 } 146 /*刪除第index個節點*/ 147 int deleteElementByIndex(linkList** head, int index) 148 { 149 linkList* p; 150 linkList* temp; 151 p = indexof(*head, index); //找到第index個節點 152 if (p == NULL) 153 { 154 cout << "要刪除的爲頭節點" << endl; 155 return false; 156 } 157 temp = index == 1 ? NULL : indexof(*head, index - 1); //找到要刪除節點的前一個節點(前驅節點) 158 temp->next = p->next; //讓要刪除節點的前驅節點指向要刪除節點的下一個節點 159 free(p); //釋放要刪除節點的內存 160 return true; 161 }
1 /*鏈表*/ 2 #include <iostream> 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 8 typedef int ElementType; 9 10 /*定義一個結構*/ 11 struct linkList 12 { 13 ElementType Element; //定義結構中的一個數據(數據域) 14 linkList* next; //定義指向下一個結構的指針(指針域) 15 }; 16 17 typedef struct linkList *PtrtoNode; //PtrtoNode是一個類型,能夠定義變量,且PtrtoNode是一個指針,指向結構體Node 18 typedef PtrtoNode List; //爲PtrtoNode起別名爲List 19 typedef PtrtoNode Position; //爲PtrtoNode起別名爲Position 20 21 void initlinkList(linkList** head); 22 void destroylinkListByHead(linkList** head); 23 void destroylinkListByTail(linkList** head); 24 void insertDatabyHead(linkList** head); 25 void insertDatabyTail(linkList** head); 26 void showlinkList(linkList** head); 27 linkList* indexof(linkList** head, int index); 28 int deleteElementByIndex(linkList** head, int index);
運行結果:
以下圖所示:
另外在destroylinkListByHead()函數中的while循環中加入了一個cout用於顯示刪除的數據
1 #include "stacktp1.h" 2 3 int main() 4 { 5 linkList* linkPtr; //建立鏈表的頭結點 6 initlinkList(&linkPtr); 7 insertDatabyTail(&linkPtr); 8 showlinkList(&linkPtr); //此句已經使linkPt成爲了尾節點,因此執行下一句會報錯 9 deleteElementByIndex(&linkPtr,5); //刪除頭結點爲linkPtr,鏈表中第二個數 10 showlinkList(&linkPtr); //此句已經使linkPt成爲了尾節點,因此不會執行下一個函數中的while循環,即不會刪除鏈表 11 destroylinkListByHead(&linkPtr); 12 13 system("pause"); 14 return 0; 15 }
1 #include "stacktp1.h" 2 3 /* 4 01)鏈表的初始化(給頭節點申請空間),因此在使用改函數的時候,只傳入已建立結構的next指針便可; 5 02)使用指向指針的指針做爲形參的緣由在於要傳入的參數是一個指針(要傳入的參數是結構中的next指針), 6 若是形參定義爲一層指針,那麼就會發生形參改變而實參並無發生任何改變的狀況。 7 */ 8 void initlinkList(linkList** head) 9 { 10 if ((*head) == NULL) //若是結構這的next指針爲空,那麼代表已經初始化完成;剛剛這裏寫成了 != 致使在插入數據的時候head->next訪問不了 11 return; 12 *head = (linkList*)malloc(sizeof(linkList)); //給結構分配足夠的內存空間 13 (*head)->Element = 0; 14 (*head)->next = NULL; //head此時便是頭節點也是尾節點,由於此時head指向了NULL 15 } 16 17 /* 18 01)鏈表的銷燬 19 02)鏈表全部節點包括頭結點都是動態申請的堆空間,使用完畢後必須手動釋放,這裏的銷燬要把全部的節點空間所有釋放; 20 03)方法一:從鏈表頭開始遍歷,也就是從前向後逐個釋放每個節點的空間 21 */ 22 void destroylinkListByHead(linkList** head) 23 { 24 linkList* header = (*head)->next; //因爲傳入的是頭結點,因此越過頭結點,保留頭結點 25 linkList* p; 26 cout << "開始刪除鏈表" << endl; 27 while ( header != NULL) //原來這裏的條件是(*head)!=NULL,致使p->next指向了空指針;或者是循環了無數次 28 { 29 p = header; //講當前數據節點保存下來 30 cout << "刪除數據: " << p->Element << endl; 31 header = p->next; //將下一個數據節點保存下來 32 free(p); //講當前節點空間釋放 33 } 34 free(header); //釋放頭節點 35 head = NULL; //空間釋放完的指針指向空指針 36 cout << "鏈表已被刪除完畢" << endl; 37 } 38 39 /* 40 01)方法二:從鏈表尾部向頭部開始銷燬,就不用臨時保存 41 02)用遞歸遍歷到最後一個結點,逐層向上返回,銷燬每個節點,順序就是從頭尾向頭結點的順序銷燬。 42 */ 43 void destroylinkListByTail(linkList** head) 44 { 45 if ((*head) == NULL) 46 return; 47 destroylinkListByTail(&((*head)->next)); //遞歸調用 48 free(*head); 49 head = NULL; 50 cout << "鏈表已被刪除完畢" << endl; 51 } 52 53 /* 54 01)向鏈表這插入數據 55 02)頭插法:每次在頭結點H的後面插入一個輸入的數據,鏈表中的數據順序和實際輸入順序相反 56 03)插入的過程主要是:先申請一個新的結點,鏈表不像數組一次性分配指定長度的空間, 57 鏈表是須要增加一個就再申請一份,而後連接起來。申請完了以後給節點賦值,讓新申請的節 58 點指向頭結點的next,也就是node->next = h->next,再讓頭結點指向這個新節點, 59 H->next = node就完成插入操做。 60 04)傳入的參數能夠是頭結點(頭節點指向的是NULL) 61 05)傳入的參數也能夠是一個linkList結構的地址 62 06)覺得此時是要向一個鏈表中插入數據,因此在使用malloc以後並無釋放內存 63 */ 64 void insertDatabyHead(linkList** head) 65 { 66 linkList* node; //新建一個須要插入的節點 67 int x; 68 cout << "請輸入數據(-1結束):" << endl; 69 cin >> x; 70 while (x != -1) 71 { 72 node = (linkList*) malloc(sizeof(linkList)); //爲須要插入的節點分配空間 73 node->Element = x; 74 //若是頭節點指向的是NULL,因此下面這一句node->next換成NULL也能夠 75 node->next = (*head)->next; //使node成爲head指向的一個節點以後的節點 76 (*head)->next = node; //使 77 cout << "請輸入數據(-1結束):" << endl; //接着輸入數據 78 cin >> x; 79 } 80 } 81 82 /* 83 01)向鏈表這插入數據 84 02)尾插法:每次插入新的數據在鏈表的尾部插入就行,鏈表中的數據順序和實際輸入順序相同 85 03)先找到鏈表的尾節點H->next == NULL,就是最後一個節點,一樣插入就行。相比頭插法, 86 尾插法插入數據的時候若是鏈表不是一條空鏈表,得遍歷先找到尾節點。 87 04)傳入的參數的頭結點(頭節點指向的是NULL) 88 05)輸入的參數是一個linkList結構的地址 89 */ 90 91 void insertDatabyTail(linkList** head) 92 { 93 linkList* node; 94 linkList* remove; 95 int x; 96 while ((*head)->next != NULL) //若是head不是尾節點,那麼找到尾節點,並使head成爲尾節點;尾節點指向NULL 97 (*head) = (*head)->next; 98 remove = (*head); //將head(尾節點)賦給remove,是remove也成爲尾節點 99 cout << "請輸入要插入的數據(-1結束): " << endl; 100 cin >> x; 101 while (x != -1) 102 { 103 node = (linkList*)malloc(sizeof(linkList)); 104 node->Element = x; 105 node->next = remove->next; //此處也可使用head->next,但使用remove是爲了循環大計 106 remove->next = node; //此處也可使用head->next,可是鏈表就是斷的了 107 remove = node; //爲下一次循環作準備 108 cout << "請輸入要插入的數據(-1結束): " << endl; 109 cin >> x; 110 } 111 } 112 113 /* 114 01)打印鏈表 115 02)輸入爲當前節點,或者是一個結構的地址 116 */ 117 118 void showlinkList(linkList** head) 119 { 120 linkList* header = *head; 121 if (header->next == NULL ) //若是當前節點是頭節點,則指向下一個節點;覺得頭節點是沒有數據的 122 header = header->next; 123 header = header->next; //不顯示頭結點中的元素;上面那個if確定不會被執行的,由於傳入的參數是頭結點,頭結點的下一個節點確定不是空(只要有數據) 124 while (header != NULL ) 125 { 126 cout << header->Element << endl; 127 header = header->next; //注意!!這裏已經將傳入的頭結點變成了NULL!!!!!且實參是頭結點的地址,因此會改變實參的值 128 } 129 } 130 131 /* 132 01)刪除第index個節點 133 */ 134 /*返回第index個節點*/ 135 linkList* indexof(linkList* head, int index) 136 { 137 linkList* p = head; 138 if (head->next == NULL) //(*head)->next == NULL 139 { 140 cout << "輸入的鏈表只有一個節點,且該節點爲尾節點" << endl; 141 return NULL; 142 } 143 int j; 144 for (j = 0; p != NULL && j < index; j++) //若是index等於1,則該for循環會忽略p=NULL的狀況 145 p = p->next; 146 return j == index ? p : NULL; 147 } 148 /*刪除第index個節點*/ 149 int deleteElementByIndex(linkList** head, int index) 150 { 151 linkList* p; 152 linkList* temp; 153 p = indexof(*head, index); //找到第index個節點 154 if (p == NULL) 155 { 156 cout << "要刪除的爲頭節點" << endl; 157 return false; 158 } 159 temp = index == 1 ? NULL : indexof(*head, index - 1); //找到要刪除節點的前一個節點(前驅節點) 160 temp->next = p->next; //讓要刪除節點的前驅節點指向要刪除節點的下一個節點 161 cout << "開始刪除第" << index << "個節點" << endl; 162 free(p); //釋放要刪除節點的內存 163 return true; 164 }
1 /*鏈表*/ 2 #include <iostream> 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 8 typedef int ElementType; 9 10 /*定義一個結構*/ 11 struct linkList 12 { 13 ElementType Element; //定義結構中的一個數據(數據域) 14 linkList* next; //定義指向下一個結構的指針(指針域) 15 }; 16 17 typedef struct linkList *PtrtoNode; //PtrtoNode是一個類型,能夠定義變量,且PtrtoNode是一個指針,指向結構體Node 18 typedef PtrtoNode List; //爲PtrtoNode起別名爲List 19 typedef PtrtoNode Position; //爲PtrtoNode起別名爲Position 20 21 void initlinkList(linkList** head); 22 void destroylinkListByHead(linkList** head); 23 void destroylinkListByTail(linkList** head); 24 void insertDatabyHead(linkList** head); 25 void insertDatabyTail(linkList** head); 26 void showlinkList(linkList** head); 27 linkList* indexof(linkList* head, int index); 28 int deleteElementByIndex(linkList** head, int index);
執行結果:
給每一個元素附加兩個指針域,一個存儲前一個元素的地址,一個存儲下一個元素的地址。這種鏈表稱爲雙向鏈表,以下圖所示:
初始化和建立雙向鏈表的代碼:
1 #pragma once 2 3 typedef int Type; 4 5 6 struct doubleLinklist 7 { 8 Type data; //存儲數據 9 doubleLinklist* prior; //前向指針 10 doubleLinklist* next; //後繼指針 11 }; 12 13 typedef struct doubleLinklist* PtrNode; 14 15 void initdoubleLinklist(doubleLinklist** head); 16 void creeatdoubleLinklist(doubleLinklist** head); //和單向鏈表的insert是同樣的,連續的插入並不僅是插入一個數據
1 #include <iostream> 2 #include "doubleLinkList.h" 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 8 void initdoubleLinklist(doubleLinklist** head) 9 { 10 if ((*head) == NULL) 11 return; 12 (*head) = new doubleLinklist; 13 (*head)->data = 0; 14 (*head)->prior = NULL; 15 (*head)->next = NULL; 16 } 17 void creeatdoubleLinklist(doubleLinklist** head) 18 { 19 doubleLinklist* node; 20 cout << "請輸入一個Type類型的數據(-1結束): " << endl; 21 Type x; 22 cin >> x; 23 while (x != -1) 24 { 25 node = new doubleLinklist; 26 node->data = x; 27 if ((*head)->next != NULL) 28 (*head)->next->prior = node; 29 node->next = (*head)->next; 30 node->prior = (*head); 31 (*head)->next = node; 32 cout << "請輸入一個Type類型的數據(-1結束): " << endl; 33 cin >> x; 34 } 35 }
1 /*雙向鏈表測試*/ 2 #include <iostream> //for system() 3 #include "doubleLinkList.h" 4 5 void showAll(doubleLinklist** head) 6 { 7 doubleLinklist* header = (*head)->next; //越過頭節點 8 while (header != NULL) 9 { 10 cout << header->data << endl; 11 header = header->next; 12 } 13 } 14 15 int main() 16 { 17 doubleLinklist* PtrLinklist; 18 initdoubleLinklist(&PtrLinklist); 19 creeatdoubleLinklist(&PtrLinklist); 20 showAll(&PtrLinklist); 21 22 system("pause"); 23 return 0; 24 }
運行結果:
「在鏈表的第i個位置插入數據data」的插入過程其實和建立鏈表插入第2個數據步驟是同樣的,具體參考圖
1 #pragma once 2 3 typedef int Type; 4 5 6 struct doubleLinklist 7 { 8 Type data; //存儲數據 9 doubleLinklist* prior; //前向指針 10 doubleLinklist* next; //後繼指針 11 }; 12 13 typedef struct doubleLinklist* PtrNode; 14 15 void initDULinklist(doubleLinklist** head); 16 void creeatDULinklistByHead(doubleLinklist** head); //和單向鏈表的insert是同樣的,連續的插入並不僅是插入一個數據 17 void insertToDULinkList(doubleLinklist** head, int i, int data); 18 19 void showAllByNext(doubleLinklist** head);
1 #include <iostream> 2 #include "doubleLinkList.h" 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 8 /*雙向鏈表初始化*/ 9 void initDULinklist(doubleLinklist** head) 10 { 11 if ((*head) == NULL) 12 return; 13 (*head) = new doubleLinklist; 14 (*head)->data = 0; 15 (*head)->prior = NULL; 16 (*head)->next = NULL; 17 } 18 19 /*頭插入創造雙向鏈表*/ 20 void creeatDULinklistByHead(doubleLinklist** head) 21 { 22 doubleLinklist* node; 23 cout << "請輸入一個您設置類型的數據(-1結束): " << endl; 24 Type x; 25 cin >> x; 26 while (x != -1) 27 { 28 node = new doubleLinklist; 29 node->data = x; 30 if ((*head)->next != NULL) 31 (*head)->next->prior = node; 32 node->next = (*head)->next; 33 node->prior = (*head); 34 (*head)->next = node; 35 cout << "請輸入一個Type類型的數據(-1結束): " << endl; 36 cin >> x; 37 } 38 } 39 40 /*在鏈表的第i個位置插入數據data*/ 41 void insertToDULinkList(doubleLinklist** head, int i, int data) 42 { 43 doubleLinklist* header = (*head)->next; //越過頭節點 44 doubleLinklist* node; //建立新插入的節點 45 int j=1; 46 while (header != NULL && j < i) //找到第i個節點 47 { 48 header = header->next; 49 j++; 50 } 51 node = new doubleLinklist; //爲新建立的節點分配空間 52 node->data = data; 53 header->next->prior = node; 54 node->next = header->next; 55 node->prior = header; 56 header->next = node; 57 } 58 59 void showAllByNext(doubleLinklist** head) 60 { 61 doubleLinklist* header = (*head)->next; //越過頭節點 62 while (header != NULL) 63 { 64 cout << header->data << endl; 65 header = header->next; 66 } 67 }
1 //#include "stacktp1.h" 2 // 3 //int main() 4 //{ 5 // linkList* linkPtr; //建立鏈表的頭結點 6 // initlinkList(&linkPtr); 7 // insertDatabyTail(&linkPtr); 8 // showlinkList(&linkPtr); //此句已經使linkPt成爲了尾節點,因此執行下一句會報錯 9 // deleteElementByIndex(&linkPtr,5); //刪除頭結點爲linkPtr,鏈表中第二個數 10 // showlinkList(&linkPtr); //此句已經使linkPt成爲了尾節點,因此不會執行下一個函數中的while循環,即不會刪除鏈表 11 // destroylinkListByTail(&linkPtr); 12 // 13 // system("pause"); 14 // return 0; 15 //} 16 // 17 18 /*最大堆測試*/ 19 //#include "PriorityQueue.h" 20 // 21 //int main() 22 //{ 23 // { 24 // int arr[] = { 37,26,14,52,69,78,98,48,69,70 }; 25 // int n = sizeof(arr) / sizeof(arr[0]); //獲取數組元素個數的新方法 26 // Heap<int>* heap = new Heap<int>(20); //新建指向類模板的指針,不新建指針也是能夠的如Heap<int> heap(20); 27 // for (int i = 0; i < n; i++) 28 // { 29 // heap->insert(arr[i]); 30 // } 31 // heap->showHeap(); 32 // cout << endl; 33 // 34 // cout << "添加元素100" << endl; 35 // heap->insert(100); 36 // heap->showHeap(); 37 // cout << endl; 38 // 39 // cout << "刪除元素78" << endl; 40 // heap->remove(78); 41 // heap->showHeap(); 42 // } 43 // 44 // system("pause"); 45 // return 0; 46 //} 47 48 //#include <iostream> 49 //#include <cstdio> 50 //#include <queue> 51 // 52 //using namespace std; 53 // 54 //int main() 55 //{ 56 // priority_queue<int> q; 57 // int arr[] = { 37,26,14,52,69,78,98,48,69,70 }; 58 // int n = sizeof(arr) / sizeof(arr[0]); //獲取數組元素個數的新方法 59 // for (int i = 0; i < n; i++) 60 // { 61 // q.push(arr[i]); 62 // } 63 // while (!q.empty()) 64 // { 65 // cout << q.top() << " " << endl; 66 // q.pop(); 67 // } 68 // 69 // system("pause"); 70 // return 0; 71 //} 72 73 //#include <iostream> 74 // 75 //using std::cout; 76 //using std::endl; 77 // 78 //int main() 79 //{ 80 // int i = 8; 81 // int arr[] = { 1,2,3,4,5,6,7,8,9 }; 82 // 83 // //cout << arr[i--] << endl; //打印9 先使用後修改 84 // //cout << arr[i--] << endl; //打印8 85 // 86 // //cout << arr[--i] << endl; //打印8 先修改後使用 87 // //cout << arr[--i] << endl; //打印7 88 // //cout << endl; 89 // //cout << i; //此時i=6 90 // 91 // int c[] = { 2,3,4,5 }; 92 // int j, *p = c, *q = c; 93 // for (j = 0; j < 4; j++) 94 // { 95 // printf(" %d", *c); 96 // ++q; 97 // } 98 // for (j = 0; j < 4; j++) 99 // { 100 // printf(" %d", *p); 101 // ++p; 102 // } 103 // 104 // system("pause"); 105 // return 0; 106 //} 107 108 //#include "queue.h" 109 // 110 //int main() 111 //{ 112 // int x; 113 // int temp; 114 // int size = 6; 115 // Queue<int>* queue = new Queue<int>(size); 116 // cout << "請輸入一個整數,按字母q結束:"; 117 // cin >> x; 118 // while (x != 0) 119 // { 120 // queue->enqueue(x); 121 // cout << "請輸入一個整數,按字母q結束:"; 122 // cin >> x; 123 // } 124 // cout << "隊中元素個數爲:" << queue->queueLength() << endl; 125 // int n = queue->queueLength(); 126 // for (int i = 0; i <= n; i++) 127 // { 128 // queue->dequeue(temp); 129 // cout << "出隊的元素是:" << temp << endl; 130 // } 131 // /*queue->dequeue(temp); 132 // cout << "出隊的元素是:" << temp << endl; 133 // queue->dequeue(temp); 134 // cout << "出隊的元素是:" << temp << endl; 135 // queue->dequeue(temp); 136 // cout << "出隊的元素是:" << temp << endl; 137 // queue->dequeue(temp); 138 // cout << "出隊的元素是:" << temp << endl; 139 // queue->dequeue(temp); 140 // cout << "出隊的元素是:" << temp << endl; 141 // queue->dequeue(temp); 142 // cout << "出隊的元素是:" << temp << endl; 143 // 144 // queue->dequeue(temp); 145 // cout << "出隊的元素是:" << temp << endl;*/ 146 // 147 // system("pause"); 148 // return 0; 149 //} 150 151 //#include "queue.h" 152 // 153 //int main() 154 //{ 155 // int x; 156 // int temp; 157 // int size = 6; 158 // Queue<int>* queue = new Queue<int>(size); 159 // cout << "請輸入一個整數,按字母q結束:"; 160 // cin >> x; 161 // queue->enqueue(x); 162 // cout << "請輸入一個整數,按字母q結束:"; 163 // cin >> x; 164 // queue->enqueue(x); 165 // queue->dequeue(temp); 166 // cout << "出隊的元素是:" << temp << endl; 167 // queue->dequeue(temp); 168 // cout << "出隊的元素是:" << temp << endl; 169 // 170 // system("pause"); 171 // return 0; 172 //} 173 174 /*雙向鏈表測試*/ 175 #include <iostream> //for system() 176 #include "doubleLinkList.h" 177 178 using std::cout; 179 using std::endl; 180 181 int main() 182 { 183 doubleLinklist* PtrLinklist; 184 initDULinklist(&PtrLinklist); 185 creeatDULinklistByHead(&PtrLinklist); 186 showAllByNext(&PtrLinklist); 187 cout << "開始插入數據" << endl; 188 insertToDULinkList(&PtrLinklist, 2, 45); 189 showAllByNext(&PtrLinklist); 190 191 system("pause"); 192 return 0; 193 }
運行結果(該方法是先的是在第二個節點以後插入新數據,把3所在的節點當作是第一個節點):
刪除一個結點,其實是把這個結點跳過去。要想跳過第i個結點,能夠先找到第i個結點。而後修改指針,如圖:
1 #pragma once 2 3 typedef int Type; 4 5 6 struct doubleLinklist 7 { 8 Type data; //存儲數據 9 doubleLinklist* prior; //前向指針 10 doubleLinklist* next; //後繼指針 11 }; 12 13 typedef struct doubleLinklist* PtrNode; 14 15 void initDULinklist(doubleLinklist** head); 16 void creeatDULinklistByHead(doubleLinklist** head); //和單向鏈表的insert是同樣的,連續的插入並不僅是插入一個數據 17 void insertToDULinkList(doubleLinklist** head, int i, int data); 18 void deleteOneNode(doubleLinklist** head, int i); //刪除第i個節點 19 20 void showAllByNext(doubleLinklist** head);
1 #include <iostream> 2 #include "doubleLinkList.h" 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 8 /*雙向鏈表初始化*/ 9 void initDULinklist(doubleLinklist** head) 10 { 11 if ((*head) == NULL) 12 return; 13 (*head) = new doubleLinklist; 14 (*head)->data = 0; 15 (*head)->prior = NULL; 16 (*head)->next = NULL; 17 } 18 19 /*頭插入創造雙向鏈表*/ 20 void creeatDULinklistByHead(doubleLinklist** head) 21 { 22 doubleLinklist* node; 23 cout << "請輸入一個您設置類型的數據(-1結束): "; 24 Type x; 25 cin >> x; 26 while (x != -1) 27 { 28 node = new doubleLinklist; 29 node->data = x; 30 if ((*head)->next != NULL) 31 (*head)->next->prior = node; 32 node->next = (*head)->next; 33 node->prior = (*head); 34 (*head)->next = node; 35 cout << "請輸入一個您設置類型的數據(-1結束): "; 36 cin >> x; 37 } 38 } 39 40 /*在鏈表的第i個位置插入數據data*/ 41 void insertToDULinkList(doubleLinklist** head, int i, int data) 42 { 43 doubleLinklist* header = (*head)->next; //越過頭節點 此時header是第一個節點,因此j=1 44 doubleLinklist* node; //建立新插入的節點 45 int j=1; 46 while (header != NULL && j < i) //找到第i個節點 47 { 48 header = header->next; 49 j++; 50 } 51 node = new doubleLinklist; //爲新建立的節點分配空間 52 node->data = data; 53 header->next->prior = node; 54 node->next = header->next; 55 node->prior = header; 56 header->next = node; 57 } 58 59 /*刪除第i個節點*/ 60 void deleteOneNode(doubleLinklist** head, int i) 61 { 62 doubleLinklist* header = (*head)->next; //越過頭節點(第0個節點) 63 int j = 1; // 64 while (header != NULL && j < i) //找到第i個節點 65 { 66 header = header->next; 67 j++; 68 } 69 header->next->prior = header->prior; 70 header->prior->next = header->next; 71 delete header; //刪除第i個節點 72 } 73 74 void showAllByNext(doubleLinklist** head) 75 { 76 doubleLinklist* header = (*head)->next; //越過頭節點 77 while (header != NULL) 78 { 79 cout << header->data << endl; 80 header = header->next; 81 } 82 }
1 //#include "stacktp1.h" 2 // 3 //int main() 4 //{ 5 // linkList* linkPtr; //建立鏈表的頭結點 6 // initlinkList(&linkPtr); 7 // insertDatabyTail(&linkPtr); 8 // showlinkList(&linkPtr); //此句已經使linkPt成爲了尾節點,因此執行下一句會報錯 9 // deleteElementByIndex(&linkPtr,5); //刪除頭結點爲linkPtr,鏈表中第二個數 10 // showlinkList(&linkPtr); //此句已經使linkPt成爲了尾節點,因此不會執行下一個函數中的while循環,即不會刪除鏈表 11 // destroylinkListByTail(&linkPtr); 12 // 13 // system("pause"); 14 // return 0; 15 //} 16 // 17 18 /*最大堆測試*/ 19 //#include "PriorityQueue.h" 20 // 21 //int main() 22 //{ 23 // { 24 // int arr[] = { 37,26,14,52,69,78,98,48,69,70 }; 25 // int n = sizeof(arr) / sizeof(arr[0]); //獲取數組元素個數的新方法 26 // Heap<int>* heap = new Heap<int>(20); //新建指向類模板的指針,不新建指針也是能夠的如Heap<int> heap(20); 27 // for (int i = 0; i < n; i++) 28 // { 29 // heap->insert(arr[i]); 30 // } 31 // heap->showHeap(); 32 // cout << endl; 33 // 34 // cout << "添加元素100" << endl; 35 // heap->insert(100); 36 // heap->showHeap(); 37 // cout << endl; 38 // 39 // cout << "刪除元素78" << endl; 40 // heap->remove(78); 41 // heap->showHeap(); 42 // } 43 // 44 // system("pause"); 45 // return 0; 46 //} 47 48 //#include <iostream> 49 //#include <cstdio> 50 //#include <queue> 51 // 52 //using namespace std; 53 // 54 //int main() 55 //{ 56 // priority_queue<int> q; 57 // int arr[] = { 37,26,14,52,69,78,98,48,69,70 }; 58 // int n = sizeof(arr) / sizeof(arr[0]); //獲取數組元素個數的新方法 59 // for (int i = 0; i < n; i++) 60 // { 61 // q.push(arr[i]); 62 // } 63 // while (!q.empty()) 64 // { 65 // cout << q.top() << " " << endl; 66 // q.pop(); 67 // } 68 // 69 // system("pause"); 70 // return 0; 71 //} 72 73 //#include <iostream> 74 // 75 //using std::cout; 76 //using std::endl; 77 // 78 //int main() 79 //{ 80 // int i = 8; 81 // int arr[] = { 1,2,3,4,5,6,7,8,9 }; 82 // 83 // //cout << arr[i--] << endl; //打印9 先使用後修改 84 // //cout << arr[i--] << endl; //打印8 85 // 86 // //cout << arr[--i] << endl; //打印8 先修改後使用 87 // //cout << arr[--i] << endl; //打印7 88 // //cout << endl; 89 // //cout << i; //此時i=6 90 // 91 // int c[] = { 2,3,4,5 }; 92 // int j, *p = c, *q = c; 93 // for (j = 0; j < 4; j++) 94 // { 95 // printf(" %d", *c); 96 // ++q; 97 // } 98 // for (j = 0; j < 4; j++) 99 // { 100 // printf(" %d", *p); 101 // ++p; 102 // } 103 // 104 // system("pause"); 105 // return 0; 106 //} 107 108 //#include "queue.h" 109 // 110 //int main() 111 //{ 112 // int x; 113 // int temp; 114 // int size = 6; 115 // Queue<int>* queue = new Queue<int>(size); 116 // cout << "請輸入一個整數,按字母q結束:"; 117 // cin >> x; 118 // while (x != 0) 119 // { 120 // queue->enqueue(x); 121 // cout << "請輸入一個整數,按字母q結束:"; 122 // cin >> x; 123 // } 124 // cout << "隊中元素個數爲:" << queue->queueLength() << endl; 125 // int n = queue->queueLength(); 126 // for (int i = 0; i <= n; i++) 127 // { 128 // queue->dequeue(temp); 129 // cout << "出隊的元素是:" << temp << endl; 130 // } 131 // /*queue->dequeue(temp); 132 // cout << "出隊的元素是:" << temp << endl; 133 // queue->dequeue(temp); 134 // cout << "出隊的元素是:" << temp << endl; 135 // queue->dequeue(temp); 136 // cout << "出隊的元素是:" << temp << endl; 137 // queue->dequeue(temp); 138 // cout << "出隊的元素是:" << temp << endl; 139 // queue->dequeue(temp); 140 // cout << "出隊的元素是:" << temp << endl; 141 // queue->dequeue(temp); 142 // cout << "出隊的元素是:" << temp << endl; 143 // 144 // queue->dequeue(temp); 145 // cout << "出隊的元素是:" << temp << endl;*/ 146 // 147 // system("pause"); 148 // return 0; 149 //} 150 151 //#include "queue.h" 152 // 153 //int main() 154 //{ 155 // int x; 156 // int temp; 157 // int size = 6; 158 // Queue<int>* queue = new Queue<int>(size); 159 // cout << "請輸入一個整數,按字母q結束:"; 160 // cin >> x; 161 // queue->enqueue(x); 162 // cout << "請輸入一個整數,按字母q結束:"; 163 // cin >> x; 164 // queue->enqueue(x); 165 // queue->dequeue(temp); 166 // cout << "出隊的元素是:" << temp << endl; 167 // queue->dequeue(temp); 168 // cout << "出隊的元素是:" << temp << endl; 169 // 170 // system("pause"); 171 // return 0; 172 //} 173 174 /*雙向鏈表測試*/ 175 #include <iostream> //for system() 176 #include "doubleLinkList.h" 177 178 using std::cout; 179 using std::endl; 180 181 int main() 182 { 183 doubleLinklist* PtrLinklist; 184 initDULinklist(&PtrLinklist); 185 creeatDULinklistByHead(&PtrLinklist); 186 showAllByNext(&PtrLinklist); 187 188 cout << "開始插入數據" << endl; 189 insertToDULinkList(&PtrLinklist, 2, 45); 190 showAllByNext(&PtrLinklist); 191 192 cout << "開始刪除第1個節點" << endl; 193 deleteOneNode(&PtrLinklist, 1); 194 showAllByNext(&PtrLinklist); 195 196 cout << "再刪除第2個節點" << endl; 197 deleteOneNode(&PtrLinklist, 2); 198 showAllByNext(&PtrLinklist); 199 200 201 system("pause"); 202 return 0; 203 }
運行結果:
刪除元素藉鑑了單向鏈表刪除全部元素的方法
1 #pragma once 2 3 typedef int Type; 4 5 6 struct doubleLinklist 7 { 8 Type data; //存儲數據 9 doubleLinklist* prior; //前向指針 10 doubleLinklist* next; //後繼指針 11 }; 12 13 typedef struct doubleLinklist* PtrNode; 14 15 void initDULinklist(doubleLinklist** head); 16 void creeatDULinklistByHead(doubleLinklist** head); //和單向鏈表的insert是同樣的,連續的插入並不僅是插入一個數據 17 void insertToDULinkList(doubleLinklist** head, int i, int data); 18 void deleteOneNode(doubleLinklist** head, int i); //刪除第i個節點 19 void deleteAll(doubleLinklist** head); //刪除全部節點 20 21 void showAllByNext(doubleLinklist** head);
1 #include <iostream> 2 #include "doubleLinkList.h" 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 8 /*雙向鏈表初始化*/ 9 void initDULinklist(doubleLinklist** head) 10 { 11 if ((*head) == NULL) 12 return; 13 (*head) = new doubleLinklist; 14 (*head)->data = 0; 15 (*head)->prior = NULL; 16 (*head)->next = NULL; 17 } 18 19 /*頭插入創造雙向鏈表*/ 20 void creeatDULinklistByHead(doubleLinklist** head) 21 { 22 doubleLinklist* node; 23 cout << "請輸入一個您設置類型的數據(-1結束): "; 24 Type x; 25 cin >> x; 26 while (x != -1) 27 { 28 node = new doubleLinklist; 29 node->data = x; 30 if ((*head)->next != NULL) 31 (*head)->next->prior = node; 32 node->next = (*head)->next; 33 node->prior = (*head); 34 (*head)->next = node; 35 cout << "請輸入一個您設置類型的數據(-1結束): "; 36 cin >> x; 37 } 38 } 39 40 /*在鏈表的第i個位置插入數據data*/ 41 void insertToDULinkList(doubleLinklist** head, int i, int data) 42 { 43 doubleLinklist* header = (*head)->next; //越過頭節點 此時header是第一個節點,因此j=1 44 doubleLinklist* node; //建立新插入的節點 45 int j=1; 46 while (header != NULL && j < i) //找到第i個節點 47 { 48 header = header->next; 49 j++; 50 } 51 node = new doubleLinklist; //爲新建立的節點分配空間 52 node->data = data; 53 header->next->prior = node; 54 node->next = header->next; 55 node->prior = header; 56 header->next = node; 57 } 58 59 /*刪除第i個節點*/ 60 void deleteOneNode(doubleLinklist** head, int i) 61 { 62 doubleLinklist* header = (*head)->next; //越過頭節點(第0個節點) 63 int j = 1; // 64 while (header != NULL && j < i) //找到第i個節點 65 { 66 header = header->next; 67 j++; 68 } 69 header->next->prior = header->prior; 70 header->prior->next = header->next; 71 delete header; //刪除第i個節點 72 } 73 74 /*刪除全部節點*/ 75 void deleteAll(doubleLinklist** head) 76 { 77 doubleLinklist* header = (*head)->next; 78 doubleLinklist* p; 79 while (header != NULL) 80 { 81 p = header; //必須找一箇中間變量,不然會發生訪問權限錯誤 82 cout << "刪除元素: " << p->data <<endl; 83 header = p->next; 84 delete(p); 85 } 86 delete(header); //刪除頭結點 87 cout << "全部節點刪除完畢" << endl; 88 } 89 90 void showAllByNext(doubleLinklist** head) 91 { 92 doubleLinklist* header = (*head)->next; //越過頭節點 93 while (header != NULL) 94 { 95 cout << header->data << endl; 96 header = header->next; 97 } 98 }
1 /*雙向鏈表測試*/ 2 #include <iostream> //for system() 3 #include "doubleLinkList.h" 4 5 using std::cout; 6 using std::endl; 7 8 int main() 9 { 10 doubleLinklist* PtrLinklist; 11 initDULinklist(&PtrLinklist); 12 creeatDULinklistByHead(&PtrLinklist); 13 showAllByNext(&PtrLinklist); 14 15 cout << "開始插入數據" << endl; 16 insertToDULinkList(&PtrLinklist, 2, 45); 17 showAllByNext(&PtrLinklist); 18 19 cout << "開始刪除第1個節點" << endl; 20 deleteOneNode(&PtrLinklist, 1); 21 showAllByNext(&PtrLinklist); 22 23 cout << "再刪除第2個節點" << endl; 24 deleteOneNode(&PtrLinklist, 2); 25 showAllByNext(&PtrLinklist); 26 27 deleteAll(&PtrLinklist); 28 29 30 system("pause"); 31 return 0; 32 }
運行結果:
1 #include <iostream> 2 #include "doubleLinkList.h" 3 4 using std::cin; 5 using std::cout; 6 using std::endl; 7 8 /*雙向鏈表初始化*/ 9 void initDULinklist(doubleLinklist** head) 10 { 11 if ((*head) == NULL) 12 return; 13 (*head) = new doubleLinklist; 14 (*head)->data = 0; 15 (*head)->prior = NULL; 16 (*head)->next = NULL; 17 } 18 19 /*頭插入創造雙向鏈表*/ 20 void creeatDULinklistByHead(doubleLinklist** head) 21 { 22 doubleLinklist* node; 23 cout << "請輸入一個您設置類型的數據(-1結束): "; 24 Type x; 25 cin >> x; 26 while (x != -1) 27 { 28 node = new doubleLinklist; 29 node->data = x; 30 if ((*head)->next != NULL) 31 (*head)->next->prior = node; 32 node->next = (*head)->next; 33 node->prior = (*head); 34 (*head)->next = node; 35 cout << "請輸入一個您設置類型的數據(-1結束): "; 36 cin >> x; 37 } 38 } 39 40 /*在鏈表的第i個位置插入數據data*/ 41 void insertToDULinkList(doubleLinklist** head, int i, int data) 42 { 43 doubleLinklist* header = (*head)->next; //越過頭節點 此時header是第一個節點,因此j=1 44 doubleLinklist* node; //建立新插入的節點 45 int j=1; 46 while (header != NULL && j < i) //找到第i個節點 47 { 48 header = header->next; 49 j++; 50 } 51 node = new doubleLinklist; //爲新建立的節點分配空間 52 node->data = data; 53 header->next->prior = node; 54 node->next = header->next; 55 node->prior = header; 56 header->next = node; 57 } 58 59 /*刪除第i個節點*/ 60 void deleteOneNode(doubleLinklist** head, int i) 61 { 62 doubleLinklist* header = (*head)->next; //越過頭節點(第0個節點) 63 int j = 1; // 64 while (header != NULL && j < i) //找到第i個節點 65 { 66 header = header->next; 67 j++; 68 } 69 if (header->next == NULL) 70 { 71 cout << "deleteOneNode()子程序中出現了header->next=NULL的狀況!" << endl; 72 return; //退出程序 73 } 74 header->next->prior = header->prior; 75 header->prior->next = header->next; 76 delete header; //刪除第i個節點 77 } 78 79 /*刪除全部節點*/ 80 void deleteAll(doubleLinklist** head) 81 { 82 doubleLinklist* header = (*head)->next; 83 doubleLinklist* p; 84 while (header != NULL) 85 { 86 p = header; //必須找一箇中間變量,不然會發生訪問權限錯誤 87 cout << "刪除元素: " << p->data <<endl; 88 header = p->next; 89 delete(p); 90 } 91 delete(header); //刪除頭結點 92 cout << "全部節點刪除完畢" << endl; 93 } 94 95 void showAllByNext(doubleLinklist** head) 96 { 97 doubleLinklist* header = (*head)->next; //越過頭節點 98 while (header != NULL) 99 { 100 cout << header->data << ", "; 101 header = header->next; 102 } 103 cout << endl; 104 } 105 106 void showAllByPrior(doubleLinklist** head) 107 { 108 doubleLinklist* header = *head; 109 while (header->next != NULL) //找到尾節點(使header成爲尾結點) 110 header = header->next; 111 while (header->prior != NULL) //不顯示頭結點的數據 112 { 113 cout << header->data <<", "; 114 header = header->prior; 115 } 116 cout << endl; 117 }
1 #pragma once 2 3 typedef int Type; 4 5 6 struct doubleLinklist 7 { 8 Type data; //存儲數據 9 doubleLinklist* prior; //前向指針 10 doubleLinklist* next; //後繼指針 11 }; 12 13 typedef struct doubleLinklist* PtrNode; 14 15 void initDULinklist(doubleLinklist** head); 16 void creeatDULinklistByHead(doubleLinklist** head); //和單向鏈表的insert是同樣的,連續的插入並不僅是插入一個數據 17 void insertToDULinkList(doubleLinklist** head, int i, int data); 18 void deleteOneNode(doubleLinklist** head, int i); //刪除第i個節點 19 void deleteAll(doubleLinklist** head); //刪除全部節點 20 21 void showAllByNext(doubleLinklist** head); 22 void showAllByPrior(doubleLinklist** head);
1 /*雙向鏈表測試*/ 2 #include <iostream> //for system() 3 #include "doubleLinkList.h" 4 5 using std::cout; 6 using std::endl; 7 8 int main() 9 { 10 doubleLinklist* PtrLinklist; 11 initDULinklist(&PtrLinklist); 12 creeatDULinklistByHead(&PtrLinklist); 13 showAllByPrior(&PtrLinklist); 14 15 cout << "在第二個節點後插入數據" << endl; 16 insertToDULinkList(&PtrLinklist, 2, 45); 17 showAllByPrior(&PtrLinklist); 18 19 cout << "刪除第1個節點" << endl; 20 deleteOneNode(&PtrLinklist, 1); 21 showAllByPrior(&PtrLinklist); 22 23 cout << "刪除第2個節點" << endl; 24 deleteOneNode(&PtrLinklist, 2); 25 showAllByPrior(&PtrLinklist); 26 27 deleteAll(&PtrLinklist); 28 29 30 system("pause"); 31 return 0; 32 }
測試結果:
1 #include <iostream> 2 3 using std::cout; 4 using std::endl; 5 6 int main() 7 { 8 int i = 8; 9 int arr[] = { 1,2,3,4,5,6,7,8,9 }; 10 11 //cout << arr[i--] << endl; //打印9 先使用後修改 12 //cout << arr[i--] << endl; //打印8 13 14 cout << arr[--i] << endl; //打印8 先修改後使用 15 cout << arr[--i] << endl; //打印7 16 cout << endl; 17 cout << i; //此時i=6 18 19 system("pause"); 20 return 0; 21 }
最大堆:父結點的鍵值老是大於或等於任何一個子節點的鍵值;
最小堆:父結點的鍵值老是小於或等於任何一個子節點的鍵值;
1 /*最大堆的實現*/ 2 #pragma once 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 template<class Type> 9 class Heap 10 { 11 private: 12 Type* array; //存放數據的堆矩陣 13 int totalsize; //能夠存放的總的數據個數 14 int currentsize; //目前數據個數的索引 15 void filterDown(int start, int end); //刪除數據使用下濾方法 16 void filterUp(int start); //插入數據使用上濾方法 17 public: 18 Heap(int size = 30); //默認堆大小爲30 19 ~Heap(); 20 int getIndex(Type data); //獲取data在堆內的索引 21 int insert(Type data); 22 int remove(Type data); 23 void showHeap(); 24 }; 25 26 template<class Type> 27 Heap<Type>::Heap(int size) 28 { 29 array = new Type[totalsize]; //爲堆(數組分配空間) 30 totalsize = size; 31 currentsize = 0; 32 } 33 34 template<class Type> 35 Heap<Type>::~Heap() 36 { 37 totalsize = 0; 38 currentsize = 0; 39 delete[] array; 40 } 41 42 template <class Type> 43 int Heap<Type>::getIndex(Type data) 44 { 45 for (int i = 0; i < currentsize; i++) 46 { 47 if (array[i] == data) 48 return i; 49 } 50 return -1; //沒有在堆array中找到data則返回-1 51 } 52 53 template <class Type> 54 int Heap<Type>::insert(Type data) //data即爲要插入的數據 55 { 56 if (currentsize == totalsize) //判斷堆是否已滿 57 return -1; 58 array[currentsize] = data; //將新插入的數據data先存入array數組的最後,注crrentsize是從0開始 59 filterUp(currentsize); 60 currentsize++; 61 return 0; 62 } 63 64 template <class Type> 65 void Heap<Type>::filterUp(int start) 66 { 67 int i = start; //將傳入的當前索引值傳遞給i 68 int p = (i - 1) / 2; //獲取索引爲i節點的父節點(根節點的索引從0開始) 69 Type temp = array[i]; //將要插入的元素值賦給temp 70 while (i > 0) 71 { 72 if (array[p] >= temp) //因爲實現的是最大堆,節點比左右字樹值都是要大的 73 break; 74 else 75 { 76 array[i] = array[p]; //將父節點的值向下移動,移到當前新插入的元素的位置 77 i = p; //再沿着新插入節點的父節點爲基礎向上查找 78 p = (i - 1) / 2; //找到索引爲i的節點的父節點 79 } 80 } 81 array[i] = temp; //執行完while循環以後找到的i就是咱們要把元素插入的地方(索引) 82 } 83 84 template <class Type> 85 int Heap<Type>::remove(Type data) 86 { 87 if (currentsize == 0) 88 return -1; 89 int index = getIndex(data); //獲取要刪除元素的索引 90 if (index == -1) //若是沒有在隊列中找到data則getIndex()函數返回-1 91 return -1; 92 array[index] = array[--currentsize]; //將要刪除的位置用最後一個元素替換(由於在插入函數裏面插入元素後currentsize自加1,因此這裏要加1) 93 filterDown(index, currentsize - 1); //將隊列中倒數第二個元素的索引傳入 94 return 0; 95 } 96 97 template <class Type> 98 void Heap<Type>::filterDown(int start, int end) 99 { 100 int i = start; 101 int leftNode = 2 * i + 1; //索引爲i對應的左節點,右節點索引爲2*i+2 102 int temp = array[i]; //將最後一個元素(如今索引爲要刪除元素的索引)賦給一個臨時變量 103 while (leftNode <= end) 104 { 105 if (leftNode < end && array[leftNode] < array[leftNode + 1]) //leftNode+1則爲右節點了 106 leftNode = leftNode + 1; //若是左節點的值小於右節點的值,則讓左節點變成右節點 107 if (temp >= array[leftNode]) //若是最後一個元素(此時索引爲要刪除的元素的索引)大於左右節點中最大的一個節點,則退出循環 108 break; 109 else 110 { 111 array[i] = array[leftNode]; //將要刪除的元素下的左右節點中最大的一個節點替換掉最後一個元素 112 i = leftNode; //再以leftNode爲主節點,向下比較 113 leftNode = 2 * leftNode + 1; 114 } 115 } 116 array[i] = temp; //將隊列中最後一個值賦給通過第112行變換後、索引爲i的地方 117 } 118 119 template <class Type> 120 void Heap<Type>::showHeap() 121 { 122 for (int i = 0; i < currentsize; i++) 123 cout << array[i] << " " << endl; 124 }
1 /*最大堆測試*/ 2 #include "PriorityQueue.h" 3 4 int main() 5 { 6 { 7 int arr[] = { 37,26,14,52,69,78,98,48,69,70 }; 8 int n = sizeof(arr) / sizeof(arr[0]); //獲取數組元素個數的新方法 9 Heap<int>* heap = new Heap<int>(20); //新建指向類模板的指針,不新建指針也是能夠的如Heap<int> heap(20); 10 for (int i = 0; i < n; i++) 11 { 12 heap->insert(arr[i]); 13 } 14 heap->showHeap(); 15 cout << endl; 16 17 cout << "添加元素100" << endl; 18 heap->insert(100); 19 heap->showHeap(); 20 cout << endl; 21 22 cout << "刪除元素78" << endl; 23 heap->remove(78); 24 heap->showHeap(); 25 } 26 27 system("pause"); 28 return 0; 29 }
運行結果:
參考博客:https://blog.csdn.net/qq_37172182/article/details/88978808
插入優先隊列(堆)中的流程圖:
刪除寫了註釋,就沒有畫流程圖。。。腦補緣由吧~~哈哈
1 #pragma once 2 /*c語言實現優先隊列(堆)*/ 3 #include <iostream> 4 using std::cout; 5 using std::endl; 6 7 typedef int Type; 8 #define Mindata (-32767) 9 10 struct PriorQueue 11 { 12 int size; //堆當前元素數目 13 int capacity; //堆可容納最大元素數 14 Type* array; 15 }; 16 17 PriorQueue* initQueue(int maxElements); //優先隊列(堆)初始化,返回值爲一個指向結構的指針 18 bool isFull(PriorQueue* H); 19 bool isEmpty(PriorQueue* H); 20 void insert(PriorQueue** H, Type data); 21 Type deleteMinC(PriorQueue** H); 22 Type findMin(PriorQueue* H); 23 void destroy(PriorQueue** H); 24 void makeEmpty(PriorQueue** H);
1 /*C語言實現最小堆*/ 2 3 #include "PriorityQueueC.h" 4 5 /*C語言實現有限隊列初始化*/ 6 PriorQueue* initQueue(int maxElements) 7 { 8 PriorQueue* H = new PriorQueue; //爲結構分配空間 9 H->array = new Type[maxElements + 1]; //爲結構中的優先隊列(其實是一個數組)分配空間,因爲數組索引從0開始,而最開始的索引0是不用的,故要加1纔夠maxElements數目 10 H->size = 0; 11 H->capacity = maxElements; 12 H->array[0] = Mindata; //初始化優先隊列中第一個元素爲-32767 13 return H; 14 } 15 16 bool isFull(PriorQueue* H) 17 { 18 if (H->size == H->capacity) 19 return true; 20 else 21 return false; 22 } 23 bool isEmpty(PriorQueue* H) 24 { 25 if (H->size == 0) 26 return true; 27 else 28 return false; 29 } 30 31 /* 32 01)優先隊列(堆插入元素) 33 02)要向隊列中插入data,要首先將其插入到數組的新開闢的位置上,數組新開闢的位置索引是(H->size)+1 34 03)因爲根節點在數組內的索引是1,即第一個元素的索引爲1;(索引爲0的位置在初始化的時候已被佔用) 35 因此索引爲i的父節點索引爲i/2,左子節點索引爲2*i,右子節點索引爲2*i+1 36 04)首先爲新插入的數分配一個數組索引i,而後比較i的父節點和索引爲i的值的大小;若小於父節點則上去,不然不上去 37 */ 38 void insert(PriorQueue** H, Type data) 39 { 40 if (isFull(*H)) 41 { 42 cout << "優先隊列(堆)已滿!" << endl; 43 return; 44 } 45 (*H)->size = (*H)->size + 1; //爲要插入的數字新開闢一個空間(數組內索引加1) (*H)->size就相似於一個int型變量 46 int i; 47 for (i = (*H)->size; (*H)->array[i / 2] > data; i = i / 2) 48 (*H)->array[i] = (*H)->array[i / 2]; //若是父節點的值大於要插入的值,則將父節點的值插入到最後一個節點處(第一次循環) 49 (*H)->array[i] = data; //爲data找到一個合適的節點i 50 } 51 52 /* 53 01)刪除元素(堆排序) 54 02)不斷的去找一個節點i來存放堆內最後一個值,該節點i的特徵是:堆內最後一個值比i的左右節點處的值都小; 55 因此要先找出來節點i的左右節點中較小的那一個,而後再和堆內最後一個值比較; 56 03)要判斷堆中元素數目爲奇數仍是偶數,由於若是堆內元素數爲偶數,則有一個節點不存在右節點; 57 判斷方法爲:if (child != (*H)->size && (*H)->array[child] > (*H)->array[child + 1]) 58 (01)若是(*H)->size爲奇數,則child != (*H)->size恆成立(由於child=2*i);此時任何一個節點都存在左右節點; 59 (02)若是(*H)->size爲偶數,則當child=(*H)->size的時候,再也不執行後面的判斷,所以不會報錯。 60 */ 61 Type deleteMinC(PriorQueue** H) 62 { 63 if (isEmpty(*H)) 64 { 65 cout << "優先隊列(堆)已空!" << endl; 66 return (*H)->array[0]; //不能只寫一個return,是會報錯的;返回默認的元素就行了 67 } 68 int i, child; 69 Type lastData = (*H)->array[(*H)->size]; 70 Type minData = (*H)->array[1]; //先將最小的值保存起來,以避免後面被破壞 71 (*H)->size = (*H)->size - 1; //因爲是要刪除根節點的元素,因此堆內元素數是要減1的 72 for (i = 1; i * 2 <= (*H)->size; i = child) //從根節點開始,比較節點i的左右節點的大小,將較小的放入i的位置處 73 { 74 child = 2 * i; //節點i的左子節點 75 if (child != (*H)->size && (*H)->array[child] > (*H)->array[child + 1]) 76 child++; //若是左子節點的值大於右子節點的值,則讓child變成右子節點 77 if ((*H)->array[child] < lastData) 78 (*H)->array[i] = (*H)->array[child]; //若是節點i左右節點中較小的那一個比最後一個還要小,則讓節點i處放左右節點中較小的那一個值 79 else 80 break; //不然,結束循環,即找到了存放lastData的節點i 81 } 82 (*H)->array[i] = lastData; 83 return minData; 84 } 85 86 Type findMin(PriorQueue* H) 87 { 88 if (isEmpty(H)) 89 { 90 cout << "優先隊列(堆)已空!" << endl; 91 return 0; 92 } 93 else 94 return H->array[1]; 95 } 96 97 void makeEmpty(PriorQueue** H) 98 { 99 (*H)->size = 0; 100 } 101 102 void destroy(PriorQueue** H) 103 { 104 delete[](*H)->array; 105 delete (*H); 106 cout << "釋放空間完畢" << endl; 107 }
1 /*C語言實現最小堆測試*/ 2 #include "PriorityQueueC.h" 3 4 int main() 5 { 6 PriorQueue* Queue; 7 Queue = initQueue(10); 8 int ar[] = { 32, 21, 16, 24, 31, 19, 68, 65, 26, 13 }; 9 cout << "輸入的元素爲:" << endl; 10 for(int i = 0; i < 10; i++) 11 cout << ar[i] << ", "; 12 cout << endl; 13 14 cout << "將數組內元素插入到優先隊列(堆)中:" << endl; 15 for (int i = 0; i < 10; i++) 16 insert(&Queue, ar[i]); 17 for(int i=1;i<11;i++) 18 cout << Queue->array[i] << ", "; 19 cout << endl; 20 21 cout << "將優先隊列(堆)中的元素進行堆排序:" << endl; 22 for (int i = 0; i < 10; i++) 23 cout << deleteMinC(&Queue) << ", "; 24 cout << endl; 25 26 destroy(&Queue); //釋放空間 27 28 system("pause"); 29 return 0; 30 }
運行結果:
2019.10.04 下午
於 杭電 二教
隊列也是一種線性表,只不過它是操做受限的線性表,只能在兩端操做,先進先出(First In First Out,FIFO)。進的一端稱爲隊尾(rear),出的一端稱爲隊頭(front)。隊列能夠用順序存儲,也能夠用鏈式存儲。
1)開始時爲空隊,Q.front=Q.rear,如圖所示:
2)元素a1進隊,放入尾指針Q.rear(整型下標)的位置,Q.rear後移一位,如圖所示:
03)元素a2進隊,放入尾指針Q.rear(整型下標)的位置,Q.rear後移一位,如圖所示:
04)元素a3,a4,a5分別按順序進隊,尾指針Q.rear依次後移,如圖所示:
05)元素a1出隊,頭指針Q.front(整型下標)後移一位,如圖所示:
06)元素a2出隊,頭指針Q.front(整型下標)後移一位,如圖所示:
07)元素a6進隊,放入尾指針rear(整型下標)的位置,rear後移一位,如圖所示:
素a6進隊以後,尾指針Q.rear要後移一個位置,此時已經超過了數組的下標,即Q.rear+1=Maxsize(最大空間數6),那麼若是前面有空閒,Q.rear能夠轉向前面0的位置,如圖所示:
08)元素a7進隊,放入尾指針Q.rear(整型下標)的位置,Q.rear後移一位,如圖所示:
09)元素a8進隊,放入尾指針Q.rear(整型下標)的位置,Q.rear後移一位,如圖所示:
10)這時候雖然隊列空間存滿了,可是出現了一個大問題,隊滿時Q.front=Q.rear,這和隊空的條件如出一轍,沒法區分隊空仍是隊滿,如何解決呢?有兩種辦法:一是設置一個標誌,標記隊空和隊滿;另外一種辦法是浪費一個空間,當尾指針Q.rear的下一個位置Q.front是時,就認爲是隊滿。如圖所示:
此時認爲隊列已滿(浪費了一個空間)
循環隊列不管入隊仍是出隊,出隊或入隊以後,隊尾、隊頭加1後都要取模運算,例如入隊後隊尾後移一位:Q.rear =(Q.rear+1)%Maxsize。
爲何要使用Maxsize對(rear+1)取餘呢?
主要是爲了處理臨界狀態,即Q.rear向後移動一個位置Q.rear+1後,頗有可能超出了數組的下標,這時它的下一個位置實際上是0,若是將一維數組畫成環形圖,如圖所示:
所以不管是front仍是rear向後移動一個位置時,都要加1與最大空間Maxsize取模運算,處理臨界問題。
隊空:Q.front=Q.rear; // Q.rear和Q.front指向同一個位置
隊滿: (Q.rear+1) %Maxsize=Q.front; // Q.rear向後移一位正好是Q.front
入隊:
Q.base[Q.rear]=x; //將元素放入Q.rear所指空間,
Q.rear =( Q.rear+1) %Maxsize; // Q.rear向後移一位
出隊:
e= Q.base[Q.front]; //用變量記錄Q.front所指元素,
Q.front=(Q.front+1) %Maxsize // Q. front向後移一位
由於隊列是循環的,因此存在兩種狀況:
1) Q.rear>= Q.front,以下圖所示:
這種狀況隊列中元素個數爲:Q.rear-Q.front=4-1=3。
2) Q.rear< Q.front,以下圖所示:
此時,Q.rear=4,Q.front=Maxsize-2,Q.rear-Q.front=6-Maxsize。可是咱們能夠看到循環隊列中的元素實際上爲6個,那怎麼辦呢?當二者之差爲負數時,能夠將差值+Maxsize計算元素個數,即:Q.rear-Q.front+Maxsize=6-Maxsize+Maxsize =6,元素個數爲6。
那麼在計算元素個數時,能夠分兩種狀況判斷:
Q.rear>= Q.front:元素個數爲Q.rear-Q.front;
Q.rear<Q.front:元素個數爲Q.rear-Q.front+ Maxsize;
也能夠採用取模的方法把兩種狀況統一爲一個語句:
隊列中元素個數:(Q.rear-Q.front+Maxsize)% Maxsize
當Q.rear-Q.front爲負數時,加上Maxsize再取餘正好是元素個數,如(-2+6)%6=4;當Q.rear-Q.front爲正數時,加上Maxsize超過了最大空間數,取餘後正好是元素個數,如(3+6)%6=3。
1 #pragma once 2 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 using std::cin; 8 9 template <class Type> 10 class Queue 11 { 12 private: 13 Type* queue; 14 int rear; 15 int front; 16 int size; 17 public: 18 explicit Queue(int totalsize = 30); //隊列大小默認爲30 19 ~Queue(); 20 bool isEmpty(); 21 bool isFull(); 22 void enqueue(Type data); 23 void dequeue(Type & data); //data對應於主函數中的實參,用於顯示出隊的元素 24 Type getFront(); //取隊首元素 25 int queueLength(); //隊列中元素個數 26 /*void show();*/ 27 }; 28 29 /*隊列初始化*/ 30 template <class Type> 31 Queue<Type>::Queue(int totalsize) 32 { 33 queue = new Type[totalsize]; 34 size = totalsize; 35 front = 0; 36 rear = 0; 37 } 38 39 /*析構函數*/ 40 template <class Type> 41 Queue<Type>::~Queue() 42 { 43 delete[] queue; 44 size = rear = front = 0; 45 } 46 47 /*判斷隊列是否爲空*/ 48 template <class Type> 49 bool Queue<Type>::isEmpty() 50 { 51 if (front == rear) 52 return true; //若是爲空,則返回true 53 else 54 return false; 55 } 56 57 /*判斷隊列是否已滿*/ 58 template <class Type> 59 bool Queue<Type>::isFull() 60 { 61 if (front == (rear+1)%size) 62 return true; //若是已滿,則返回true 63 else 64 return false; 65 } 66 67 /*入隊*/ 68 template <class Type> 69 void Queue<Type>::enqueue(Type data) 70 { 71 if (isFull()) 72 { 73 cout << "The queue is full!" << endl; 74 return; 75 } 76 queue[rear] = data; //元素入隊 77 rear = (rear + 1) % size; //隊爲加1,爲防止溢出.rear加1後對size取餘 78 } 79 80 /* 81 01)出隊 82 02)有缺陷:隊列中最後一個元素不會出隊 83 */ 84 template <class Type> 85 void Queue<Type>::dequeue(Type & data) 86 { 87 if (isEmpty()) 88 { 89 cout << "The queue is empty!" << endl; 90 return; 91 } 92 data = queue[front]; //因爲形參是引用,因此形參的改變也會影響到實參,這裏是要引用的目的是便於顯示 93 front = (front + 1) % size; //將front加1,爲防止溢出.front加1後對size取餘 94 } 95 96 /*取隊首元素*/ 97 template <class Type> 98 Type Queue<Type>::getFront() 99 { 100 if (isEmpty()) 101 return 0; 102 else 103 return queue[front]; //返回隊首元素 104 } 105 106 /*返回隊列中元素個數*/ 107 template <class Type> 108 int Queue<Type>::queueLength() 109 { 110 return (((rear - front) + size) % size); 111 } 112 113 //template <class Type> 114 //void Queue<Type>::show() 115 //{ 116 // int n = queueLength(); 117 // for (int i = 0; i < n; i++) 118 // { 119 // cout << queue[i]; 120 // } 121 //}
1 #include "queue.h" 2 3 int main() 4 { 5 int x; 6 int temp; 7 int size = 6; 8 Queue<int>* queue = new Queue<int>(size); 9 cout << "請輸入一個整數,按字母q結束:"; 10 cin >> x; 11 while (x != 0) 12 { 13 queue->enqueue(x); 14 cout << "請輸入一個整數,按字母q結束:"; 15 cin >> x; 16 } 17 cout << "隊中元素個數爲:" << queue->queueLength() << endl; 18 for (int i = 0; i <= queue->queueLength(); i++) 19 { 20 queue->dequeue(temp); 21 cout << "出隊的元素是:" << temp << endl; 22 } 23 24 system("pause"); 25 return 0; 26 }
運行結果:
是for循環出了問題,不能使用函數queue->queueLength()寫在for循環裏邊
1 #include "queue.h" 2 3 int main() 4 { 5 int x; 6 int temp; 7 int size = 6; 8 Queue<int>* queue = new Queue<int>(size); 9 cout << "請輸入一個整數,按字母q結束:"; 10 cin >> x; 11 while (x != 0) 12 { 13 queue->enqueue(x); 14 cout << "請輸入一個整數,按字母q結束:"; 15 cin >> x; 16 } 17 cout << "隊中元素個數爲:" << queue->queueLength() << endl; 18 int n = queue->queueLength(); 19 for (int i = 0; i <= n; i++) 20 { 21 queue->dequeue(temp); 22 cout << "出隊的元素是:" << temp << endl; 23 } 24 /*queue->dequeue(temp); 25 cout << "出隊的元素是:" << temp << endl; 26 queue->dequeue(temp); 27 cout << "出隊的元素是:" << temp << endl; 28 queue->dequeue(temp); 29 cout << "出隊的元素是:" << temp << endl; 30 queue->dequeue(temp); 31 cout << "出隊的元素是:" << temp << endl; 32 queue->dequeue(temp); 33 cout << "出隊的元素是:" << temp << endl; 34 queue->dequeue(temp); 35 cout << "出隊的元素是:" << temp << endl; 36 37 queue->dequeue(temp); 38 cout << "出隊的元素是:" << temp << endl;*/ 39 40 system("pause"); 41 return 0; 42 }
用法:
1 queue<int> Q; //定義一個int型隊列 2 Q.empty(); //返回隊列是否爲空 3 Q.size(); //返回當前隊列長度 4 Q.front(); //返回當前隊列的第一個元素 5 Q.back(); //返回當前隊列的最後一個元素 6 Q.push(); //在隊列後面插入一個元素, 好比插入數字5: Q.push(5) 7 Q.pop(); //從當前隊列裏,移出第一個元素
1 #include <iostream> 2 #include <queue> 3 4 using namespace std; 5 int main() 6 { 7 queue<int> Q; 8 cout<<"queue empty? "<<Q.empty()<<endl; 9 10 for(int i=0;i<5;i++) 11 { 12 Q.push(i); //進隊列 13 } 14 15 cout<<"queue empty? "<<Q.empty()<<endl; 16 cout<<"queue size: "<<Q.size()<<endl; 17 cout<<endl; 18 19 for(int i=0;i<5;i++) 20 { 21 cout<<"queue front: "<<Q.front()<<endl; 22 Q.pop(); //出隊列 23 } 24 25 return 0; 26 }
參考博客:http://www.javashuo.com/article/p-rzlhbkhl-ba.html
棧的最基本操做是後進先出,其實前邊已經實現了這種功能,只是函數名字不是push()和pop(),好比鏈表的初始化和建立
1 #pragma once 2 /*棧的列表實現*/ 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 typedef int Type; 9 struct Stack 10 { 11 Type data; 12 Stack* next; 13 }; 14 15 16 void initStack(Stack** head); 17 bool isEmpty(Stack** head); 18 void push(Stack** head, Type data); //該data是傳入到棧的數據,不能夠省略 19 void pop(Stack** head, Type & data); //該data是傳入到主函數用於顯示,能夠省略 20
1 #include "stack.h" 2 3 void initStack(Stack** head) 4 { 5 if ((*head) == NULL) 6 return; 7 (*head) = new Stack; 8 (*head)->next = NULL; 9 (*head)->data = 0; 10 } 11 12 bool isEmpty(Stack** head) 13 { 14 return (*head)->next == NULL ? true : false; 15 } 16 17 /*利用鏈表的頭插法實現入棧操做*/ 18 void push(Stack** head, Type data) 19 { 20 Stack* node; 21 node = new Stack; 22 node->next = (*head)->next; 23 node->data = data; 24 (*head)->next = node; 25 } 26 27 /*傳入的是頭結點*/ 28 void pop(Stack** head, Type & data) 29 { 30 Stack* node; 31 if (isEmpty(&(*head))) 32 { 33 cout << "棧已空!" << endl; 34 return; 35 } 36 node = (*head)->next; //node爲頭結點的下一個節點,即要輸出的數據的節點 37 data = node->data; 38 (*head)->next = node->next; 39 delete node; 40 }
1 /*棧測試代碼*/ 2 #include "stack.h" 3 4 Type data; 5 6 int main() 7 { 8 Stack* stack; 9 initStack(&stack); 10 cout << "入棧的數據爲:" << 1 << endl; 11 push(&stack, 1); 12 cout << "入棧的數據爲:" << 2 << endl; 13 push(&stack, 2); 14 cout << "入棧的數據爲:" << 3 << endl; 15 push(&stack, 3); 16 17 cout << endl; 18 19 pop(&stack, data); 20 cout << "出棧的數據爲:" << data << endl; 21 pop(&stack, data); 22 cout << "出棧的數據爲:" << data << endl; 23 pop(&stack, data); 24 cout << "出棧的數據爲:" << data << endl; 25 26 pop(&stack, data); 27 28 system("pause"); 29 return 0; 30 }
運行結果:
2019.10.02 晚
於杭電二教南336
C++中的stack爲程序員實現了堆棧的所有功能,也就是說實現了一個先進後出(FILO)的數據結構。
1 #include <iostream> 2 #include <stack> 3 4 using namespace std; 5 6 int main() 7 { 8 stack<int> s; 9 s.push(1); //入棧 10 s.push(2); 11 s.push(3); 12 s.push(4); 13 s.push(5); 14 15 cout << "棧中元素個數爲:" << s.size() << endl; 16 17 while (!s.empty()) //若是棧中元素爲空,empty()則返回0 18 { 19 cout << s.top() << " "; //top()返回棧頂元素 20 s.pop(); //將當前棧頂元素出棧 21 } 22 cout << endl; 23 system("pause"); 24 return 0; 25 }
運行結果:
快速排序算法是一種基於交換的高效的排序算法,它採用了分治法的思想:
一、從數列中取出一個數做爲基準數(樞軸,pivot)。
二、將數組進行劃分(partition),將比基準數大的元素都移至樞軸右邊,將小於等於基準數的元素都移至樞軸左邊。
三、再對左右的子區間重複第二步的劃分操做,直至每一個子區間只有一個元素。
快排最重要的一步就是劃分了。劃分的過程用通俗的語言講就是「挖坑」和「填坑」。
算法流程以下所示:
參考博客:http://www.javashuo.com/article/p-gypvysya-z.html
1 /*快速排序*/ 2 #define _CRT_SECURE_NO_WARNINGS 3 #include <iostream> 4 #include <string> 5 #include <vector> 6 #include <algorithm> 7 #include <time.h> 8 9 using namespace std; 10 11 void QuickSort(int array[], int start, int last) 12 { 13 int i = start; 14 int j = last; 15 int temp = array[i]; 16 /*下面的循環直到i=j結束,即找到中心,再以i爲中心,分別對左右分別進行快速排序*/ 17 if (i < j) 18 { 19 while (i < j) 20 { 21 // 22 while (i < j && array[j] >= temp) //從右向左掃描,找到比temp小的值,並退出循環 23 j--; //經過自減j,找到第一個比temp小的值的位置j 24 if (i < j) 25 { 26 array[i] = array[j]; //將第一個比temp小的值賦在數組中i的位置上 27 i++; //賦值後將左邊指針自加1 28 } 29 30 while (i < j && temp > array[i]) //從左向右掃描,找到比temp大的值,並退出循環 31 i++; //經過自增i,找到第一個比temp大的值的位置i 32 if (i < j) 33 { 34 array[j] = array[i]; //將第一個比temp大的值賦在數組中j的位置 35 j--; //賦值後將右邊指針自減1 36 } 37 38 } 39 //把基準數放到中間i位置 40 array[i] = temp; 41 //遞歸方法,以i爲中心,分左右進行快速排序 42 QuickSort(array, start, i - 1); //對從start到i-1的數字進行快速排序 43 QuickSort(array, i + 1, last); //對從i+1到last的數字進行快速排序 44 } 45 } 46 47 void PrintArray(int array[], int len) 48 { 49 for (int i = 0; i < len; i++) 50 { 51 cout << array[i] << " "; 52 } 53 cout << endl; 54 } 55 56 int main(void) 57 { 58 const int NUM = 10; 59 int array[NUM] = { 0 }; 60 srand((unsigned int)time(nullptr)); 61 for (int i = 0; i < NUM; i++) 62 { 63 array[i] = rand() % 100 + 1; 64 } 65 cout << "排序前:" << endl; 66 PrintArray(array, NUM); 67 cout << "排序後:" << endl; 68 QuickSort(array, 0, NUM - 1); 69 PrintArray(array, NUM); 70 71 system("pause"); 72 return 0; 73 } 74 75 /*遞歸*/ 76 /* 77 void recurs(argumentlist) 78 { 79 statment1; 80 if (test) 81 recurs(arguments); 82 statment2; 83 } 84 01)一般是將遞歸調用放在if語句中,例如上述遞歸調用recurs(arguments);放在了if語句中 85 02)當test爲true時,每一個recurs()都將執行statment1,而後再調用recurs(),而不會執行statment2; 86 03)當test爲false時,當前調用執行statment2,程序將控制權返回給調用它的recurs(),而該recurs()將執行它的statment2部分,而後結束 87 並將控制權返回給前一個調用,以此類推; 88 04)所以,若是recurs()執行了5次遞歸調用,則statment1將按照函數調用順序執行5次,statment2將按照與函數調用相反的順序執行5次 89 */
執行結果:
假如要對6 1 2 7 9 3 4 5 10 8 這十個數字進行從小到大排序:
(1)選第一個數字6爲基準數,分別從左邊探測第一個比6大的數,從右邊探測第一個比6小的數,若是找到了,則交換兩者,注意若是選左邊第一個數做爲基準數,則此時要先 從右邊開始掃描;若選右邊第一個數做爲基準數,則先從左邊開始掃描;爲方便,令i指向第一個位置,j指向最後一個位置,剛開始的時候讓i指向序列的最左邊(即i=1),指向數字6。讓j指向序列的最右邊(即j=10),指向數字8;
(2)先讓j向左移動,即j--,直到找到第一個比6小的位置,即5停下來;而後讓i向右移動,即i++,直到找到第一個比6大的位置,即7停下來;交換i和j位置處的值,即交換5和7;
(3)接下來開始j繼續向左挪動(再友情提醒,每次必須是哨兵j先出發),直到在4的位置停下來,i也繼續向右挪動的,他發現了9(比基準數6要大,知足要求)以後停了下來。交換i和j位置處的值,即交換9和4;
(4)j繼續先向右移動(j--),在3的位置停下來,假如i遇到比6大的值,必定是會停下來的,若是沒有遇到,則i和j相遇,此時是要交換首位置和此時j所處的位置的值,知足了6的左邊全是比6小的值 和 6的右邊全是比6大的值的特色;這也許是必須先從右邊移動的緣由了吧,關鍵是在於相遇時的值的肯定的問題,即假如先從右邊開始移動的話,那麼相遇處的值必定是會比基準值小的,在相遇時,要交換相遇位置的值和首位值的值,以下所示:
到此第一輪「探測」真正結束。此時以基準數6爲分界點,6左邊的數都小於等於6,6右邊的數都大於等於6。回顧一下剛纔的過程,其實哨兵j的使命就是要找小於基準數的數,而哨兵i的使命就是要找大於基準數的數,直到i和j碰頭爲止。
此時咱們已經將原來的序列,以6爲分界點拆分紅了兩個序列,左邊的序列是「3 1 2 5 4」,右邊的序列是「9 7 10 8」。接下來還須要分別處理這兩個序列,使用遞歸便可。
霸氣的圖描述算法全過程:
參考博客:http://www.javashuo.com/article/p-sgzgfbdc-hx.html
實現代碼:
1 /*方法二實現快速排序*/ 2 void QuickSort(int arr[], int left, int right) 3 { 4 int i = left; 5 int j = right; 6 int base = arr[i]; //以最左邊的值爲基準值 7 if (i > j) 8 return; 9 while (i < j) 10 { 11 while (base <= arr[j] && i<j) //找到比temp小的值(此時爲從小到大排序,若是是要從大到小排序,則此處找比temp大的值) 12 j--; 13 while (base >= arr[i] && i<j) //找到比temp大的值(此時爲從小到大排序,若是是要從大到小排序,則此處找比temp小的值) 14 i++; 15 if (i < j) 16 { 17 int temp = arr[i]; //交換位置i個位置j處的值 18 arr[i] = arr[j]; 19 arr[j] = temp; 20 } 21 } 22 arr[left] = arr[i]; //將i和j相遇處的值放在首位置,由於是從右邊開始探索比基準值小的值,因此i和j相遇處的值必定比6小 23 arr[i] = base; //將基準值放在"中間位置",該"中間位置"的左邊全是比base小的值,右邊全是比base大的值 24 QuickSort(arr, left, i - 1); 25 QuickSort(arr, i + 1, right); 26 } 27 28 void PrintArray(int array[], int len) 29 { 30 for (int i = 0; i < len; i++) 31 { 32 cout << array[i] << " "; 33 } 34 cout << endl; 35 } 36 37 int main(void) 38 { 39 const int NUM = 10; 40 int array[NUM] = { 0 }; 41 srand((unsigned int)time(nullptr)); 42 for (int i = 0; i < NUM; i++) 43 { 44 array[i] = rand() % 100 + 1; 45 } 46 cout << "排序前:" << endl; 47 PrintArray(array, NUM); 48 cout << "排序後:" << endl; 49 QuickSort(array, 0, NUM - 1); 50 PrintArray(array, NUM); 51 52 system("pause"); 53 return 0; 54 } 55 56 /*遞歸*/ 57 /* 58 void recurs(argumentlist) 59 { 60 statment1; 61 if (test) 62 recurs(arguments); 63 statment2; 64 } 65 01)一般是將遞歸調用放在if語句中,例如上述遞歸調用recurs(arguments);放在了if語句中 66 02)當test爲true時,每一個recurs()都將執行statment1,而後再調用recurs(),而不會執行statment2; 67 03)當test爲false時,當前調用執行statment2,程序將控制權返回給調用它的recurs(),而該recurs()將執行它的statment2部分,而後結束 68 並將控制權返回給前一個調用,以此類推; 69 04)所以,若是recurs()執行了5次遞歸調用,則statment1將按照函數調用順序執行5次,statment2將按照與函數調用相反的順序執行5次 70 */
運行結果:
1 int QuickSort(vector<int> arr,int left,int right,int k) 2 { 3 int i=left; 4 int j=right; 5 int base=arr[i]; 6 while(i<j) 7 { 8 while(base>=arr[j] && i<j) 9 j--; 10 while(base<=arr[i] && i<j) 11 i++; 12 if(i<j) 13 { 14 int temp=arr[i]; 15 arr[i]=arr[j]; 16 arr[j]=temp; 17 } 18 } 19 arr[left]=arr[i]; 20 arr[i]=base; 21 if(k == i+1) //數組元素從0開始 22 return arr[i]; 23 else if(k<i+1) //說明第k大的元素在數組前半段 24 return QuickSort(arr,left,i-1,k); 25 else //說明第k大元素在數組後半段 26 return QuickSort(arr,i+1,right,k); 27 }
牛客網原題位置:https://www.nowcoder.com/practice/e016ad9b7f0b45048c58a9f27ba618bf
原理:
(1)兩兩比較相鄰元素A(I)和A(I+1)(I=1,2,…N-1),若是A(I)>A(I+1),則交換A(I)和A(I+1)的位置;
(2)對剩下的N-1個元素,再兩兩進行比較,按一樣規則交換它們的位置,通過N-2次比較,將次最大值交換到A(N-1)的位置;
(3)如法炮製,通過N-1趟的「冒泡處理」,每趟進行N-i次的比較,所有數列有序。
該圖片地址:https://img-blog.csdnimg.cn/20190326182928474.gif (注:有的瀏覽器可能播放不了該圖片中的動畫)
代碼(使用srand()和rand()自動生成數組):
1 #include <iostream> 2 #include <time.h> //for time() 3 4 using namespace std; 5 6 7 /*冒泡排序*/ 8 void BubbleSort(int arr[], int n) 9 { 10 for (int i = 0; i < n - 1; i++) 11 { 12 for (int j = 0; j < n - i - 1; j++) 13 { 14 if (arr[j] > arr[j + 1]) //若是前一個數比後一個數大,則交換兩者的順序;總的來講就是將大的數字後移 15 { 16 int temp = arr[j]; 17 arr[j] = arr[j + 1]; 18 arr[j + 1] = temp; 19 } 20 } 21 } 22 } 23 24 /*打印數組*/ 25 void PrintArray(int arr[], int n) 26 { 27 for (int i = 0; i < n; i++) 28 cout << arr[i] << ","; 29 cout << endl; 30 } 31 32 int main() 33 { 34 const int NUM = 10; //NUM若是做爲數組大小,必須爲常量 35 int array[NUM]; 36 srand((unsigned int)time(nullptr)); //初始化隨機生成函數 37 for (int i = 0; i < NUM; i++) 38 { 39 array[i] = rand() % 100 + 1; //隨機生成1-100之內的數字 40 } 41 cout << "排序前: " << endl; 42 PrintArray(array, NUM); 43 cout << "排序後: " << endl; 44 BubbleSort(array, NUM); 45 PrintArray(array, NUM); 46 47 system("pause"); 48 return 0; 49 }
(1)i=0便可完成將數組中最大值放到數組最後的位置,第一次循環n-1-0次
(2)i=1便可完成將數組中第二大值放到數組倒數第二的位置 ,第二次循環n-1-1次,因爲在數組中n-2到n-1位置已經排序完成,故下一次循環n-1-2次便可
(3)i=1便可完成將數組中第三大值放到數組倒數第三的位置 ,第三次循環n-1-2次,因爲在數組中n-3到n-1位置已經排序完成,故下一次循環n-1-3次便可
即第二次層循環中j結束條件爲j< n - i -1
運行結果:
在一組數的編碼中,若任意兩個相鄰的代碼只有一位二進制數不一樣, 則稱這種編碼爲格雷碼(Gray Code)
例如:
1 1位格雷碼爲:0 1 2 2位格雷碼爲:00 01 11 10 3 3位格雷碼爲:000 001 011 010 110 111 101 100
格雷碼有以下規律:
n=3的gray碼其實就是對n=2的gray碼首位添加0或1生成的,添加0後變成(000,001,011,010),
添加1後須要順序反向就變成(110,111,101,100),
組合在一塊兒就是(000,001,011,010,110,111,101,100)
1 #include <iostream> 2 #include <vector> 3 #include <string> 4 5 using std::endl; 6 using std::cout; 7 using std::cin; 8 using std::string; 9 using std::vector; 10 11 vector<string> getGray(int n) 12 { 13 vector<string> gray; 14 vector<string> lastGray; 15 if (n == 1) 16 { 17 gray.push_back("0"); 18 gray.push_back("1"); 19 return gray; 20 } 21 lastGray = getGray(n - 1); 22 /*在n-1位格雷碼的前面加(順序)0*/ 23 for (int i = 0; i < lastGray.size(); i++) 24 gray.push_back("0" + lastGray[i]); 25 /*在n-1爲格雷碼的前面(反序)加1*/ 26 for (int i = lastGray.size() - 1; i >= 0; i--) 27 gray.push_back("1" + lastGray[i]); 28 return gray; 29 } 30 31 int main() 32 { 33 vector<string> gray; 34 int n = 3; 35 gray = getGray(n); 36 cout << n << "位格雷碼爲:" << endl; 37 for (int i = 0; i < gray.size(); i++) 38 cout << gray[i] << " "; 39 cout << endl; 40 41 system("pause"); 42 return 0; 43 }
運行結果: