數據結構與算法分析_二階指針作爲形參_鏈表頭插入法工做流程及測試_鏈表尾插入法工做流程及測試_雙向鏈表_優先隊列(堆)測試_優先隊列上濾插入和下濾刪除_C語言實現最小堆和堆排序_隊列(循環隊列方法實現

目錄

一、二階指針作爲形參的目的(使實參的值發生改變)html

二、鏈表頭插入法工做流程及測試node

三、鏈表尾插入法工做流程及測試ios

    3.1調試deleteElementByIndex()函數發現,主函數中的linkPtr通過showlinkList()函數以後已經成爲了NULL空指針程序員

    3.2改進算法

四、雙向鏈表數組

  (1) 鏈表初始化和建立瀏覽器

  (2) 在鏈表的第i個位置插入數據data數據結構

  (3) 刪除鏈表中的第i個節點ide

  (4) 刪除全部元素函數

  (5) 最後的修改

五、優先隊列(堆)測試

  5.1++i和i++運算符的測試        m41

  5.2優先隊列上濾插入和下濾刪除

  5.3 C語言實現最小堆和堆排序

六、隊列(循環隊列方法實現)

  (1) 隊列結構體定義;

  (2) 循環隊列出隊入隊圖解

  (3) 臨界狀態下,front和rear的取值方式

  (4) 總結

  (5) 循環隊列中存儲的元素個數計算方式

  (6)調試

  (7)C++中的queue類

七、棧

  (1)本身實現

  (2)使用C++庫函數stack

  (3)使用兩個站實現一個隊列:參考筆試練習:m12

八、快速排序

  (1)實現方法一

  (2)實現方法二

  (3)使用快速排序算法找到數組中的k大的值

九、冒泡排序 

十、生成n位格雷碼

一、二階指針做爲形參的目的

1)普通變量作爲形參,不能改變主函數中實參的值

例子:

 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 }
普通變量做爲形參和普通變了做爲實參

運行結果:

2)一階指針做爲形參,變量地址做爲實參能夠改變主函數中實參的值

例子:

 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 }
View Code

運行結果:

3)二階指針作爲形參,對指針用取地址運算符取地址後做爲實參,能夠改變實參的值

例子:

 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 */
View Code

運行結果:

在例子中的一個解析:

 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  
View Code

參考博客:https://blog.csdn.net/qq_34991245/article/details/81868212

04)二階指針做爲形參,一階指針的地址做爲實參,將形參賦給子函數中的一個變量,後改變該變量的值不會影響實參的值

例子:

 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 }
View Code

運行結果:

05)二階指針做爲形參,一階指針的地址做爲實參,改變子涵數(形參)實參的值會影響實參的值

 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 }
View Code

運行結果:

二、鏈表頭插入法工做流程及測試

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);
linkList.h
  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 }
linkList.cpp
 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 }
main.cpp

運行結果:

三、鏈表尾插入法工做流程及測試

3.1調試deleteElementByIndex()函數的發現,使用二階指針是要謹慎的

調試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 }
mian.cpp
  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 }
stack1.cpp
 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);
stack1.h

運行結果:

 3.2 改進(將showlinkList()中定義一個變量a,將形參賦值給變量a,改變變量a,而不改變實參便可)

以下圖所示:

另外在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 }
mian.cpp
  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 }
stack1.cpp
 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);
stack1.h

執行結果:

四、雙向鏈表  m44

給每一個元素附加兩個指針域,一個存儲前一個元素的地址,一個存儲下一個元素的地址。這種鏈表稱爲雙向鏈表,以下圖所示:

  (1) 鏈表初始化和建立  m441

初始化和建立雙向鏈表的代碼:

 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是同樣的,連續的插入並不僅是插入一個數據
doubleLinkList.h
 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 }
doubleLinkList.cpp
 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 }
main.cpp

運行結果:

(2) 在鏈表的第i個位置插入數據data

「在鏈表的第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);
doubleLinkList.h
 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 }
doubleLinkList.cpp
  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 }
main.cpp

運行結果(該方法是先的是在第二個節點以後插入新數據,把3所在的節點當作是第一個節點):

(3) 刪除鏈表中的第i個節點

刪除一個結點,其實是把這個結點跳過去。要想跳過第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);
doubleLinkList.h
 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 }
doubleLinkList.cpp
  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 }
main.cpp

運行結果:

(4) 刪除全部元素

