-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path==
4282 lines (3577 loc) · 90.7 KB
/
==
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
---
# 木棒三角形
# (枚举)
```c++
#include <iostream>
#include<stdlib.h>
using namespace std;
int main()//木棒三角形 有n根木棍 挑出其中三根构成直角三角形 输出面积最大的三角形面积 输入n再输入每根三角形长度,n<100
{
int n;//输入n根木棍 再分别输入每根木棍的长度 限制了n数量小于100
int len[110];//每个数组元素储存木棍长度 且要求长度由小到大给出
while (scanf("%d", &n) != EOF)
{
for (int i = 0; i < n; i++)
cin >> len[i];
double ans = -1;
for (int i = 0; i < n ; i++)//枚举最短木棍
for (int j = i + 1; j < n ; j++)
for (int z = j + 1; j < n ; j++)
{
if(len[i]*len[i] + len[j]*len[j]==len[z]*len[z])
{
if ((len[i] * len[i] + len[j] * len[j] + len[z] * len[z]) > ans)
ans = 0.5 * len[i] * len[j];
}
}
if (ans == -1)
cout << "no !";
else
cout << ans;
}
}
```
# 顺序查找
```c++
/顺序查找 从第一个开始查找 关键字与给定值相比较 如果相等则退出
int order(int array[], int n, int key)
{
int i;
array[n] = key;//监视哨
for (i = 0; array[i] != key; i++);//分号不可少
return (i < n ? i : -1);
}
```
# 希尔排序
```c++
struct node {
int key;//简化
}a[20];
int n;//全局变量 排序的数字数目
void print()
{
for (int i = 0; i < n; i++)
cout << a[i].key << " ";
}
void create()
{
int i; n = 0;
cout << "input keys:";
cin >> i;
while (i != -999)
{
cin >> i;
a[n].key = i; n++;
}
}
void shell(node a[], int n)
{
int k = n / 2;
for (int i = n; i >=1; i--)
a[i].key = a[i-1].key;
while (k>=1)
{
for (int i = k + 1; i <= n; i++)
{
a[0].key = a[i].key; int j = i - k;
while(a[j].key>a[0].key&&(j>=0))
{
a[j + k].key = a[j].key; j -= k;
}
a[j + k] = a[0];
}
k /= 2;
}
for (int i = 0; i <= n; i++)
a[i].key = a[i + 1].key;
cout << endl;
}
int main()
{
create(); print();
shell(a,n); print();
}
```
# 折半查找
也叫二分查找 可以在最坏的情况下用O(logn)完成任务
```c++
int binarysearch(int array[], int key, int n)
{
int left = 0;
int right = n - 1;
while (left <= right)
{
int middle = (left + right) / 2;
if (array[middle] == key)
return middle;
if (left > array[middle])
left = middle + 1;
if (right < array[middle])
right = middle - 1;
}
return -1;
}
```
# /字符串统计
## 每组测试输出两个正整数 第一个是表示重复的次数,第二次是在该重复次数下有几种不同的字符串
```c++
using namespace std;
struct abc
{
char str[20];
///int num;
}que[20000];
int cmp(const void* a, const void* b)
{
abc* f1 = (abc*)a;
abc* f2 = (abc*)b;
return strcmp(f1->str, f2->str);//排序函数用于在qsort函数中将字符串从小到大排序 可以根据cmp的写法来确定从大到小还是从小到大
}
//qsort函数的基本用法:qsort(que,n,sizeof(que[0]),cmp)que为需要排序的序列首地址
//n为序列的元素 sizeof为序列中单个元素所占空间的大小 cmp为排序过程中用到的比较函数 有-1、0、1三种返回值
int main()
{
int count[20000];//存放种类数 其中[]中的数值是重复的次数
int n;
int number = 1;
while (cin >> n)
{
for (int i = 0; i < n; i++)
{
cin >>que[i].str;
count[i] = 0;
}
qsort(que, n, sizeof(que[0]), cmp);
////如果后一个元素等于前一个元素则出现次数加一
int i = 1;
//while(i < n)
for (int i = 0; i < n - 1; i++)
{
if (strcmp(que[i].str, que[i+1].str) == 0)//比较两个字符串是否相等 不要用==
{
number++;
continue;
}
count[number]++;//如果不相等了 再加上最后这一位本身
number = 1;
//恢复number
}
count[number]++;//
for (int i = 1; i < n; i++)
{
cout << i << " :" << count[i] << "";
cout << endl;
}
}
}
```
#
# 递归:
```c++
//求解组合问题 1~n中任取r个数 求所有组合
//输出一个组合
int r;//全局变量
void display(int a[])
{
for (int i = 0; i < r; i++)
cout << a[i]<<" ";
cout << endl;
}
void mm(int a[], int n, int r)
{
for (int i = n; i >= r; i--)
{
a[r - 1] = i;
if (r > 1)
mm(a, i - 1, r - 1);
else
display(a);
}
}
int main() {
int n;
int a[8];
cin >> n >> r;
mm(a, n, r);
}
```
## 1.n皇后问题
```
using namespace std;
//n皇后问题
//每个皇后不能同行不能同列且不能同对角线
const int N = 20;//最多的皇后数
int q[N];//存放皇后的列好 i是行数q[i]是列数即第i个皇后所在的列号place(k,n)是指【已经在1~k-1行上
//放好了k-1个皇后,现要在k~n上放n-k+1个皇后,则place(k+1,n)指已经在1~k行上放了k个皇后,要在k+1~n行
//放n-k个皇后 即place(k+1,n)比place(k,n)少放一个皇后,前者是小问题,后者是大问题
//当同对角线时 即等腰直角三角形 行的绝对值之差=列的绝对值之差
//本代码i从1开始取,最大下标是n
int ccount = 0;//解的个数
void display(int n)
{
ccount++;
cout << "第" << ccount << "个解:";
for (int i = 1; i <= n; i++)
cout << i << " " << q[i]<<".";
cout << endl;
}
//已经放好了k-1个皇后 考虑第k个皇后 它只能放第k行 j是传进来的值
bool iff(int k, int j)//判断(k,j)能否放皇后 已经放好的皇后是(i,q[i]) i为1~k-1
{
int i = 1;
while (i < k)//前面k-1行已经放了皇后
{
if (q[i] == j ||fabs(j - q[i]) == fabs(k - i))
return false;
i++;
}
return true;
}
void place(int k, int n)
{
if (k > n)
display(n);//此时所有皇后放置结束
else
for (int j = 1; j <= n; j++)//在K行上穷举每一个位置
{
if (iff(k, j))//找到了合适的位置(k,j)时
{
q[k] = j;
place(k + 1, n);
}
}
}
int main()
{
int n;//实际的皇后数
cin >> n;
place(1, n);
}
```
<img src="C:\Users\14172\OneDrive\图片\屏幕快照\2020-10-24.png" style="zoom:67%;" />
![](C:\Users\14172\OneDrive\图片\屏幕快照\2020-10-23 (3).png)
## 2.//生成1~n的排列
```c++
//我们尝试用递归的思想解决:先输出所有以1开头的排列(这一步是递归调用),然后
//输出以2开头的排列(又是递归调用),接着是以3开头的排列……最后才是以n开头的排
//列。
//或者当前需要确定的元素位置cur,
void print_permutation(int n, int* A, int cur)
{
if (n == cur)
{
for (int i = 0; i < n; i++)//递归边界
{
cout << A[i] << " ";
}
cout << endl;
}
else for (int i = 1; i <= n; i++)//尝试在A[cur]中填各种整数i
{
int ok = 1;//标志位 相当于bool
for (int j = 0; j < cur; j++)
if (A[j] == i)//如果i已经在A[0]~A[cur-1]出现过,则不能再选
ok = 0;
if (ok)
{ A[cur] = i;
print_permutation(n, A, cur + 1//递归调用
}
}
}
int main()
{
int A[10] = { 0 };
print_permutation(4, A, 0);
}
```
# 数组。
## 设计算法高效将数组的奇数元素移到偶数元素后面
```c++
//设计算法尽可能高效地将所有奇数元素移动到偶数元素前面
//设置两个指针 ij i=0,j = n-1,当ij不相等时循环 a[i]找偶数元素 a[j]找奇数元素 当i!=j时发生交换
void swapp(int a[], int n)
{
int i = 0, j = n - 1;
int temp;
while (i != j)
{
j--;
if (a[j] % 2 == 1)
{
for (; i != j; i++)
{
if (a[i] % 2 == 0 && a[j] % 2 == 1 && i != j)
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
break;
}
}
}
}
}
int main()
{
m1 = 3;
int m[] = { 1,2,3,4,4,5,6 };
swapp(m, 7);
for (int i = 0; i < 7; i++)
cout << m[i];
}
```
## 以第一个元素为基准 大于该基准的移到后面
```c++
//以a[0]为基准将所有大于a[0]的元素移到该基准后面 小于等于的元素移到该基准前面 得到一个新的数组
void swapp(int a[], int n)
{
int temp;
int num = a[0];
int j = n - 1;//a[j]扫描小于a[0]的 a[i]扫描大于a[0]的 两者发生交换
int i = 0;
while (i != j)
{
j--;
if(a[j] < num)
for (; i != j; i++)
{
if (a[i] >= num)
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
break;
}
}
}
}
```
## //删除一个已排序好的整数数组的重复元素 返回a[](算法效率问题)
```c++
//删除一个已排序好的整数数组的重复元素 返回a[](算法效率问题)
//重建法
int* delee(int a[], int n)
{
int k = 0;
for (int i = 0; i < n; i++)
{
if (a[i] != a[i + 1//如果a[i]不是重复的元素则将a[i]重新插入到a中
{
a[k] = a[i];
k++;//保留的元素增一
}
}
return a;
}
```
## //删除给定的有序整数数组 两个或两个以上的 重复元素仅仅保留两个
```c++
#include<iostream>
using namespace std;
int* delee(int a[], int& n)
{
//删除给定的有序整数数组 两个或两个以上的 重复元素仅仅保留两个
int k = 0;
int b[30] = { 0 };
for (int i = 0; i < n-1; i++)
{
if (a[i] != a[i + 1])
{
a[k] = a[i];
k++;//保留的元素增一
}
if (a[i] == a[i + 1] && a[i] != a[i + 2] )
{
a[k] = a[i];
a[k+1] = a[i + 1];
k += 2;
i += 1;
}
}
n = k;//更新数组的个数 用引用传递 这样在主函数中可以获得新数组的大小
return a;
}
int main()
{
int a[20] = { 2,2,2,2,3,3,3,4,5,6,7,7,8,8,8 };
int k = 16;
int* b= delee(a,k);
for (int i = 0; i < k; i++)
cout << b[i] << " ";
}
```
## //假设数组a中有m+n个元素空间其中0~m-1存放m个升序 数组b存放n个降序整数 不借助其他数组将这些元素升序存放到a中
```c++
//采用二路归并产生升序数组,用i从a[m-1]的元素开始向前扫描 j从前向后扫描 k=m+n-1指向最后一个位置
void shengxu(int a[], int m,int b[], int n)
{
int l = 0;
int r = m - 1;
int k = m+n-1;
while (r >= 0 && l < n)
{
if (b[l] > a[r])//如果b更大
{
a[k] = b[l];
k--;
l++;
}
else
{
a[k] = a[r];
r--;
k--;
}
while (r >= 0)//此时a的前半部分没有扫完
{
a[k] = a[r];
k--;
r--;
}
while (l < n)//b的后部分没有扫完
{
a[k] = b[l];
l++;
k--;
}
}
}
//上述算法时间复杂度为m+n空间复杂度为o(1)
int main()
{
int a[31] = { -2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,21 };
int b[10] = { 8,7,6,5,4,3,2,1,-3,-4};
shengxu(a, 20, b, 10);
for (int i = 0; i < 30; i++)
cout << a[i] << " ";
}
```
## 高效判断两个数组是否存在相同元素
```c++
//采用二路归并产生升序数组,用i从a[m-1]的元素开始向前扫描 j从前向后扫描 k=m+n-1指向最后一个位置
bool shengxu(int a[], int m,int b[], int n)
{
int i = 0, j = 0;
while (i < m && j < n)
{
if (a[i] == b[j])
return true;
else if (a[i] > b[j])
j++;
else
i++;
}
return false;
}
```
# 深度优先搜索算法
油田问题
```c++
//油田问题 一个油田是由m*n个单元组成的矩形,有些里面有石油,一个采油机可以把与该单元油田相连的油田采完,问至少
//需要多少台采油机
//@表示有石油
//采用深度优先搜索算法 设变量many表示采油机 把整个地图搜索完毕 当遇到没有标号的油田时用深度优先搜索把与这块油田相连
//的其他油田全部进行标号
#include <iostream>
using namespace std;
int dfs(int i, int j);
int mmap[55][55] = { 0 };
char s[50][50] = { '0' };
int main()
{
int m, n;
cin >> m >> n;
for(int i = 0;i < m;i++)
for (int j = 0; j < n; j++)
{
cin >> s[i][j];
}
int many = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
if (mmap[i][j] == 0 && s[i][j] == '@')
many += dfs(i, j);
}
cout << many;
}
int dfs(int i, int j)
{
mmap[i][j] = 1;//搜索过的地方置为1
if (mmap[i + 1][j] == 0 && s[i + 1][j] == '@')
dfs(i + 1, j);
if (mmap[i][j + 1] == 0 && s[i][j + 1] == '@')
dfs(i, j + 1);
if (mmap[i - 1][j] == 0 && s[i - 1][j] == '@')
dfs(i - 1, j);
if (mmap[i][j - 1] == 0 && s[i][j - 1] == '@')
dfs(i, j - 1);//将该点周围上下左右四个点全部搜索并且标记为1
return 1;//搜到一个符合条件的点时加一
}
```
## 2.油田问题 一个m行n列的字符矩阵 统计字符@组成多少个八连块
```c++
//油田问题 一个m行n列的字符矩阵 统计字符@组成多少个八连块 DFS更容易编写 递归遍历它周围的@
//每次访问一个格子就给它写上一个“连通分量编号”,这样可以在访问之前检查它是否已经有了编号,避免多次访问
const int maxx = 105;
char pic[maxx][maxx];
int col, row, idx[maxx][maxx];//一个数组是编号一个数组是字符
void dfs(int r, int c, int id)//id是连通分量编号
{
if (r < 0 || r >= row || c < 0 || c >= col) return;//越界检测
if (pic[r][c] != '@' || idx[r][c] > 0) return;//如果不是@或者是已经访问过的格子
idx[r][c] = id;//进行标记 将未访问过的含@格子编号 注意在一个八连块的格子编号相同
for(int i = -1;i<=1;i++)
for (int j = -1; j <= 1; j++)//上下左右寻找
{
if (i != 0 || j != 0)
dfs(r + i, c + j, id);
}
}
int main()
{
cin >> col >> row;
memset(idx, 0, sizeof(idx));
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
cin >> pic[i][j];
int cns = 0;
for (int i = 0; i < row; i++)
for (int j = 0; j < col; j++)
if(pic[i][j] == '@' && idx[i][j] == 0)
dfs(i, j, ++cns);
cout << cns;
}
```
## 3.n件物品放入若干背包
![](C:\Users\14172\OneDrive\图片\屏幕快照\2020-11-19.png)
```c++
const int maxn = 30;
int c[maxn], w[maxn];
int v, n, maxvalue = 0;//v:背包容量 n:物品件数 最大价值maxvalue index:当前物品编号
void dfs(int index, int sumw, int sumc)
{//sumw为当前的背包容量 sumc为当前背包价值
if (index == n) //已经完成对n件物品的选择 死路
{
if (sumw <= v && sumc > maxvalue)
maxvalue = sumc;
return;
}
dfs(index + 1, sumw, sumc);
dfs(index + 1, sumw + c[index], sumc + w[index]);
}
int main()
{
char m;
cin >> n >> v;
for (int i = 0; i < n; i++)
cin >> c[i] ;//每件物品的重量和价值
for (int i = 0; i < n; i++)
cin >> w[i];
}
```
<img src="C:\Users\14172\OneDrive\图片\屏幕快照\2020-11-20 (1).png" style="zoom:150%;" />
# 螺旋矩阵 子矩阵之和(递归和非递归算法)
![](C:\Users\14172\Pictures\数组.jpg)
![](C:\Users\14172\Pictures\数组2.jpg)
![](C:\Users\14172\Pictures\子矩阵.jpg)
![](C:\Users\14172\Pictures\子矩阵解答.jpg)
# 求一个a矩阵以(i,j)和(m,n)为对角线的子矩阵元素之和
```c++
//求一个a矩阵以(i,j)和(m,n)为对角线的子矩阵元素之和
int a[][100];
void sum(int a[][100], int b[][100], int m, int n)
{
b[0][0] = a[0][0];
for (int i = 1; i < m; i++)
b[0][i] = b[0][i - 1] + a[0][i];
for (int i = 1; i < m; i++)
b[i][0] = b[i - 1][0] + a[i][0];
for (int i = 1; i < m; i++)
for (int j = 1; j < n; i++)
b[i][j] = b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1] + a[i][j];//引入数组b b(i,j)存储的是以a[0][0] a[i][j]
//为对角线的矩阵元素之和
}
int ziju(int b[][100], int s, int t, int m, int n)
{
if(m == 0 && n == 0)
return b[m][n];
int sum = b[m][n] - b[m][t - 1] - b[s - 1][n] + b[s - 1][t - 1];
return sum;
}
```
## 递归和非递归创建螺旋矩阵
```c++
//创建一个n阶螺旋矩阵并输出
//对于左上角(ix,iy)右下角(ex,ey)起始元素为start的那一圈,通过调用函数1产生 函数2用于创建整个螺旋矩阵
//设f(x,y,start,n)用于创建左上角为(x,y)起始元素为start的n阶螺旋矩阵,是大问题,则f(x+1,y+1,start,n-2)是小问题
//(去掉最外面一大圈后剩下的部分)
//有递归算法和非递归算法
int a[15][15] = { 0 };
void create(int& start,int ix,int iy,int ex,int ey)//最外面的大圈
{
if (ix == ex)
a[ix][iy] = start++;//当该圈只有一个元素时
else
{
int curl = iy;
while (curl != ey)
a[ix][curl++] = start ++;
curl = ix;
while (curl != ex)
a[curl++][ey] = start++;
curl = ey;
while (curl != iy)
a[ex][curl--] = start++;
curl = ex;
while (curl != ix)
a[curl--][iy] = start++;
}
}
void spira(int x,int y,int n,int start)//递归调用螺旋矩阵
{
if (n <= 0)//退出递归条件
return;
if (n == 1)
{
a[x][y] = start;//矩阵大小为1时
return;
}
else
{
for (int i = y; i < y+n-1; i++)//上一行
a[x][i] = start++;
for (int i = x; i < x+n-1; i++)//右一列
a[i][x +n-1] = start++;
for (int i = x +n-1;i > y; i--)//下一行
a[x + n-1][i] = start++;
for (int i =x+ n-1; i > x; i--)//左一列
a[i][y] = start++;
spira(x+1,y + 1, n-2,start);//递归调用自身
}
}
void spira2(int n)//非递归调用螺旋矩阵
{
int start = 1;
int i = 0, j = 0, ex = n - 1, ey = n - 1;
while (i <= ex)
create(start, i++, j++, ex--, ey--);// 不断循环调用创建最外圈元素的函数
}
void display(int n)
{
for (int i = 0; i < n; i++)
{ for (int j = 0; j < n; j++)
cout << a[i][j] << " ";
cout << endl;//输出
}
}
```
![](C:\Users\14172\Pictures\屏幕截图 2020-10-28 210335.png)
## //有两个有序数组ab 元素个数m,n 设计一个高效算法求a和b的差集
```c++
//设a-b的元素数组为c
int a[5], b[5];
int c[8] = { 0 };
void chaji(int m,int n,int a[],int b[])
{
int i = 0, k = 0, j = 0;//k来维护c中元素个数
while (i < m && j < n)//注意这个while循环很重要不能遗漏否则无法得到正确结果
{
if (a[i] < b[j])
{
c[k] = a[i];
i++;
k++;//只将a中较小的元素放入c中
}
else if (a[i] > b[j])//如果b中元素更小则跳过
{
j++;
}
else//如果元素相等 不能放入C中 下标加一
{
i++;
j++;
}
}
while (i < n)//注意要将如果a没有遍历完则全部放入C中
{
c[k] = a[i];
i++;
k++;
}
}
int main()
{
int a[5] = { 3,4,9,10,77};
int b[5] = { 2,3,5,6,4 };
chaji(5, 5, a, b);
for (int i = 0; i < 8; i++)
cout << c[i]<<" ";
}
```
# 基于链表的算法设计
- 通常单链表是带头结点的结构,单链表如果有头结点,通常用头结点的地址即头指针来标识整个单链表,第一个**数据结点**称为首结点,指向首结点的指针称为首指针,
- **头结点**是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息,它不计入表长度。
**首元结点**是指链表中存储线性表第一个数据元素a0的结点。
其中头指针只是指针,它指向头结点或首元结点所对应的地址,在程序中,并没有给它分配固定的内存;而头结点和首元结点却对应着固定的内存。头结点和首元结点的区别在于数据域中是否存放了数据元素,头结点中的数据域为空,或存放表长信息,引入它是为了方便链表的插入和删除操作;而首元结点的数据域中会存储第一个数据元素的值。
- ![](C:\Users\14172\Pictures\==.png)
- Head指针为单链表的头指针,单链表L:L既是单链表的名字,也是其头指针。链表中的最后一个结点的指针域定义为空指针(NULL)。那么什么是头指针呢?我们把指向第一个结点的指针称为头指针,那么每次访问链表时都可以从这个头指针依次遍历链表中的每个元素,例如:
- struct node first;
struct node *head = &first;这个head指针就是头指针。
这个头指针的意义在于,在访问链表时,总要知道链表存储在什么位置(从何处开始访问),由于链表的特性(next指针),知道了头指针,那么整个链表的元素都能够被访问,也就是说头指针是必须存在的。示例如下
```c++
示例如下:
#include <stdio.h>
struct node {
int data;
struct node *next;
};
int main(void)
{
struct node *head, first, second;
head = &first;
first.data = 1;
first.next = &second;
second.data = 2;
second.next = NULL;
while (head) {
printf("%d\n", head->data);
head = head->next;
}
return 0;
}
```
需要着重注意的是while那部分(通过头指针遍历完整个链表)。
单链表有带头结点和不带头结点之分。
![](C:\Users\14172\Pictures\111.jpg)
```c++
1.单链表的初始化,即建立一个空链表。
[plain] view plain copy
//不带头结点的单链表的初始化
void LinkedListInit1(LinkedList L)
{
L=NULL;
}
//带头结点的单链表的初始化
void LinkedListInit2(LinkedList L)
{
L=(LNode *)malloc(sizeof(LNode));
if(L==NULL)
{
printf("申请空间失败!");
exit(0);
}
L->next=NULL;
}
```
那么什么又是头结点呢?很多时候,会在链表的头部附加一个结点,该结点的数据域可以不存储任何信息,这个结点称为头结点,
头结点的指针域指向第一个结点,例如:
struct node head, first;
head.next = &first;
那么这里的头指针又是谁呢,不再是指向第一个结点的指针,而是指向头结点的指针,例如:
```html
struct node *root = &head;
```
即root指针才是头指针。示例如下:
1. \#include <stdio.h>
2.
3. **struct** node {
4. **int** data;
5. **struct** node *next;
6. };
7.
8. **int** main(**void**)
9. {
10. **struct** node *root, head, first, second;
11.
12. root = &head;
13. root->data = 0;
14. root->next = &first;
15.
16. first.data = 1;
17. first.next = &second;