数据结构与算法分析_二阶指针作为形参_链表头插入法工做流程及测试_链表尾插入法工做流程及测试_双向链表_优先队列(堆)测试_优先队列上滤插入和下滤删除_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 }
代码及测试代码

运行结果:

相关文章
相关标签/搜索