刪除元素藉鑑了單向鏈表刪除全部元素的方法

 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);
doubleLinkList.h
 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 }
doubleLinkList.cpp
 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 }
main.cpp

運行結果:

(5) 最後的修改

  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 }
doubleLinkList.cpp
 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);
doubleLinkList.h
 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 }
main.cpp

測試結果:

五、優先隊列(堆)測試

5.1++i和i++運算符的測試

 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 }
示例

5.2優先隊列上濾插入和下濾刪除

最大堆:父結點的鍵值老是大於或等於任何一個子節點的鍵值;

最小堆:父結點的鍵值老是小於或等於任何一個子節點的鍵值;

 

 

 

 

  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 }
PriorityQueue.h
 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 }
main.cpp

運行結果:

參考博客:https://blog.csdn.net/qq_37172182/article/details/88978808 

5.3 C語言實現最小堆和堆排序

插入優先隊列(堆)中的流程圖:

 

 刪除寫了註釋,就沒有畫流程圖。。。腦補緣由吧~~哈哈

 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);
PrioriQueueC.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 }
PrioriQueueC.cpp
 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 }
main.cpp

運行結果:

2019.10.04 下午

於 杭電 二教

六、隊列

隊列也是一種線性表,只不過它是操做受限的線性表,只能在兩端操做,先進先出(First In First Out,FIFO)。進的一端稱爲隊尾(rear),出的一端稱爲隊頭(front)。隊列能夠用順序存儲,也能夠用鏈式存儲。

(1) 隊列結構體定義;

(2) 循環隊列出隊入隊圖解

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是時,就認爲是隊滿。如圖所示:

                         此時認爲隊列已滿(浪費了一個空間)

(3) 臨界狀態下,front和rear的取值方式

循環隊列不管入隊仍是出隊,出隊或入隊以後,隊尾、隊頭加1後都要取模運算,例如入隊後隊尾後移一位:Q.rear =(Q.rear+1)%Maxsize。

爲何要使用Maxsize對(rear+1)取餘呢?

主要是爲了處理臨界狀態,即Q.rear向後移動一個位置Q.rear+1後,頗有可能超出了數組的下標,這時它的下一個位置實際上是0,若是將一維數組畫成環形圖,如圖所示:

 

上圖中最大空間Maxsize,當Q.rear=Maxsize-1時,(Q.rear+1)%Maxsize=0,並且Q.front=0,正好知足隊滿的條件:(Q.rear+1) %Maxsize= Q.front,此時爲隊滿(用第一種方法斷定隊滿)

所以不管是front仍是rear向後移動一個位置時,都要加1與最大空間Maxsize取模運算,處理臨界問題。

(4) 總結

隊空: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向後移一位

(5) 循環隊列中存儲的元素個數計算方式

由於隊列是循環的,因此存在兩種狀況:

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。

(6)、調試

  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 //}
queue.h
 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 }
main.cpp

運行結果:

 

 是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 }
mian.cpp

(7)C++中的queue類

用法:

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();                                //從當前隊列裏,移出第一個元素
View Code
 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

七、棧

(1)本身的方法實現

棧的最基本操做是後進先出,其實前邊已經實現了這種功能,只是函數名字不是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  
Stack.h
 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 }
Stack.cpp
 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 }
main.cpp

運行結果:

 2019.10.02 晚 

於杭電二教南336

(2)使用C++庫函數stack實現

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 }
使用C++庫函數實現棧操做

運行結果:

八、快速排序

快速排序算法是一種基於交換的高效的排序算法,它採用了分治法的思想:

一、從數列中取出一個數做爲基準數(樞軸,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 */
方法二實現快速排序

運行結果:

 (3)使用快速排序算法找到數組中第k大的值(筆試題)

 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 }
使用快速排序算法找到數組中第k大的數

牛客網原題位置: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 }
View Code

(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

運行結果:

十、生成n位格雷碼

在一組數的編碼中,若任意兩個相鄰的代碼只有一位二進制數不一樣, 則稱這種編碼爲格雷碼(Gray Code)

例如:

1 1位格雷碼爲:0  1
2 2位格雷碼爲:00 01 11 10
3 3位格雷碼爲:000 001 011 010 110 111 101 100

格雷碼有以下規律:

  • 除了1以外,其餘全部位數的格雷碼的個數都是2的n次方
  • 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 }
代碼及測試代碼

運行結果:

相關文章
相關標籤/搜索