-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.scm
1329 lines (832 loc) · 52 KB
/
main.scm
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
;; L-99: Ninety-Nine Lisp Problems
;; Based on a Prolog problem list by [email protected]
(import test)
(import (chicken random))
(define-syntax with-determinate-random
(syntax-rules ()
[(_ body ...)
(begin
(set-pseudo-random-seed! "this is some very random data")
body ...)]))
;;; Working with lists
;; P01 (*) Find the last box of a list.
;; Example:
;; * (my-last '(a b c d))
;; (D)
(define (my-last lst)
(cond
[(null? lst) #f]
[(null? (cdr lst)) lst]
[else (my-last (cdr lst))]))
(test "P01" '(d) (my-last '(a b c d)))
;; P02 (*) Find the last but one box of a list.
;; Example:
;; * (my-but-last '(a b c d))
;; (C D)
(define (my-but-last lst)
(cond
[(null? lst) #f]
[(null? (cdr lst)) #f]
[(null? (cddr lst)) lst]
[else (my-but-last (cdr lst))]))
(test "P02" '(c d) (my-but-last '(a b c d)))
;; P03 (*) Find the K'th element of a list.
;; The first element in the list is number 1.
;; Example:
;; * (element-at '(a b c d e) 3)
;; C
(define (my-element-at lst k)
(if (= k 1)
(car lst)
(my-element-at (cdr lst) (- k 1))))
(test "P03" 'c (my-element-at '(a b c d e) 3))
;; P04 (*) Find the number of elements of a list.
(define (my-length lst)
(let count ([lst lst]
[c 0])
(if (null? lst)
c
(count (cdr lst) (+ c 1)))))
;; P05 (*) Reverse a list.
(define (my-reverse lst)
(let reverse ([lst lst]
[tsl '()])
(if (null? lst)
tsl
(reverse (cdr lst) (cons (car lst) tsl)))))
(test "P05" '(d c b a) (my-reverse '(a b c d)))
;; P06 (*) Find out whether a list is a palindrome.
;; A palindrome can be read forward or backward; e.g. (x a m a x).
(define (my-palindrome? lst)
(if (> 2 (my-length lst))
#t
(let palindrome? ([lst lst]
[tsl (my-reverse lst)]
[c (floor (/ (my-length lst) 2))])
(cond
[(= 0 c) #t]
[(eq? (car lst) (car tsl))
(palindrome? (cdr lst) (cdr tsl) (- c 1))]
[else #f]))))
(test "P06" #t (my-palindrome? '(a b c b a)))
(test "P06" #t (my-palindrome? '(a a)))
(test "P06" #t (my-palindrome? '(a)))
(test "P06" #t (my-palindrome? '()))
(test "P06" #f (my-palindrome? '(a b)))
(test "P06" #f (my-palindrome? '(a b c)))
;; P07 (**) Flatten a nested list structure.
;; Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively).
;; Example:
;; * (my-flatten '(a (b (c d) e)))
;; (A B C D E)
;; Hint: Use the predefined functions list and append.
(define (my-flatten lst)
(cond
[(null? lst) lst]
[(list? (car lst))
(append (my-flatten (car lst))
(my-flatten (cdr lst)))]
[else (cons (car lst) (my-flatten (cdr lst)))]))
(test "P07" '(a b c d e) (my-flatten '(a (b (c d) e))))
;; P08 (**) Eliminate consecutive duplicates of list elements.
;; If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.
;; Example:
;; * (compress '(a a a a b c c a a d e e e e))
;; (A B C A D E)
(define (my-compress lst)
;; I know *this and following solutions aren't guarateed to work correctly
;; when presented with lists containing #f*; I know how to fix it and would if
;; I were to implement a general purpose library, but that'd be quite a bit
;; wordier and not worth a study task.
(let compress ([lst lst]
[el #f])
(cond
[(null? lst) '()]
[(eq? el (car lst)) (compress (cdr lst) (car lst))]
[else (cons (car lst) (compress (cdr lst) (car lst)))])))
(test "P08" '(a b c a d e) (my-compress '(a a a a b c c a a d e e e e)))
;; P09 (**) Pack consecutive duplicates of list elements into sublists.
;; If a list contains repeated elements they should be placed in separate sublists.
;; Example:
;; * (pack '(a a a a b c c a a d e e e e))
;; ((A A A A) (B) (C C) (A A) (D) (E E E E))
(define (my-pack lst)
(if (null? lst)
'()
(let pack ([lst (cdr lst)]
[els (cons (car lst) '())])
(cond
[(null? lst) (cons els '())]
[(eq? (car els) (car lst))
(pack (cdr lst) (cons (car lst) els))]
[else (cons els (my-pack lst))]))))
(my-pack '(a a a a b c c a a d e e e e))
(test "P09" '((a a a a) (b) (c c) (a a) (d) (e e e e))
(my-pack '(a a a a b c c a a d e e e e)))
;; P10 (*) Run-length encoding of a list.
;; Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as lists (N E) where N is the number of duplicates of the element E.
;; Example:
;; * (encode '(a a a a b c c a a d e e e e))
;; ((4 A) (1 B) (2 C) (2 A) (1 D)(4 E))
(define (my-encode lst)
(let encode ([lst (my-pack lst)])
(if (null? lst)
'()
(cons (list (my-length (car lst)) (caar lst))
(encode (cdr lst))))))
(test "P10" '((4 a) (1 b) (2 c) (2 a) (1 d)(4 e)) (my-encode '(a a a a b c c a a d e e e e)))
;; P11 (*) Modified run-length encoding.
;; Modify the result of problem P10 in such a way that if an element has no duplicates it is simply copied into the result list. Only elements with duplicates are transferred as (N E) lists.
;; Example:
;; * (encode-modified '(a a a a b c c a a d e e e e))
;; ((4 A) B (2 C) (2 A) D (4 E))
(define (my-encode-modified lst)
(let encode ([lst (my-pack lst)])
(if (null? lst)
'()
(let ([l (my-length (car lst))]
[el (caar lst)]
[rest (encode (cdr lst))])
(if (= 1 l)
(cons el rest)
(cons (list l el) rest))))))
(test "P11" '((4 a) b (2 c) (2 a) d (4 e)) (my-encode-modified '(a a a a b c c a a d e e e e)))
;; P12 (**) Decode a run-length encoded list.
;; Given a run-length code list generated as specified in problem P11. Construct its uncompressed version.
(define (my-decode lst)
(if (null? lst)
'()
(letrec ([decompress
(lambda (n el)
(if (< 0 n)
(cons el (decompress (- n 1) el))
'()))]
[enc (car lst)]
[rest (my-decode (cdr lst))])
(if (list? enc)
(append (apply decompress enc) rest)
(cons enc rest)))))
(test "P12" '(a a a a b c c a a d e e e e) (my-decode (my-encode-modified '(a a a a b c c a a d e e e e))))
;; P13 (**) Run-length encoding of a list (direct solution).
;; Implement the so-called run-length encoding data compression method directly. I.e. don't explicitly create the sublists containing the duplicates, as in problem P09, but only count them. As in problem P11, simplify the result list by replacing the singleton lists (1 X) by X.
;; Example:
;; * (encode-direct '(a a a a b c c a a d e e e e))
;; ((4 A) B (2 C) (2 A) D (4 E))
(define (my-encode-direct lst)
(let* ([enc (lambda (l e)
(if (= 1 l)
e
(list l e)))])
(cdr
(let encode ([lst lst]
[el #f]
[c 0])
(cond
[(null? lst) (list (enc c el))]
[(eq? el (car lst)) (encode (cdr lst) el (+ 1 c))]
[else (cons (enc c el) (encode (cdr lst) (car lst) 1))])))))
(test "P13" '((4 a) b (2 c) (2 a) d (4 e)) (my-encode-direct '(a a a a b c c a a d e e e e)))
;; P14 (*) Duplicate the elements of a list.
;; Example:
;; * (dupli '(a b c c d))
;; (A A B B C C C C D D)
(define (my-dupli lst)
(if (null? lst)
'()
(cons (car lst) (cons (car lst) (my-dupli (cdr lst))))))
(test "P14" '(a a b b c c c c d d) (my-dupli '(a b c c d)))
;; P15 (**) Replicate the elements of a list a given number of times.
;; Example:
;; * (repli '(a b c) 3)
;; (A A A B B B C C C)
(define (my-repli lst n)
(letrec [(repeat (lambda (el n)
(if (= 0 n)
'()
(cons el (repeat el (- n 1))))))]
(if (null? lst)
'()
(append (repeat (car lst) n) (my-repli (cdr lst) n)))))
(test "P15" '(a a a b b b c c c) (my-repli '(a b c) 3))
;; P16 (**) Drop every N'th element from a list.
;; Example:
;; * (drop '(a b c d e f g h i k) 3)
;; (A B D E G H K)
(define (my-drop lst n)
(let drop ([lst lst]
[n n]
[k 1])
(cond
[(null? lst) '()]
[(= n k) (drop (cdr lst) n 1)]
[else (cons (car lst) (drop (cdr lst) n (+ k 1)))])))
(test "P16" '(a b d e g h k) (my-drop '(a b c d e f g h i k) 3))
;; P17 (*) Split a list into two parts; the length of the first part is given.
;; Do not use any predefined functions.
;; Example:
;; * (split '(a b c d e f g h i k) 3)
;; ( (A B C) (D E F G H I K))
(define (my-split lst n)
(cond
[(null? lst) '()]
[(< 0 n) (let* ([rest (my-split (cdr lst) (- n 1))]
[lhs (car rest)]
[rhs (cdr rest)])
(cons (cons (car lst) lhs) rhs))]
[else (list '() lst)]))
(test "P17" '((a b c) (d e f g h i k)) (my-split '(a b c d e f g h i k) 3))
;; P18 (**) Extract a slice from a list.
;; Given two indices, I and K, the slice is the list containing the elements between the I'th and K'th element of the original list (both limits included). Start counting the elements with 1.
;; Example:
;; * (slice '(a b c d e f g h i k) 3 7)
;; (C D E F G)
(define (my-slice lst ks ke)
(let ([rest (lambda ()
(my-slice (cdr lst) (- ks 1) (- ke 1)))])
(cond
[(null? lst) '()]
[(< 1 ks) (rest)]
[(< 0 ke) (cons (car lst) (rest))]
[else '()])))
(test "P18" '(c d e f g) (my-slice '(a b c d e f g h i k) 3 7))
;; P19 (**) Rotate a list N places to the left.
;; Examples:
;; * (rotate '(a b c d e f g h) 3)
;; (D E F G H A B C)
;; * (rotate '(a b c d e f g h) -2)
;; (G H A B C D E F)
;; Hint: Use the predefined functions length and append, as well as the result of problem P17.
(define (my-rotate lst n)
(let* ([l (my-length lst)]
[k (if (< 0 n) n (+ l n))]
[lhs (my-slice lst 1 k)]
[rhs (my-slice lst (+ k 1) l)])
(append rhs lhs)))
(test "P17" '(d e f g h a b c) (my-rotate '(a b c d e f g h) 3))
(test "P17" '(g h a b c d e f) (my-rotate '(a b c d e f g h) -2))
;; P20 (*) Remove the K'th element from a list.
;; Example:
;; * (remove-at '(a b c d) 2)
;; (A C D)
(define (my-remove-at lst k)
(cond
[(null? lst) '()]
[(= 1 k) (cdr lst)]
[else (cons (car lst) (my-remove-at (cdr lst) (- k 1)))]))
(test "P20" '(a c d) (my-remove-at '(a b c d) 2))
;; P21 (*) Insert an element at a given position into a list.
;; Example:
;; * (insert-at 'alfa '(a b c d) 2)
;; (A ALFA B C D)
(define (my-insert-at s lst k)
(cond
[(null? lst) '()]
[(= 1 k) (cons s lst)]
[else (cons (car lst) (my-insert-at s (cdr lst) (- k 1)))]))
(test "P21" '(a alpha b c d) (my-insert-at 'alpha '(a b c d) 2))
;; P22 (*) Create a list containing all integers within a given range.
;; If first argument is smaller than second, produce a list in decreasing order.
;; Example:
;; * (range 4 9)
;; (4 5 6 7 8 9)
(define (my-range ks ke)
(if (> ks ke)
'()
(cons ks (my-range (+ ks 1) ke))))
(test "P22" '(4 5 6 7 8 9) (my-range 4 9))
;; P23 (**) Extract a given number of randomly selected elements from a list.
;; The selected items shall be returned in a list.
;; Example:
;; * (rnd-select '(a b c d e f g h) 3)
;; (E D A)
;; Hint: Use the built-in random number generator and the result of problem P20.
(define (my-rnd-select lst n)
;; Totally inefficient! That's not what we're here for, are we?
(let rnd-select ([lst lst]
[k (- (+ 1 (my-length lst)) n)])
(cond
[(null? lst) '()]
[(= k 0) lst]
[else (rnd-select
(my-remove-at lst (pseudo-random-integer (my-length lst)))
(- k 1))])))
(test "P23" '(f g h) (with-determinate-random
(my-rnd-select '(a b c d e f g h) 3)))
;; P24 (*) Lotto: Draw N different random numbers from the set 1..M.
;; The selected numbers shall be returned in a list.
;; Example:
;; * (lotto-select 6 49)
;; (23 1 17 33 21 37)
;; Hint: Combine the solutions of problems P22 and P23.
(define (my-lotto-select n m)
(my-rnd-select (my-range 1 m) n))
(test "P24" '(1 9 19 23 24 40 43 46 49)
(with-determinate-random (my-lotto-select 6 49)))
;; P25 (*) Generate a random permutation of the elements of a list.
;; Example:
;; * (rnd-permu '(a b c d e f))
;; (B A D C E F)
;; Hint: Use the solution of problem P23.
(define (my-rnd-permu lst)
(if (null? lst)
'()
(let* ([k (+ 1 (pseudo-random-integer (my-length lst)))]
[el (my-element-at lst k)]
[rest (my-remove-at lst k)])
(cons el (my-rnd-permu rest)))))
(test "P25" '(f c b a d e) (with-determinate-random (my-rnd-permu '(a b c d e f))))
;; P26 (**) Generate the combinations of K distinct objects chosen from the N elements of a list
;; In how many ways can a committee of 3 be chosen from a group of 12 people? We all know that there are C(12,3) = 220 possibilities (C(N,K) denotes the well-known binomial coefficients). For pure mathematicians, this result may be great. But we want to really generate all the possibilities in a list.
;; Example:
;; * (combination 3 '(a b c d e f))
;; ((A B C) (A B D) (A B E) ... )
(define (my-combination k lst)
(cond
[(>= k (my-length lst)) (list lst)]
[(= k 0) '(())]
[else (append
(map (lambda (combs)
(cons (car lst) combs))
(my-combination (- k 1) (cdr lst)))
(my-combination k (cdr lst)))]))
(test "P26" '((a b) (a c) (a d) (b c) (b d) (c d))
(my-combination 2 '(a b c d)))
;; P27 (**) Group the elements of a set into disjoint subsets.
;; a) In how many ways can a group of 9 people work in 3 disjoint subgroups of 2, 3 and 4 persons? Write a function that generates all the possibilities and returns them in a list.
;; Example:
;; * (group3 '(aldo beat carla david evi flip gary hugo ida))
;; ( ( (ALDO BEAT) (CARLA DAVID EVI) (FLIP GARY HUGO IDA) )
;; ... )
;; b) Generalize the above function in a way that we can specify a list of group sizes and the function will return a list of groups.
;; Example:
;; * (group '(aldo beat carla david evi flip gary hugo ida) '(2 2 5))
;; ( ( (ALDO BEAT) (CARLA DAVID) (EVI FLIP GARY HUGO IDA) )
;; ... )
;; Note that we do not want permutations of the group members; i.e. ((ALDO BEAT) ...) is the same solution as ((BEAT ALDO) ...). However, we make a difference between ((ALDO BEAT) (CARLA DAVID) ...) and ((CARLA DAVID) (ALDO BEAT) ...).
;; You may find more about this combinatorial problem in a good book on discrete mathematics under the term "multinomial coefficients".
(define (my-in? el lst)
(cond
[(null? lst) #f]
[(eqv? el (car lst)) #t]
[else (my-in? el (cdr lst))]))
(define (my-list-difference a b)
(cond
[(null? a) '()]
[(my-in? (car a) b) (my-list-difference (cdr a) b)]
[else (cons (car a)
(my-list-difference (cdr a) b))]))
(define (my-group elements sizes)
(if (or (null? elements)
(null? sizes))
'(())
(let ([combs (my-combination (car sizes) elements)])
(map (lambda (comb)
(car (map (lambda (grouping)
(cons comb grouping))
(my-group (my-list-difference elements comb)
(cdr sizes)))))
combs))))
(test "P27" '(((a b) (c d e))
((a c) (b d e))
((a d) (b c e))
((a e) (b c d))
((b c) (a d e))
((b d) (a c e))
((b e) (a c d))
((c d) (a b e))
((c e) (a b d))
((d e) (a b c)))
(my-group '(a b c d e) '(2 3)))
;; P28 (**) Sorting a list of lists according to length of sublists
;; a) We suppose that a list contains elements that are lists themselves. The objective is to sort the elements of this list according to their length. E.g. short lists first, longer lists later, or vice versa.
;; Example:
;; * (lsort '((a b c) (d e) (f g h) (d e) (i j k l) (m n) (o)))
;; ((O) (D E) (D E) (M N) (A B C) (F G H) (I J K L))
;; b) Again, we suppose that a list contains elements that are lists themselves. But this time the objective is to sort the elements of this list according to their length frequency; i.e., in the default, where sorting is done ascendingly, lists with rare lengths are placed first, others with a more frequent length come later.
;; Example:
;; * (lfsort '((a b c) (d e) (f g h) (d e) (i j k l) (m n) (o)))
;; ((I J K L) (O) (A B C) (F G H) (D E) (D E) (M N))
;; Note that in the above example, the first two lists in the result have length 4 and 1, both lengths appear just once. The third and forth list have length 3 which appears twice (there are two list of this length). And finally, the last three lists have length 2. This is the most frequent length.
(define (my-sort lst rating-func)
(define (strip-of-rating lst)
(if (null? lst)
'()
(cons (cadar lst) (strip-of-rating (cdr lst)))))
(strip-of-rating
(let sort ([lst (rating-func lst)])
(cond [(null? lst) '()]
[(null? (cdr lst)) lst]
[else (let* ([rest (sort (cdr lst))]
[this (car lst)]
[next (car rest)]
[tail (cdr rest)])
(if (> (car this) (car next))
(sort (cons next (cons this tail)))
(cons this rest)))]))))
(define (my-lsort lst)
(my-sort lst
(lambda (lst)
(let rate ([lst lst])
(if (not (null? lst))
(cons (list (my-length (car lst))
(car lst))
(rate (cdr lst)))
'())))))
(define (my-lfsort lst)
(my-sort lst
(lambda (lst)
(define ratings (make-parameter '()))
(let rate ([lst lst])
(if (not (null? lst))
(let* ([el (car lst)]
[l (my-length el)]
;; I update the alist of frequencies before I call (rate (cdr lst))
;; so that the last (rate ...) will have a complete rating table.
[freq (alist-ref l (ratings) eqv? 0)]
[newfreq (+ 1 freq)]
[_ (ratings (alist-update l newfreq (ratings)))]
[rest (rate (cdr lst))]
[rating (alist-ref l (ratings) eqv? 0)])
(cons (list rating el)
rest))
'())))))
(test "P30" '((o) (d e) (d e) (m n) (a b c) (f g h) (i j k l))
(my-lsort '((a b c) (d e) (f g h) (d e) (i j k l) (m n) (o))))
(test "P30" '((i j k l) (o) (a b c) (f g h) (d e) (d e) (m n))
(my-lfsort '((a b c) (d e) (f g h) (d e) (i j k l) (m n) (o))))
;; Arithmetic
;; P31 (**) Determine whether a given integer number is prime.
;; Example:
;; * (is-prime 7)
;; T
(define (my-is-prime n)
(let check ([number n]
[candidate 2]
[bound (ceiling (sqrt n))])
(cond
[(>= candidate bound) #t]
[(= 0 (remainder number candidate)) #f]
[else (check number (+ 1 candidate) bound)])))
(test "P31" #t (my-is-prime 7))
;; P32 (**) Determine the greatest common divisor of two positive integer numbers.
;; Use Euclid's algorithm.
;; Example:
;; * (gcd 36 63)
;; 9
(define (my-gcd a b)
(cond
[(= a b)
a]
[(> a b) (my-gcd (- a b) b)]
[else (my-gcd a (- b a))]))
(test "P32" 9 (my-gcd 36 63))
;; P33 (*) Determine whether two positive integer numbers are coprime.
;; Two numbers are coprime if their greatest common divisor equals 1.
;; Example:
;; * (coprime 35 64)
;; T
(define (my-coprime a b)
(= 1 (my-gcd a b)))
(test "P33" #t (my-coprime 35 64)
;; P34 (**) Calculate Euler's totient function phi(m).
;; Euler's so-called totient function phi(m) is defined as the number of positive integers r (1 <= r < m) that are coprime to m.
;; Example: m = 10: r = 1,3,7,9; thus phi(m) = 4. Note the special case: phi(1) = 1.
;; * (totient-phi 10)
;; 4
;; Find out what the value of phi(m) is if m is a prime number. Euler's totient function plays an important role in one of the most widely used public key cryptography methods (RSA). In this exercise you should use the most primitive method to calculate this function (there are smarter ways that we shall discuss later).
;; P35 (**) Determine the prime factors of a given positive integer.
;; Construct a flat list containing the prime factors in ascending order.
;; Example:
;; * (prime-factors 315)
;; (3 3 5 7)
;; P36 (**) Determine the prime factors of a given positive integer (2).
;; Construct a list containing the prime factors and their multiplicity.
;; Example:
;; * (prime-factors-mult 315)
;; ((3 2) (5 1) (7 1))
;; Hint: The problem is similar to problem P10.
;; P37 (**) Calculate Euler's totient function phi(m) (improved).
;; See problem P34 for the definition of Euler's totient function. If the list of the prime factors of a number m is known in the form of problem P36 then the function phi(m) can be efficiently calculated as follows: Let ((p1 m1) (p2 m2) (p3 m3) ...) be the list of prime factors (and their multiplicities) of a given number m. Then phi(m) can be calculated with the following formula:
;; phi(m) = (p1 - 1) * p1 ** (m1 - 1) * (p2 - 1) * p2 ** (m2 - 1) * (p3 - 1) * p3 ** (m3 - 1) * ...
;; Note that a ** b stands for the b'th power of a.
;; P38 (*) Compare the two methods of calculating Euler's totient function.
;; Use the solutions of problems P34 and P37 to compare the algorithms. Take the number of basic operations, including CARs, CDRs, CONSes, and arithmetic operations, as a measure for efficiency. Try to calculate phi(10090) as an example.
;; P39 (*) A list of prime numbers.
;; Given a range of integers by its lower and upper limit, construct a list of all prime numbers in that range.
;; P40 (**) Goldbach's conjecture.
;; Goldbach's conjecture says that every positive even number greater than 2 is the sum of two prime numbers. Example: 28 = 5 + 23. It is one of the most famous facts in number theory that has not been proved to be correct in the general case. It has been numerically confirmed up to very large numbers (much larger than we can go with our Lisp system). Write a function to find the two prime numbers that sum up to a given even integer.
;; Example:
;; * (goldbach 28)
;; (5 23)
;; P41 (**) A list of Goldbach compositions.
;; Given a range of integers by its lower and upper limit, print a list of all even numbers and their Goldbach composition.
;; Example:
;; * (goldbach-list 9 20)
;; 10 = 3 + 7
;; 12 = 5 + 7
;; 14 = 3 + 11
;; 16 = 3 + 13
;; 18 = 5 + 13
;; 20 = 3 + 17
;; In most cases, if an even number is written as the sum of two prime numbers, one of them is very small. Very rarely, the primes are both bigger than say 50. Try to find out how many such cases there are in the range 2..3000.
;; Example (for a print limit of 50):
;; * (goldbach-list 1 2000 50)
;; 992 = 73 + 919
;; 1382 = 61 + 1321
;; 1856 = 67 + 1789
;; 1928 = 61 + 1867
;; Logic and Codes
;; P46 (**) Truth tables for logical expressions.
;; Define functions and, or, nand, nor, xor, impl and equ (for logical equivalence) which return the result of the respective operation on boolean values.
;; A logical expression in two variables can then be written in prefix notation, as in the following example: (and (or A B) (nand A B)).
;; Write a function table which prints the truth table of a given logical expression in two variables.
;; Example:
;; * (table 'A 'B '(and A (or A B))).
;; true true true
;; true nil true
;; nil true nil
;; nil nil nil
;; P47 (*) Truth tables for logical expressions (2).
;; Modify problem P46 by accepting expressions written in infix notation, with all parenthesis present. This allows us to write logical expression in a more natural way, as in the example: (A and (A or (not B))).
;; Example:
;; * (table 'A 'B '(A and (A or (not B)))).
;; true true true
;; true nil true
;; nil true nil
;; nil nil nil
;; P48 (**) Truth tables for logical expressions (3).
;; Generalize problem P47 in such a way that the logical expression may contain any number of logical variables. Define table in a way that (table List Expr) prints the truth table for the expression Expr, which contains the logical variables enumerated in List.
;; Example:
;; * (table '(A B C) '((A and (B or C)) equ ((A and B) or (A and C)))).
;; true true true true
;; true true nil true
;; true nil true true
;; true nil nil true
;; nil true true true
;; nil true nil true
;; nil nil true true
;; nil nil nil true
;; P49 (**) Gray code.
;; An n-bit Gray code is a sequence of n-bit strings constructed according to certain rules. For example,
;; n = 1: C(1) = ("0" "1").
;; n = 2: C(2) = ("00" "01" "11" "10").
;; n = 3: C(3) = ("000" "001" "011" "010" "110" "111" "101" "100").
;; Find out the construction rules and write a function with the following specification:
;; (gray N) returns the N-bit Gray code
;; Can you apply the method of "result caching" in order to make the function more efficient, when it is to be used repeatedly?
;; P50 (***) Huffman code.
;; First of all, consult a good book on discrete mathematics or algorithms for a detailed description of Huffman codes!
;; We suppose a set of symbols with their frequencies, given as a list of (S F) elements. Example: ( (a 45) (b 13) (c 12) (d 16) (e 9) (f 5) ). Our objective is to construct a list of (S C) elements, where C is the Huffman code word for symbol S. In our example, the result could be ( (A "0") (B "101") (C "100") (D "111") (E "1101") (F "1100") ). The task shall be performed by a function huffman defined as follows:
;; (huffman F) returns the Huffman code table for the frequency table F
;; Binary Trees
;; A binary tree is either empty or it is composed of a root element and two successors, which are binary trees themselves.
;; In Lisp we represent the empty tree by 'nil' and the non-empty tree by the list (X L R), where X denotes the information at the root node and L and R denote the left and right subtrees, respectively. The example tree depicted opposite is therefore represented by the following list:
;; (a (b (d nil nil) (e nil nil)) (c nil (f (g nil nil) nil)))
;; Other examples are a binary tree that consists of a root node only:
;; (a nil nil) or an empty binary tree: nil.
;; You can check your functions using these example trees. They are given as test cases in p54.lisp.
;; P54A (*) Check whether a given expression represents a binary tree
;; Write a function istree which returns true if and only if its argument is a list representing a binary tree.
;; Example:
;; * (istree '(a (b nil nil) nil))
;; T
;; * (istree '(a (b nil nil)))
;; NIL
;; P55 (**) Construct completely balanced binary trees
;; In a completely balanced binary tree, the following property holds for every node: The number of nodes in its left subtree and the number of nodes in its right subtree are almost equal, which means their difference is not greater than one.
;; Write a function cbal-tree to construct completely balanced binary trees for a given number of nodes. The function should generate all solutions. Put the symbol 'x' as information into all nodes of the tree.
;; Example:
;; * (cbal-tree-print 4)
;; (X (X NIL NIL) (X NIL (X NIL NIL)))
;; (X (X NIL NIL) (X (X NIL NIL) NIL))
;; etc......
;; Note: you can either print the trees or return a list with them all.
;; * (cbal-tree 4)
;; ((X (X NIL NIL) (X NIL (X NIL NIL))) (X (X NIL NIL) (X (X NIL NIL) NIL)) ......)
;; P56 (**) Symmetric binary trees
;; Let us call a binary tree symmetric if you can draw a vertical line through the root node and then the right subtree is the mirror image of the left subtree. Write a function symmetric to check whether a given binary tree is symmetric. We are only interested in the structure, not in the contents of the nodes.
;; P57 (**) Binary search trees (dictionaries)
;; Write a function to construct a binary search tree from a list of integer numbers.
;; Example:
;; * (construct '(3 2 5 7 1))
;; (3 (2 (1 nil nil) nil) (5 nil (7 nil nil)))
;; Then use this function to test the solution of the problem P56.
;; Example:
;; * (symmetric '(5 3 18 1 4 12 21))
;; T
;; * (symmetric '(3 2 5 7 1))
;; T
;; * (symmetric '(3 2 5 7))
;; NIL
;; P58 (**) Generate-and-test paradigm
;; Apply the generate-and-test paradigm to construct all symmetric, completely balanced binary trees with a given number of nodes. Example:
;; * (sym-cbal-trees-print 5)
;; (X (X NIL (X NIL NIL)) (X (X NIL NIL) NIL))
;; (X (X (X NIL NIL) NIL) (X NIL (X NIL NIL)))
;; ...
;; How many such trees are there with 57 nodes? Investigate about how many solutions there are for a given number of nodes. What if the number is even? Write an appropriate function.
;; P59 (**) Construct height-balanced binary trees
;; In a height-balanced binary tree, the following property holds for every node: The height of its left subtree and the height of its right subtree are almost equal, which means their difference is not greater than one.
;; Write a function hbal-tree to construct height-balanced binary trees for a given height. The function should generate all solutions. Put the letter 'x' as information into all nodes of the tree.
;; Example:
;; * (hbal-tree 3)
;; (X (X (X NIL NIL) (X NIL NIL)) (X (X NIL NIL) (X NIL NIL)))
;; = (X (X (X NIL NIL) (X NIL NIL)) (X (X NIL NIL) NIL))
;; etc......
;; P60 (**) Construct height-balanced binary trees with a given number of nodes
;; Consider a height-balanced binary tree of height H. What is the maximum number of nodes it can contain?
;; Clearly, MAXN = 2**H - 1. However, what is the minimum number MINN? This question is more difficult. Try to find a recursive statement and turn it into a function minnodes defined as follows:
;; (min-nodes H) returns the minimum number of nodes in a height-balanced binary tree of height H.
;; On the other hand, we might ask: what is the maximum height H a height-balanced binary tree with N nodes can have?
;; (max-height N) returns the maximum height of a height-balanced binary tree with N nodes
;; Now, we can attack the main problem: construct all the height-balanced binary trees with a given number of nodes.
;; (hbal-tree-nodes N) returns all height-balanced binary trees with N nodes.
;; Find out how many height-balanced trees exist for N = 15.
;; P61 (*) Count the leaves of a binary tree
;; A leaf is a node with no successors. Write a function count-leaves to count them.
;; (count-leaves tree) returns the number of leaves of binary tree tree
;; P61A (*) Collect the leaves of a binary tree in a list
;; A leaf is a node with no successors. Write a function leaves to return them in a list.
;; (leaves tree) returns the list of all leaves of the binary tree tree
;; P62 (*) Collect the internal nodes of a binary tree in a list
;; An internal node of a binary tree has either one or two non-empty successors. Write a function internals to collect them in a list.
;; (internals tree) returns the list of internal nodes of the binary tree tree.
;; P62B (*) Collect the nodes at a given level in a list
;; A node of a binary tree is at level N if the path from the root to the node has length N-1. The root node is at level 1. Write a function atlevel to collect all nodes at a given level in a list.
;; (atlevel tree L) returns the list of nodes of the binary tree tree at level L
;; Using atlevel it is easy to construct a function levelorder which creates the level-order sequence of the nodes. However, there are more efficient ways to do that.
;; P63 (**) Construct a complete binary tree
;; A complete binary tree with height H is defined as follows: The levels 1,2,3,...,H-1 contain the maximum number of nodes (i.e 2**(i-1) at the level i, note that we start counting the levels from 1 at the root). In level H, which may contain less than the maximum possible number of nodes, all the nodes are "left-adjusted". This means that in a levelorder tree traversal all internal nodes come first, the leaves come second, and empty successors (the nil's which are not really nodes!) come last.
;; Particularly, complete binary trees are used as data structures (or addressing schemes) for heaps.
;; We can assign an address number to each node in a complete binary tree by enumerating the nodes in levelorder, starting at the root with number 1. In doing so, we realize that for every node X with address A the following property holds: The address of X's left and right successors are 2*A and 2*A+1, respectively, supposed the successors do exist. This fact can be used to elegantly construct a complete binary tree structure. Write a function complete-binary-tree with the following specification:
;; (complete-binary-tree N) returns a complete binary tree with N nodes
;; Test your function in an appropriate way.
;; P64 (**) Layout a binary tree (1)
;; Consider a binary tree as the usual symbolic expression (X L R) or nil. As a preparation for drawing the tree, a layout algorithm is required to determine the position of each node in a rectangular grid. Several layout methods are conceivable, one of them is shown in the illustration below.
;; In this layout strategy, the position of a node v is obtained by the following two rules:
;; x(v) is equal to the position of the node v in the inorder sequence
;; y(v) is equal to the depth of the node v in the tree
;; In order to store the position of the nodes, we extend the symbolic expression representing a node (and its successors) as follows:
;; nil represents the empty tree (as usual)
;; (W X Y L R) represents a (non-empty) binary tree with root W "positioned" at (X,Y), and subtrees L and R
;; Write a function layout-binary-tree with the following specification:
;; (layout-binary-tree tree) returns the "positioned" binary tree obtained from the binary tree tree
;; Test your function in an appropriate way.
;; P65 (**) Layout a binary tree (2)
;; An alternative layout method is depicted in the illustration opposite. Find out the rules and write the corresponding Lisp function. Hint: On a given level, the horizontal distance between neighboring nodes is constant.
;; Use the same conventions as in problem P64 and test your function in an appropriate way.
;; P66 (***) Layout a binary tree (3)