Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
  • added_codes
2 results

Target

Select target project
No results found
Select Git revision
  • master
1 result
Show changes
1000 files
+ 182546
1431
Compare changes
  • Side-by-side
  • Inline

Files

+5 −0
Original line number Diff line number Diff line
*.o
*.xopp*
slides/package-lock.json
slides/package.json
slides/.vscode/settings.json
.vscode/settings.json
slides/node_modules/.package-lock.json

README.md

0 → 100644
+17 −0
Original line number Diff line number Diff line
# Remerciements et contributions

Merci aux contributeurs suivants pour leurs efforts (dans un ordre alphabétique):

* P. Albuquerque
* J. Bach
* A. Boyer
* M. Corboz
* M. Divià
* Y. El Hakouni
* A. Escribano
* P. Kunzli
* G. Legouic
* G. Marino Jarrin
* H. Radhwan
* I. Saroukhanian
* C. Volta
+470 −0
Original line number Diff line number Diff line
@charset "UTF-8";

/* Import ET Book styles
   adapted from https://github.com/edwardtufte/et-book/blob/gh-pages/et-book.css */

@font-face {
    font-family: "et-book";
    src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot");
    src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff") format("woff"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf") format("truetype"), url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg#etbookromanosf") format("svg");
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "et-book";
    src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot");
    src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff") format("woff"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf") format("truetype"), url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg#etbookromanosf") format("svg");
    font-weight: normal;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: "et-book";
    src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot");
    src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff") format("woff"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf") format("truetype"), url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg#etbookromanosf") format("svg");
    font-weight: bold;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "et-book-roman-old-style";
    src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot");
    src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot?#iefix") format("embedded-opentype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff") format("woff"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf") format("truetype"), url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg#etbookromanosf") format("svg");
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

/* Tufte CSS styles */
html {
    font-size: 15px;
}

body {
    width: 87.5%;
    margin-left: auto;
    margin-right: auto;
    padding-left: 12.5%;
    font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
    background-color: #fffff8;
    color: #111;
    max-width: 1400px;
    counter-reset: sidenote-counter;
}

h1 {
    font-weight: 400;
    margin-top: 4rem;
    margin-bottom: 1.5rem;
    font-size: 3.2rem;
    line-height: 1;
}

h2 {
    font-style: italic;
    font-weight: 400;
    margin-top: 2.1rem;
    margin-bottom: 1.4rem;
    font-size: 2.2rem;
    line-height: 1;
}

h3 {
    font-style: italic;
    font-weight: 400;
    font-size: 1.7rem;
    margin-top: 2rem;
    margin-bottom: 1.4rem;
    line-height: 1;
}

hr {
    display: block;
    height: 1px;
    width: 55%;
    border: 0;
    border-top: 1px solid #ccc;
    margin: 1em 0;
    padding: 0;
}

p.subtitle {
    font-style: italic;
    margin-top: 1rem;
    margin-bottom: 1rem;
    font-size: 1.8rem;
    display: block;
    line-height: 1;
}

.numeral {
    font-family: et-book-roman-old-style;
}

.danger {
    color: red;
}

article {
    padding: 5rem 0rem;
}

section {
    padding-top: 1rem;
    padding-bottom: 1rem;
}

p,
dl,
ol,
ul {
    font-size: 1.4rem;
    line-height: 2rem;
}

p {
    margin-top: 1.4rem;
    margin-bottom: 1.4rem;
    padding-right: 0;
    vertical-align: baseline;
}

/* Chapter Epigraphs */
div.epigraph {
    margin: 5em 0;
}

div.epigraph > blockquote {
    margin-top: 3em;
    margin-bottom: 3em;
}

div.epigraph > blockquote,
div.epigraph > blockquote > p {
    font-style: italic;
}

div.epigraph > blockquote > footer {
    font-style: normal;
}

div.epigraph > blockquote > footer > cite {
    font-style: italic;
}
/* end chapter epigraphs styles */

blockquote {
    font-size: 1.4rem;
}

blockquote p {
    width: 55%;
    margin-right: 40px;
}

blockquote footer {
    width: 55%;
    font-size: 1.1rem;
    text-align: right;
}

section > p,
section > footer,
section > table {
    width: 55%;
}

/* 50 + 5 == 55, to be the same width as paragraph */
section > dl,
section > ol,
section > ul {
    width: 50%;
    -webkit-padding-start: 5%;
}

dt:not(:first-child),
li:not(:first-child) {
    margin-top: 0.25rem;
}

figure {
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
    max-width: 55%;
    -webkit-margin-start: 0;
    -webkit-margin-end: 0;
    margin: 0 0 3em 0;
}

figcaption {
    float: right;
    clear: right;
    margin-top: 0;
    margin-bottom: 0;
    font-size: 1.1rem;
    line-height: 1.6;
    vertical-align: baseline;
    position: relative;
    max-width: 40%;
}

figure.fullwidth figcaption {
    margin-right: 24%;
}

/* Links: replicate underline that clears descenders */
a:link,
a:visited {
    color: inherit;
}

.no-tufte-underline:link {
    background: unset;
    text-shadow: unset;
}

a:link, .tufte-underline, .hover-tufte-underline:hover {
    text-decoration: none;
    background: -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(#fffff8, #fffff8), -webkit-linear-gradient(currentColor, currentColor);
    background: linear-gradient(#fffff8, #fffff8), linear-gradient(#fffff8, #fffff8), linear-gradient(currentColor, currentColor);
    -webkit-background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
    -moz-background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
    background-size: 0.05em 1px, 0.05em 1px, 1px 1px;
    background-repeat: no-repeat, no-repeat, repeat-x;
    text-shadow: 0.03em 0 #fffff8, -0.03em 0 #fffff8, 0 0.03em #fffff8, 0 -0.03em #fffff8, 0.06em 0 #fffff8, -0.06em 0 #fffff8, 0.09em 0 #fffff8, -0.09em 0 #fffff8, 0.12em 0 #fffff8, -0.12em 0 #fffff8, 0.15em 0 #fffff8, -0.15em 0 #fffff8;
    background-position: 0% 93%, 100% 93%, 0% 93%;
}

@media screen and (-webkit-min-device-pixel-ratio: 0) {
    a:link, .tufte-underline, .hover-tufte-underline:hover {
        background-position-y: 87%, 87%, 87%;
    }
}

a:link::selection,
a:link::-moz-selection {
    text-shadow: 0.03em 0 #b4d5fe, -0.03em 0 #b4d5fe, 0 0.03em #b4d5fe, 0 -0.03em #b4d5fe, 0.06em 0 #b4d5fe, -0.06em 0 #b4d5fe, 0.09em 0 #b4d5fe, -0.09em 0 #b4d5fe, 0.12em 0 #b4d5fe, -0.12em 0 #b4d5fe, 0.15em 0 #b4d5fe, -0.15em 0 #b4d5fe;
    background: #b4d5fe;
}

/* Sidenotes, margin notes, figures, captions */
img {
    max-width: 100%;
}

.sidenote,
.marginnote {
    float: right;
    clear: right;
    margin-right: -60%;
    width: 50%;
    margin-top: 0.3rem;
    margin-bottom: 0;
    font-size: 1.1rem;
    line-height: 1.3;
    vertical-align: baseline;
    position: relative;
}

.sidenote-number {
    counter-increment: sidenote-counter;
}

.sidenote-number:after,
.sidenote:before {
    font-family: et-book-roman-old-style;
    position: relative;
    vertical-align: baseline;
}

.sidenote-number:after {
    content: counter(sidenote-counter);
    font-size: 1rem;
    top: -0.5rem;
    left: 0.1rem;
}

.sidenote:before {
    content: counter(sidenote-counter) " ";
    font-size: 1rem;
    top: -0.5rem;
}

blockquote .sidenote,
blockquote .marginnote {
    margin-right: -82%;
    min-width: 59%;
    text-align: left;
}

div.fullwidth,
table.fullwidth {
    width: 100%;
}

div.table-wrapper {
    overflow-x: auto;
    font-family: "Trebuchet MS", "Gill Sans", "Gill Sans MT", sans-serif;
}

.sans {
    font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
    letter-spacing: .03em;
}

code, pre > code {
    font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
    font-size: 1.0rem;
    line-height: 1.42;
    -webkit-text-size-adjust: 100%; /* Prevent adjustments of font size after orientation changes in iOS. See https://github.com/edwardtufte/tufte-css/issues/81#issuecomment-261953409 */
}

.sans > code {
    font-size: 1.2rem;
}

h1 > code,
h2 > code,
h3 > code {
    font-size: 0.80em;
}

.marginnote > code,
.sidenote > code {
    font-size: 1rem;
}

pre > code {
    font-size: 0.9rem;
    width: 52.5%;
    margin-left: 2.5%;
    overflow-x: auto;
    display: block;
}

pre.fullwidth > code {
    width: 90%;
}

.fullwidth {
    max-width: 90%;
    clear:both;
}

span.newthought {
    font-variant: small-caps;
    font-size: 1.2em;
}

input.margin-toggle {
    display: none;
}

label.sidenote-number {
    display: inline;
}

label.margin-toggle:not(.sidenote-number) {
    display: none;
}

.iframe-wrapper {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 */
    padding-top: 25px;
    height: 0;
}

.iframe-wrapper iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

@media (max-width: 760px) {
    body {
        width: 84%;
        padding-left: 8%;
        padding-right: 8%;
    }

    hr,
    section > p,
    section > footer,
    section > table {
        width: 100%;
    }

    pre > code {
        width: 97%;
    }

    section > dl,
    section > ol,
    section > ul {
        width: 90%;
    }

    figure {
        max-width: 90%;
    }

    figcaption,
    figure.fullwidth figcaption {
        margin-right: 0%;
        max-width: none;
    }

    blockquote {
        margin-left: 1.5em;
        margin-right: 0em;
    }

    blockquote p,
    blockquote footer {
        width: 100%;
    }

    label.margin-toggle:not(.sidenote-number) {
        display: inline;
    }

    .sidenote,
    .marginnote {
        display: none;
    }

    .margin-toggle:checked + .sidenote,
    .margin-toggle:checked + .marginnote {
        display: block;
        float: left;
        left: 1rem;
        clear: both;
        width: 95%;
        margin: 1rem 2.5%;
        vertical-align: baseline;
        position: relative;
    }

    label {
        cursor: pointer;
    }

    div.table-wrapper,
    table {
        width: 85%;
    }

    img {
        width: 100%;
    }
}
Original line number Diff line number Diff line
*.pdf
*.json
*.err
*.markdown
*.html
index.md
.puppeteer.json
+14 −22
Original line number Diff line number Diff line
@@ -8,46 +8,37 @@ PDFOPTIONS += -V themeoptions:numbering=none -V themeoptions:progressbar=foot
PDFOPTIONS += -V fontsize=smaller
PDFOPTIONS += -V urlcolor=blue

REVEALOPTIONS = -t revealjs
REVEALOPTIONS += -F mermaid-filter
REVEALOPTIONS += --self-contained
REVEALOPTIONS += -V revealjs-url=reveal.js
REVEALOPTIONS += -V theme=white
REVEALOPTIONS += -V width=1920
REVEALOPTIONS += -V margin=0
REVEALOPTIONS += --slide-level=1

MD=$(wildcard *.md) # Tous les fichiers .md
PDF=$(MD:%.md=%.pdf) # Pour les fichier pdf on transforme .md -> .pdf
HTML=$(MD:%.md=%.html) # Pour les fichier html on transforme .md -> .html
MARKDOWN=$(MD:%.md=%.markdown) # Pour les fichier markdown on transforme .md -> .markdown
CHROMIUM:=$(shell which chromium || which chromium-browser)

all: puppeteer $(PDF) $(HTML) # La cible par défaut (all) exécute les cibles %.pdf
all: puppeteer $(PDF) 
# all: puppeteer $(PDF) $(HTML) # La cible par défaut (all) exécute les cibles %.pdf

docker: docker-compose.yml
	docker-compose run slides make puppeteer -k || true
	docker-compose run slides make all -k || true
	docker compose run slides

docker_clean: docker-compose.yml
	docker-compose run slides make clean -k || true
	docker compose run slides clean

puppeteer:
	@echo "Setting chromium to $(CHROMIUM) for puppeteer"
	@echo -e "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json
	# @echo "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json

index.md: gen_index.sh
	$(shell ./gen_index.sh)

index:
	rm -f index.md
	./gen_index.sh
index.html: index.md
	pandoc -s $(OPTIONS) --css ../css/tufte-css/tufte.css -o $@ $^

markdown: $(MARKDOWN) # La markdown les cibles %.markdown

%.pdf: %.md metadata.yaml # %.pdf (chaque fichier %.md génère un fichier avec le même nom mais l'extension .pdf et la dépendance metadata.yaml)
	pandoc -s $(OPTIONS) $(PDFOPTIONS) -o $@ $^

%.html: %.md metadata.yaml
	pandoc -s $(OPTIONS) $(REVEALOPTIONS) -o $@ $^

%.markdown: %.md metadata.yaml yq
	sed '1 { /^---/ { :a N; /\n---/! ba; d} }' $< > no_header
	grep -v -F -x -f  no_header $< > header.yaml
@@ -60,11 +51,12 @@ yq: # On peut même télécharger un petit programme avec notre makefile
	wget -nc https://github.com/mikefarah/yq/releases/download/3.4.1/yq_linux_amd64
	chmod "u+x" yq_linux_amd64 

deploy: all 
deploy: all index.html
	mkdir -p algo_cours
	cp *.pdf algo_cours
	cp index.html algo_cours

clean:
	rm -f *.html *.pdf *.markdown yq_linux_amd64* index.md .puppeteer.json
	rm -rf *.html *.pdf *.markdown yq_linux_amd64* index.md .puppeteer.json algo_cours *.err

.PHONY:	clean index puppeteer yq
.PHONY:	clean index.md puppeteer yq
+19 −363
Original line number Diff line number Diff line
---
title: "Introduction aux algorithmes"
date: "2021-09-22"
title: "Introduction aux algorithmes I"
date: "2025-09-16"
---

# Qu'est-ce qu'un algorithme?
@@ -42,7 +42,7 @@ de résoudre typiquement une classe de problèmes ou effectuer un calcul.

. . .

* Opérateurs (arthimétiques / booléens)
* Opérateurs (arithmétiques / booléens)
* Boucles;
* Structures de contrôle;
* Fonctions;
@@ -57,14 +57,12 @@ Nombre premier: nombre possédant deux diviseurs entiers distincts.
## Algorithme naïf (problème)

```C
est_premier(nombre) {
    si {
        pour tout i, t.q. 1 < i < nombre {
booléen est_premier(nombre) 
    si 
        pour tout i, t.q. 1 < i < nombre 
            i ne divise pas nombre
        }
    } alors vrai
    alors vrai
    sinon faux
}
```

. . .
@@ -80,14 +78,12 @@ est_premier(nombre) {
## Algorithme naïf (une solution)

```C
est_premier(nombre) { // fonction
    soit i := 2;       // variable, type, assignation
    tant que i < nombre { // boucle
        si nombre modulo i = 0 { // expression typée
booléen est_premier(nombre) // fonction
    soit i = 2       // variable, type, assignation
    tant que i < nombre // boucle
        si nombre modulo i == 0 // expression typée
            retourne faux    // expression typée
        }
        i := i + 1
    }
        i = i + 1
    retourne vrai // expression typée
```

@@ -103,7 +99,7 @@ bool est_premier(int nombre) {
        if (0 == nombre % i) { // is i divise nombre
            return false; // i n'est pas premier
        }
        i += 1; // sinon on incrémente i
        i = i + 1; // sinon on incrémente i
    }
    return true;
}
@@ -125,9 +121,9 @@ bool est_premier(int nombre) {

- Il existe une multitude d'options de compilation:

    ```bash
    $ gcc -O1 -std=c11 -Wall -Wextra -g porg.c -o prog -fsanitize=address 
    -fsanitize=leak -fsanitize=undefined
    ```console
    $ gcc -O1 -std=c11 -Wall -Wextra -g prog.c -o prog 
    	-fsanitize=address 
    ```
    1. `-std=c11` utilisation de C11.
    2. `-Wall et -Wextra` activation des warnings.
@@ -244,7 +240,7 @@ int main() {

# Quiz: compile ou compile pas?

## [Quiz: compile ou compile pas](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033948)
## [Quiz: compile ou compile pas](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501934)

# Types de base (1/4)

@@ -292,7 +288,7 @@ Type Signification

# Quiz: booléens

## [Quiz: booléens](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1032492)
## [Quiz: booléens](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501922)

<!-- TODO Quiz en ligne -->
<!-- ```C
@@ -336,7 +332,7 @@ if (x) { /* vrai */ }

# Quiz: conversions

## [Quiz: conversions](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033446)
## [Quiz: conversions](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501925)

<!-- TODO Quiz en ligne -->
<!-- ```C
@@ -351,343 +347,3 @@ bool d = 2.78; // 1
bool e = 1.0; // 1
``` -->
# Expressions et opérateurs (1/6)

Une expression est tout bout de code qui est **évalué**.

## Expressions simples

- Pas d'opérateurs impliqués.
- Les littéraux, les variables, et les constantes.

```C
const int L = -1; // 'L' est une constante, -1 un littéral
int x = 0;        // '0' est un litéral
int y = x;        // 'x' est une variable
int z = L;        // 'L' est une constante
```

## Expressions complexes

- Obtenues en combinant des *opérandes* avec des *opérateurs*

```C
int x;     // pas une expression (une instruction)
x = 4 + 5; // 4 + 5 est une expression
           // dont le résultat est affecté à 'x'
```

# Expressions et opérateurs (2/6)

## Opérateurs relationnels

Opérateurs testant la relation entre deux *expressions*:

  - `(a opérateur b)` retourne `1`{.C} si l'expression s'évalue à `true`{.C}, `0`{.C} si l'expression s'évalue à `false`{.C}.

| Opérateur | Syntaxe      | Résultat             |
|-----------|--------------|----------------------|
| `<`{.C}   | `a < b`{.C}  | 1 si a <  b; 0 sinon |
| `>`{.C}   | `a > b`{.C}  | 1 si a >  b; 0 sinon |
| `<=`{.C}  | `a <= b`{.C} | 1 si a <= b; 0 sinon |
| `>=`{.C}  | `a >= b`{.C} | 1 si a >= b; 0 sinon |
| `==`{.C}  | `a == b`{.C} | 1 si a == b; 0 sinon |
| `!=`{.C}  | `a != b`{.C} | 1 si a != b; 0 sinon |

# Expressions et opérateurs (3/6)

## Opérateurs logiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `&&`{.C}  | `a && b`{.C} | ET logique           |
| `||`{.C}  | `a || b`{.C} | OU logique           |
| `!`{.C}   | `!a`{.C}     | NON logique          |

# Quiz: opérateurs logiques

## [Quiz: opérateurs logiques](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033629)

<!-- TODO: Quiz -->
<!-- ```C
1 && 0 == 0
7 && 3 == 1
4 || 3 == 1
!34 == 0
!0 == 1

Soit n un unsigned char initialisé à 127:
!n == 0
``` -->

# Expressions et opérateurs (4/6)

## Opérateurs arithmétiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `+`{.C}   | `a + b`{.C}  | Addition             |
| `-`{.C}   | `a - b`{.C}  | Soustraction         |
| `*`{.C}   | `a * b`{.C}  | Multiplication       |
| `/`{.C}   | `a / b`{.C}  | Division             |
| `%`{.C}   | `a % b`{.C}  | Modulo               |

# Expressions et opérateurs (5/6)

## Opérateurs d'assignation

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `=`{.C}   | `a = b`{.C}  | Affecte la valeur `b` à la variable `a`     |
|           |              | et retourne la valeur de `b`                |
| `+=`{.C}  | `a += b`{.C} | Additionne la valeur de `b` à `a` et        |
|           |              | assigne le résultat à `a`.                  |
| `-=`{.C}  | `a -= b`{.C} | Soustrait la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `*=`{.C}  | `a *= b`{.C} | Multiplie la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `/=`{.C}  | `a /= b`{.C} | Divise la valeur de `b` à `a` et            |
|           |              | assigne le résultat à `a`.                  |
| `%=`{.C}  | `a %= b`{.C} | Calcule le modulo la valeur de `b` à `a` et |
|           |              | assigne le résultat à `a`.                  |

# Expressions et opérateurs (6/6)

## Opérateurs d'assignation (suite)

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `++`{.C}  | `++a`{.C}    | Incrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a += 1`).            |
| `--`{.C}  | `--a`{.C}    | Décrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a -= 1`).            |
| `++`{.C}  | `a++`{.C}    | Retourne `a`{.C} et incrémente `a` de 1.    |
| `--`{.C}  | `a--`{.C}    | Retourne `a`{.C} et décrémente `a` de 1.    |


# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (1/2)

## Syntaxe

```C
if (expression) {
    instructions;
} else if (expression) { // optionnel
                         // il peut y en avoir plusieurs
    instructions;
} else {
    instructions; // optionnel
}
```

```C
if (x) { // si x s'évalue à `vrai`
    printf("x s'évalue à vrai.\n");
} else if (y == 8) { // si y vaut 8
    printf("y vaut 8.\n");
} else {
    printf("Ni l'un ni l'autre.\n");
}
```

# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (2/2)

## Pièges

```C
int x, y;
x = y = 3;
if (x = 2)
    printf("x = 2 est vrai.\n");
else if (y < 8)
    printf("y < 8.\n");
else if (y == 3)
    printf("y vaut 3 mais cela ne sera jamais affiché.\n");
else
    printf("Ni l'un ni l'autre.\n");
    x = -1; // toujours évalué
```

# Quiz: `if ... else`{.C}

## [Quiz: `if ... else`{.C}](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033916)


# Structures de contrôle: `while`{.C}

## La boucle `while`{.C}

```C
while (condition) {
    instructions;
}
do {
    instructions;
} while (condition);
```

## La boucle `while`{.C}, un exemple

```C
int sum = 0; // syntaxe C99
while (sum < 10) {
    sum += 1;
}
do {
    sum += 10;
} while (sum < 100)
```

# Structures de contrôle: `for`{.C}

## La boucle `for`{.C}

```C
for (expression1; expression2; expression3) {
    instructions;
}
```

## La boucle `for`{.C}

```C
int sum = 0; // syntaxe C99
for (int i = 0; i < 10; i++) {
    sum += i;
}

for (int i = 0; i != 1; i = rand() % 4) { // ésotérique
    printf("C'est plus ésotérique.\n");
}
```

# Exercice: la factorielle

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un pseudo-code

. . .

```C
int factorielle(int n) {
    i = 1;
    fact = 1;
    pour i <= n {
        fact *= i;
        i += 1;
    }
}
```

# Exercice: la factorielle

\footnotesize

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un code en C

Quand vous avez fini postez le code sur le salon matrix.

. . .

```C
#include <stdio.h>
int main() {
   int nb = 10;
   int fact = 1;
   int iter = 2;
   while (iter <= nb) {
      fact *= iter;
      iter++;
   }
}
```

. . .

## Comment améliorer ce code? (notez ça sur une feuille)


# Entrées/sorties: `printf()`{.C} (1/2)

## Généralités

- La fonction `printf()`{.C} permet d'afficher du texte sur le terminal:

    ```C
    int printf(const char *format, ...);
    ```
- Nombre d'arguments variables.
- `format`{.C} est le texte, ainsi que le format (type) des variables à afficher.
- Les arguments suivants sont les expressions à afficher.

# Entrées/sorties: `printf()`{.C} (2/2)

## Exemple

```C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Hello world.\n");
    int val = 1;
    printf("Hello world %d time.\n", val);
    printf("%f squared is equal to %f.\n", 2.5, 2.5*2.5);
    return EXIT_SUCCESS;
}
```

# Entrées/sorties: `scanf()`{.C} (1/2)

## Généralités

- La fonction `scanf()`{.C} permet de lire du texte formaté entré au clavier:

    ```C
    int scanf(const char *format, ...);
    ```

- `format`{.C} est le format des variables à lire (comme `printf()`{.C}).
- Les arguments suivants sont les variables où sont stockées les valeurs lues.

# Entrées/sorties: `scanf()`{.C} (2/2)

## Exemple

```C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Enter 3 numbers: \n");
    int i, j, k;
    scanf("%d %d %d", &i, &j, &k);
    printf("You entered: %d %d %d\n", i, j, k);
    
    return EXIT_SUCCESS;
}
```

# Exercice: la factorielle en mieux

## Individuellement

1. Ajoutez des fonctionnalités à votre code.
2. Écrivez l'algorithme de calcul de deux façon différentes.
3. Pour celles et ceux qui ont fini pendant que les autres essaient: faites-le 
   en récursif (sans aide).

. . .

## Postez vos solutions sur matrix!

+302 −159
Original line number Diff line number Diff line
---
title: "Introduction aux algorithmes"
date: "2021-09-29"
title: "Introduction aux algorithmes II"
date: "2025-09-23"
---

# Rappel

* Quel est l'algorithme pour le calcul des nombres 1ers?

. . .

```C
bool est_premier(int nombre) {
    int i = 2; // bonne pratique!
    while (i < nombre) { // penser à bien indenter!
        if (0 == nombre % i) { // ça rend le code LISIBLE!
            return false;
        }
        i += 1;
    }
    return true;
}
```

# Expressions et opérateurs (1/6)

Une expression est tout bout de code qui est **évalué**.

## Expressions simples

- Pas d'opérateurs impliqués.
- Les littéraux, les variables, et les constantes.

```C
const int L = -1; // 'L' est une constante, -1 un littéral
int x = 0;        // '0' est un litéral
int y = x;        // 'x' est une variable
int z = L;        // 'L' est une constante
```

## Expressions complexes

- Obtenues en combinant des *opérandes* avec des *opérateurs*

```C
int x;     // pas une expression (une instruction)
x = 4 + 5; // 4 + 5 est une expression
           // dont le résultat est affecté à 'x'
```

# Expressions et opérateurs (2/6)

## Opérateurs relationnels

Opérateurs testant la relation entre deux *expressions*:

  - `(a opérateur b)` retourne `1`{.C} si l'expression s'évalue à `true`{.C}, `0`{.C} si l'expression s'évalue à `false`{.C}.

| Opérateur | Syntaxe      | Résultat             |
|-----------|--------------|----------------------|
| `<`{.C}   | `a < b`{.C}  | 1 si a <  b; 0 sinon |
| `>`{.C}   | `a > b`{.C}  | 1 si a >  b; 0 sinon |
| `<=`{.C}  | `a <= b`{.C} | 1 si a <= b; 0 sinon |
| `>=`{.C}  | `a >= b`{.C} | 1 si a >= b; 0 sinon |
| `==`{.C}  | `a == b`{.C} | 1 si a == b; 0 sinon |
| `!=`{.C}  | `a != b`{.C} | 1 si a != b; 0 sinon |

# Expressions et opérateurs (3/6)

## Opérateurs logiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `&&`{.C}  | `a && b`{.C} | ET logique           |
| `||`{.C}  | `a || b`{.C} | OU logique           |
| `!`{.C}   | `!a`{.C}     | NON logique          |

# Quiz: opérateurs logiques

## [Quiz: opérateurs logiques](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501928)

<!-- TODO: Quiz -->
<!-- ```C
1 && 0 == 0
7 && 3 == 1
4 || 3 == 1
!34 == 0
!0 == 1

Soit n un unsigned char initialisé à 127:
!n == 0
``` -->

# Expressions et opérateurs (4/6)

## Opérateurs arithmétiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `+`{.C}   | `a + b`{.C}  | Addition             |
| `-`{.C}   | `a - b`{.C}  | Soustraction         |
| `*`{.C}   | `a * b`{.C}  | Multiplication       |
| `/`{.C}   | `a / b`{.C}  | Division             |
| `%`{.C}   | `a % b`{.C}  | Modulo               |

# Expressions et opérateurs (5/6)

## Opérateurs d'assignation

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `=`{.C}   | `a = b`{.C}  | Affecte la valeur `b` à la variable `a`     |
|           |              | et retourne la valeur de `b`                |
| `+=`{.C}  | `a += b`{.C} | Additionne la valeur de `b` à `a` et        |
|           |              | assigne le résultat à `a`.                  |
| `-=`{.C}  | `a -= b`{.C} | Soustrait la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `*=`{.C}  | `a *= b`{.C} | Multiplie la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `/=`{.C}  | `a /= b`{.C} | Divise la valeur de `b` à `a` et            |
|           |              | assigne le résultat à `a`.                  |
| `%=`{.C}  | `a %= b`{.C} | Calcule le modulo la valeur de `b` à `a` et |
|           |              | assigne le résultat à `a`.                  |

# Expressions et opérateurs (6/6)

## Opérateurs d'assignation (suite)

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `++`{.C}  | `++a`{.C}    | Incrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a += 1`).            |
| `--`{.C}  | `--a`{.C}    | Décrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a -= 1`).            |
| `++`{.C}  | `a++`{.C}    | Retourne `a`{.C} et incrémente `a` de 1.    |
| `--`{.C}  | `a--`{.C}    | Retourne `a`{.C} et décrémente `a` de 1.    |


# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (1/2)

## Syntaxe

```C
if (expression) {
    instructions;
} else if (expression) { // optionnel
                         // il peut y en avoir plusieurs
    instructions;
} else {
    instructions; // optionnel
}
```

```C
if (x) { // si x s'évalue à `vrai`
    printf("x s'évalue à vrai.\n");
} else if (y == 8) { // si y vaut 8
    printf("y vaut 8.\n");
} else {
    printf("Ni l'un ni l'autre.\n");
}
```

# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (2/2)

## Pièges

```C
int x, y;
x = y = 3;
if (x = 2)
    printf("x = 2 est vrai.\n");
else if (y < 8)
    printf("y < 8.\n");
else if (y == 3)
    printf("y vaut 3 mais cela ne sera jamais affiché.\n");
else
    printf("Ni l'un ni l'autre.\n");
    x = -1; // toujours évalué
```

# Quiz: `if ... else`{.C}

## [Quiz: `if ... else`{.C}](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=501931)


# Structures de contrôle: `while`{.C}

## La boucle `while`{.C}

```C
while (condition) {
    instructions;
}
do {
    instructions;
} while (condition);
```

## La boucle `while`{.C}, un exemple

```C
int sum = 0; // syntaxe C99
while (sum < 10) {
    sum += 1;
}
do {
    sum += 10;
} while (sum < 100);
```

# Structures de contrôle: `for`{.C}

## La boucle `for`{.C}

```C
for (expression1; expression2; expression3) {
    instructions;
}
```

## La boucle `for`{.C}

```C
int sum = 0; // syntaxe C99
for (int i = 0; i < 10; i++) {
    sum += i;
}

for (int i = 0; i != 1; i = rand() % 4) { // ésotérique
    printf("C'est plus ésotérique.\n");
}
```


# Exercice: la factorielle

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un pseudo-code

. . .

```python
entier factorielle(entier n)
    i = 1
    fact = 1
    tant que i <= n
        fact *= i
        i += 1
    retourne fact
```

# Exercice: la factorielle

\footnotesize

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un code en C

Quand vous avez fini postez le code sur le salon matrix.

. . .

```C
#include <stdio.h>
int main() {
   int nb = 10;
   int fact = 1;
   int iter = 2;
   while (iter <= nb) {
      fact *= iter;
      iter++;
   }
   printf("La factorielle de %d est %d\n", nb, fact);
}
```

. . .

## Comment améliorer ce code? (notez ça sur une feuille)


# Exercice: la factorielle en mieux

## Individuellement

1. Écrivez l'algorithme de calcul de deux façon différentes.
2. Que se passe-t-il si $n>=15$?
3. Pour celles et ceux qui ont fini pendant que les autres essaient: faites-le 
   en récursif (sans aide).

. . .

## Postez vos solutions sur **matrix**!

# Exercice: test si un nombre est premier

## Avec tout ce que vous avez appris la dernière fois:
## Avec tout ce que vous avez appris jusqu'ici:

* Écrivez le code testant si un nombre est premier.
* Quels sont les ajouts possibles par rapport au code de la semaine passée?
@@ -159,12 +457,6 @@ Par groupe de 3 (5-10min):
Si un nombre, `p`, est multiple de `a` et de `b` alors il peut s'écrire `p = a
* i = b * j`  ou encore `p / a = i` et `p / b = j`.

<!-- Si un nombre, $p$, est multiple de $a$ et de $b$ alors il peut s'écrire -->
<!-- $$ -->
<!-- p = a \cdot i = b \cdot j, -->
<!-- $$ -->
<!-- ou encore $p / a = i$ et $p / b = j$. -->

. . .

## Pseudo-code
@@ -172,7 +464,7 @@ Si un nombre, `p`, est multiple de `a` et de `b` alors il peut s'écrire `p = a
```C
int ppcm(int a, int b) {
    for (i in [1, b]) {
        if a * i is divisible by b {
        if a * i est divisible par b {
            return a * i
        }
    }
@@ -191,7 +483,6 @@ int ppcm(int a, int b) {
```C
#include <stdio.h>
#include <stdlib.h> 

int main() { 
   int n = 15, m = 12;
   int i = 1;
@@ -209,7 +500,6 @@ int main() {
```C
#include <stdio.h>
#include <stdlib.h> 

int main() { 
   int res = n*m;
   for (int i = 2; i <= m; i++) {
@@ -222,153 +512,6 @@ int main() {
}
```

# Le calcul du PGCD (1/5)

## Définition

Le plus grand commun diviseur (PGCD) de deux nombres entiers non nuls est le
plus grand entier qui les divise en même temps. 

## Exemples:

```C
PGCD(3, 4) = 1,
PGCD(4, 6) = 2,
PGCD(5, 15) = 5.
```

. . .

## Mathématiquement

Décomposition en nombres premiers:

$$
36 = 2^2\cdot 3^2,\quad 90=2\cdot 5\cdot 3^2,
$$
On garde tous les premiers à la puissance la plus basse
$$
PGCD(36, 90)=2^{\min{1,2}}\cdot 3^{\min{2,2}}\cdot 5^{\min{0,1}}=18.
$$

# Le calcul du PGCD (2/5)

## Algorithme

Par groupe de 3 (5-10min):

* réfléchissez à un algorithme alternatif donnant le PGCD de deux nombres;
* écrivez l'algorithme en pseudo-code.

. . .

## Exemple d'algorithme

```C
PGCD(36, 90):
90 % 36 != 0 // otherwise 36 would be PGCD
90 % 35 != 0 // otherwise 35 would be PGCD
90 % 34 != 0 // otherwise 34 would be PGCD
...
90 % 19 != 0 // otherwise 19 would be PGCD
90 % 18 == 0 // The end!
```

* 18 modulos, 18 assignations, et 18 comparaisons.

# Le calcul du PGCD (3/5)

## Transcrivez cet exemple en algorithme (groupe de 3) et codez-le (5-10min)!

. . .

## Optimisation

* Combien d'additions / comparaisons au pire?
* Un moyen de le rendre plus efficace?

. . .

## Tentative de correction

```C
void main() {
   int n = 90, m = 78;
   int gcd = 1;
   for (int div = n; div >= 2; div--) { // div = m, sqrt(n)
      if (n % div == 0 && m % div == 0) {
         gcd = div;
         break;
      }
   }
   printf("Le pgcd de %d et %d est %d\n", n, m, gcd);
}
```

# Le calcul du PGCD (4/5)

## Réusinage: l'algorithme d'Euclide

`Dividende = Diviseur * Quotient + Reste`

```C
PGCD(35, 60):
35 = 60 * 0 + 35 // 60 -> 35, 35 -> 60
60 = 35 * 1 + 25 // 35 -> 60, 25 -> 35
35 = 25 * 1 + 10 // 25 -> 35, 20 -> 25
25 = 10 * 2 +  5 // 10 -> 25, 5  -> 10
10 =  5 * 2 +  0 // PGCD = 5!
```

. . .

## Algorithme

Par groupe de 3 (5-10min):

* analysez l'exemple ci-dessus;
* transcrivez le en pseudo-code.

# Le calcul du PGCD (5/5)

## Pseudo-code

```C
int pgcd(int a, int b) {
    tmp_n = n
    tmp_m = m
    while (tmp_m does not divide tmp_n) {
        tmp   = tmp_n
        tmp_n = tmp_m
        tmp_m = tmp modulo tmp_m
    }
    return tmp_m
}
```

# Le code du PGCD de 2 nombres

## Implémentez le pseudo-code et postez le code sur matrix (5min).

. . .

## Un corrigé possible

```C
#include <stdio.h>
void main() {
   int n = 90;
   int m = 78;
   printf("n = %d et m = %d\n", n, m);
   int tmp_n = n;
   int tmp_m = m;
   while (tmp_n%tmp_m > 0) {
      int tmp = tmp_n;
      tmp_n = tmp_m;
      tmp_m = tmp % tmp_m;
   }
   printf("Le pgcd de %d et %d est %d\n", n, m, tmp_m);
}
```

+267 −220
Original line number Diff line number Diff line
---
title: "Introduction aux algorithmes"
date: "2021-10-06"
patat:
  eval:
    tai:
      command: fish
      fragment: false
      replace: true
    ccc:
      command: fish
      fragment: false
      replace: true
  images:
    backend: auto
title: "Introduction aux algorithmes III"
date: "2025-09-30"
---

# Quelques algorithmes simples
# Rappel (1/2)

## Quelques algorithmes supplémentaires
## Quels algos avons-nous vu la semaine passée?

* Remplissage d'un tableau et recherche de la valeur minimal
* Anagrammes
* Palindromes
* Crible d'ératosthène
. . .

# Collections: tableaux statiques
* L'algorithme de la factorielle.
* L'algorithme du PPCM.

* Objets de même type: leur nombre est **connu à la compilation**;
* Stockés contigüement en mémoire (très efficace);
# Rappel (2/2)

    ```C
    #define SIZE 10
    int entiers[] = {2, 1, 4, 5, 7}; // taille 5, initialisé
    int tab[3]; // taille 3, non initialisé
    float many_floats[SIZE]; // taille 10, non initialisé
    ```
* Les indices sont numérotés de `0` à `taille-1`;
## Algorithme du PPCM?

    ```C
    int premier = entier[0]; // premier = 2
    int dernier = entier[4]; // dernier = 7
    ```
* Les tableaux sont **non-initialisés** par défaut;
* Les bornes ne sont **jamais** vérifiées.
. . .

```C
    int indetermine_1 = tab[1];     // undefined behavior
    int indetermine_2 = entiers[5]; // UB
int main() { 
    int m = 15, n = 12;
    int mult_m = m, mult_n = n;
    while (mult_m != mult_n) {
        if (mult_m > mult_n) {
            mult_n += n;
        } else {
            mult_m += m;
        }
    }
    printf("Le ppcm de %d et %d est %d\n", n, m, mult_m);
}
```

# Remarques

* Depuis  `C99` possibilité d'avoir des tableaux dont la taille est *inconnue à
  la compilation*;
# Le calcul du PPCM (1/2)

    ```C
    int size;
    scanf("%d", &size);
    char string[size];
    ```
## Réusinage: Comment décrire une fonction qui ferait ce calcul (arguments, sorties)?

. . .

* Considéré comme une mauvaise pratique: que se passe-t-il si `size == 1e9`?
* On préfère utiliser l'allocation **dynamique** de mémoire pour ce genre de
  cas-là (spoiler du futur du cours).

# Initialisation

* Les variables ne sont **jamais** initialisées en `C` par défaut.
* Question: Que contient le tableau suivant?
En `C` on pourrait la décrire comme

```C
    double tab[4];
int ppcm(int a, int b); // La **signature** de cette fonction
```

. . .

* Réponse: On en sait absolument rien!
* Comment initialiser un tableau?
## Algorithme

. . .
Par groupe de 3 (5-10min):

```C
#define SIZE 10
double tab[SIZE];
for (int i = 0; i < SIZE; ++i) {
    tab[i] = rand() / (double)RAND_MAX * 10.0 - 5.0; 
    // tab[i] contient un double dans [-5;5]
}
```
* réfléchissez à un algorithme alternatif donnant le PPCM de deux nombres;
* écrivez l'algorithme en pseudo-code.

# Recherche du minimum dans un tableau (1/2)
. . .

## Problématique
* Si un nombre, `p`, est multiple de `a` et de `b` alors il peut s'écrire `p = a * i = b * j`  ou encore `p / a = i` et `p / b = j`.

Trouver la valeur minimale contenue dans un tableau et l'indice de l'élément le plus petit.

## Écrire un pseudo-code résolvant ce problème (groupe de 3), 2min
# Le calcul du PPCM (2/2)

. . .

## Pseudo-code

```C
index = 0
min   = tab[0]
for i in [1; SIZE] {
    if min > tab[i] {
        min = tab[i]
        index = i
int ppcm(int a, int b) {
    for (i in [1, b]) {
        if a * i est divisible par b {
            return a * i
        }
    }
}
```

# Recherche du minimum dans un tableau (2/2)
# Le code du PPCM de 2 nombres (1/2)

## Implémenter ce bout de code en C (groupe de 3), 4min
## Implémentez le pseudo-code et postez le code sur matrix (5min).

. . .

## Un corrigé possible


```C
int index = 0;
float min = tab[0];
for (int i = 1; i < SIZE; ++i) {
    if min > tab[i] {
        min = tab[i];
        index = i;
#include <stdio.h>
#include <stdlib.h> 
int main() { 
   int n = 15, m = 12;
   int i = 1;
   while (n * i % m != 0) {
      i++;
   }
   printf("Le ppcm de %d et %d est %d\n", n, m, n*i);
}
```

# Tri par sélection (1/2)

## Problématique

Trier un tableau par ordre croissant.
# Le code du PPCM de 2 nombres (2/2)

## Idée d'algorithme
## Corrigé alternatif

```C
ind = 0
boucle (ind < SIZE-1) {
    Trouver le minimum du tableau, tab_min[ind:SIZE].
    Échanger tab_min avec tab[ind]
    ind += 1
#include <stdio.h>
#include <stdlib.h> 
int main() { 
   int res = n*m;
   for (int i = 2; i <= m; i++) {
     if (n * i % m == 0) {
        res = n * i;
        break;
     }
   }
   printf("Le ppcm de %d et %d est %d\n", n, m, res);
}
```

# Tri par sélection (2/2)

## Implémentation par groupe de 3

* Initialiser aléatoirement un tableau de `double` de taille 10;
* Afficher le tableau;
* Trier par sélection le tableau;
* Afficher le résultat trié;
* Vérifier algorithmiquement que le résultat est bien trié.

# Un type de tableau particulier

## Les chaînes de caractères
# Le calcul du PGCD (1/5)

```C
string = tableau + char + magie noire
```
## Définition

# Le type `char`{.C}
Le plus grand commun diviseur (PGCD) de deux nombres entiers non nuls est le
plus grand entier qui les divise en même temps. 

- Le type `char`{.C} est utilisé pour représenter un caractère.
- C'est un entier 8 bits signé.
- En particulier:
    - Écrire
## Exemples:

```C
        char c = 'A';
PGCD(3, 4) = 1,
PGCD(4, 6) = 2,
PGCD(5, 15) = 5.
```
    - Est équivalent à:

        ```C
        char c = 65;
        ```
- Les fonctions d'affichage interprètent le nombre comme sa valeur ASCII.
. . .

# Chaînes de caractères (strings)
## Mathématiquement

- Chaîne de caractère `==` tableau de caractères **terminé par la valeur** `'\0'`{.C} ou `0`{.C}.
Décomposition en nombres premiers:

## Exemple
$$
36 = 2^2\cdot 3^2,\quad 90=2\cdot 5\cdot 3^2,
$$
On garde tous les premiers à la puissance la plus basse
$$
PGCD(36, 90)=2^{\min{1,2}}\cdot 3^{\min{2,2}}\cdot 5^{\min{0,1}}=18.
$$

# Le calcul du PGCD (2/5)

## Algorithme

Par groupe de 3 (5-10min):

* réfléchissez à un algorithme alternatif donnant le PGCD de deux nombres;
* écrivez l'algorithme en pseudo-code.

. . .

## Exemple d'algorithme

```C
char *str  = "HELLO !";
char str[] = "HELLO !";
PGCD(36, 90):
90 % 36 != 0 // otherwise 36 would be PGCD
90 % 35 != 0 // otherwise 35 would be PGCD
90 % 34 != 0 // otherwise 34 would be PGCD
...
90 % 19 != 0 // otherwise 19 would be PGCD
90 % 18 == 0 // The end!
```

Est représenté par
* 18 modulos, 18 assignations, et 18 comparaisons.

| `char`  | `H`  | `E`  | `L`  | `L`  | `O`  |      | `!`  | `\0`|
|---------|------|------|------|------|------|------|------|-----|
| `ASCII` | `72` | `69` | `76` | `76` | `79` | `32` | `33` | `0` |
# Le calcul du PGCD (3/5)

. . .
\footnotesize

## A quoi sert le `\0`?
## Transcrivez cet exemple en algorithme et codez-le (5-10min)!

. . .

Permet de connaître la fin de la chaîne de caractères (pas le cas des autres
sortes de tableaux).
## Optimisation

# Syntaxe
* Combien d'additions / comparaisons au pire?
* Un moyen de le rendre plus efficace?

. . .

## Tentative de correction

```C
char name[5];
name[0] = 'P';  // = 70;
name[1] = 'a';  // = 97;
name[2] = 'u';  // = 117;
name[3] = 'l';  // = 108;
name[4] = '\0'; // = 0;
char name[] = {'P', 'a', 'u', 'l', '\0'};
char name[5] = "Paul";
char name[] = "Paul";
char name[100] = "Paul is not 100 characters long.";
void main() {
   int n = 90, m = 78;
   int gcd = 1;
   for (int div = n; div >= 2; div--) { // div = m, sqrt(n)
      if (n % div == 0 && m % div == 0) {
         gcd = div;
         break;
      }
   }
   printf("Le pgcd de %d et %d est %d\n", n, m, gcd);
}
```

# Fonctions
# Le calcul du PGCD (4/5)

## Réusinage: l'algorithme d'Euclide

- Il existe une grande quantités de fonction pour la manipulation de chaînes de caractères dans `string.h`.
- Fonctions principales:
`Dividende = Diviseur * Quotient + Reste`

```C
    // longueur de la chaîne (sans le \0)
    size_t strlen(char *str);
    // copie jusqu'à un \0
    char *strcpy(char *dest, const char *src);
     // copie len char
    char *strncpy(char *dest, const char *src, size_t len);
    // compare len chars
    int strncmp(char *str1, char *str2, size_t len);
    // compare jusqu'à un \0
    int strcmp(char *str1, char *str2);
PGCD(35, 60):
35 = 60 * 0 + 35 // 60 -> 35, 35 -> 60
60 = 35 * 1 + 25 // 35 -> 60, 25 -> 35
35 = 25 * 1 + 10 // 25 -> 35, 20 -> 25
25 = 10 * 2 +  5 // 10 -> 25, 5  -> 10
10 =  5 * 2 +  0 // PGCD = 5!
```

- Pour avoir la liste complète: `man string`.

. . .

## Quels problèmes peuvent se produire avec `strlen`, `strcpy`, `strcmp`?
## Algorithme

# Les anagrammes
Par groupe de 3 (5-10min):

## Définition

Deux mots sont des anagrammes l'un de l'autre quand ils contiennent les mêmes 
lettres mais dans un ordre différent.
* analysez l'exemple ci-dessus;
* transcrivez le en pseudo-code.

## Exemple
# Le calcul du PGCD (5/5)

| `t`  | `u`  | `t`  | `u`  | `t`  | `\0` | ` `  | ` ` |
|------|------|------|------|------|------|------|-----|
| `t`  | `u`  | `t`  | `t`  | `u`  | `\0` | ` `  | ` ` |
## Pseudo-code

```C
entier pgcd(m, n)
    tmp_n = n
    tmp_m = m
    tant que (tmp_m ne divise pas tmp_n)
        tmp   = tmp_n
        tmp_n = tmp_m
        tmp_m = tmp modulo tmp_m
    retourne tmp_m

## Problème: Trouvez un algorithme pour déterminer si deux mots sont des anagrammes.
```

# Les anagrammes
# Le code du PGCD de 2 nombres

## Il suffit de:
## Implémentez le pseudo-code et postez le code sur matrix (5min).

1. Trier les deux mots.
2. Vérifier s'ils contiennent les mêmes lettres.
. . .

## Implémentation en live (offerte par HepiaVPN)
## Un corrigé possible

```C
int main() { // pseudo C
    tri(mot1);
    tri(mot2);
    if egalite(mot1, mot2) {
        // anagrammes
    } else {
        // pas anagrammes
#include <stdio.h>
void main() {
   int n = 90;
   int m = 78;
   printf("n = %d et m = %d\n", n, m);
   int tmp_n = n;
   int tmp_m = m;
   while (tmp_n%tmp_m > 0) {
      int tmp = tmp_n;
      tmp_n = tmp_m;
      tmp_m = tmp % tmp_m;
   }
   printf("Le pgcd de %d et %d est %d\n", n, m, tmp_m);
}
```

<!-- TODO: Live implémentation hors des cours? -->

# Les palindromes
# Quelques algorithmes simples

Mot qui se lit pareil de droite à gauche que de gauche à droite:
* Stockage d'une liste de nombre et recherche de la valeur minimale
* Anagrammes
* Palindromes
* Crible d’Ératosthène

. . .

* rotor, kayak, ressasser, ...
* Ces algorithme nécessitent d'utiliser des **tableaux**.

# Collections: tableaux statiques

\footnotesize

## Problème: proposer un algorithme pour détecter un palindrome
* Objets de même type: leur nombre est **connu à la compilation**
* Stockés de façon contiguë en mémoire (très efficace)

    ```C
    #define SIZE 10
    int entiers[] = {2, 1, 4, 5, 7}; // taille 5, initialisé
    int tab[3]; // taille 3, non initialisé
    float many_floats[SIZE]; // taille 10, non initialisé
    ```
* Les indices sont numérotés de `0` à `taille-1`;

    ```C
    int premier = entier[0]; // premier = 2
    int dernier = entier[4]; // dernier = 7
    ```
* Les tableaux sont **non-initialisés** par défaut;
* Les bornes ne sont **jamais** vérifiées.

    ```C
    int indetermine_1 = tab[1];     // undefined behavior
    int indetermine_2 = entiers[5]; // UB
    ```

# Remarques

* Depuis  `C99` la taille peut être *inconnue à la compilation* (VLA);

    ```C
    int size;
    scanf("%d", &size);
    char string[size];
    ```

 . . .

## Solution 1
* Considéré comme une mauvaise pratique: que se passe-t-il si `size == 1e9`?
* On préfère utiliser l'allocation **dynamique** de mémoire pour ce genre de cas-là (spoiler du futur du cours).

# Initialisation

* Les variables ne sont **jamais** initialisées en `C` par défaut.
* Question: Que contient le tableau suivant?

    ```C
while (first_index < last_index {
    if (mot[first_index] != mot [last_index]) {
        return false;
    }
    first_index += 1;
    last_index -= 1;
}
return true;
    double tab[4];
    ```

. . .

## Solution 2
* Réponse: On en sait absolument rien!
* Comment initialiser un tableau?

. . .

```C
mot_tmp = revert(mot);
return mot == mot_tmp;
#define SIZE 10
double tab[SIZE];
for (int i = 0; i < SIZE; ++i) {
    tab[i] = rand() / (double)RAND_MAX * 10.0 - 5.0; 
    // tab[i] contient un double dans [-5;5]
}
int other_tab[4] = {0}; // pareil que {0, 0, 0, 0}
```

# Crible d'Ératosthène
# Recherche du minimum dans un tableau (1/2)

## Problématique

Algorithme de génération de nombres premiers.
Trouver la valeur minimale contenue dans un tableau et l'indice de l'élément le plus petit.

## Exercice
## Écrire un pseudo-code résolvant ce problème (groupe de 3), 2min

* À l'aide d'un tableau de booléens,
* Générer les nombres premiers plus petits qu'un nombre $N$
. . .

## Pseudo-code
```C
index = 0
min   = tab[0]
pour i de 1 à SIZE - 1
    si min > tab[i]
        min = tab[i]
        index = i
```

* Par groupe de trois, réfléchir à un algorithme.
# Recherche du minimum dans un tableau (2/2)

## Programme en C
## Implémenter ce bout de code en C (groupe de 3), 4min

* Implémenter l'algorithme et le poster sur le salon `Element`.
. . .

```C
int index = 0;
float min = tab[0];
for (int i = 1; i < SIZE; ++i) {
    if (min > tab[i]) {
        min = tab[i];
        index = i;
    }
}
```
+146 −572
Original line number Diff line number Diff line
---
title: "Introduction aux algorithmes"
date: "2021-10-13"
patat:
  eval:
    tai:
      command: fish
      fragment: false
      replace: true
    ccc:
      command: fish
      fragment: false
      replace: true
  images:
    backend: auto
title: "Introduction aux algorithmes IV"
date: "2025-10-07"
---

# Crible d'Ératosthène: solution
# Le tri par sélection

\footnotesize

```C
#include <stdio.h>
#include <stdbool.h>
#define SIZE 51
int main() {
   bool tab[SIZE];
   for (int i=0;i<SIZE;i++) {
      tab[i] = true;  
   }
   for (int i = 2; i < SIZE; i++) {
      if (tab[i]) {
         printf("%d ", i);
         int j = i;
         while (j < SIZE) {
            j += i;
            tab[j] = false;
         } 
      } 
   }
   printf("\n");
}
```


# Réusinage de code (refactoring)

## Le réusinage est?

. . .

* le processus de restructuration d'un programme:
    * en modifiant son design,
    * en modifiant sa structure,
    * en modifiant ses algorithmes
    * mais en **conservant ses fonctionalités**.

. . .

## Avantages?

. . .

* Amélioration de la lisibilité,
* Amélioration de la maintenabilité,
* Réduction de la complexité.

. . .

## "Make it work, make it nice, make it fast",  Kent Beck.

. . .

## Exercice:
\Huge Le tri par sélection

* Réusiner le code se trouvant sur
  [Cyberlearn](https://cyberlearn.hes-so.ch/mod/resource/view.php?id=1627712).
# Tri par sélection (1/3)

# Tableau à deux dimensions (1/4)
## Problématique

## Mais qu'est-ce donc?

. . .
Trier un tableau par ordre croissant.

* Un tableau où chaque cellule est un tableau.

## Quels cas d'utilisation?

. . .

* Tableau à double entrée;
* Image;
* Écran (pixels);
* Matrice (mathématique);
 
# Tableau à deux dimensions (2/4)

## Exemple: tableau à 3 lignes et 4 colonnes d'entiers

+-----------+-----+-----+-----+-----+
| `indices` | `0` | `1` | `2` | `3` |
+-----------+-----+-----+-----+-----+
| `0`       | `7` | `4` | `7` | `3` |
+-----------+-----+-----+-----+-----+
| `1`       | `2` | `2` | `9` | `2` |
+-----------+-----+-----+-----+-----+
| `2`       | `4` | `8` | `8` | `9` |
+-----------+-----+-----+-----+-----+

## Syntaxe
## Idée d'algorithme

```C
int tab[3][4]; // déclaration d'un tableau 4x3
tab[2][1]; // accès à la case 2, 1
tab[2][1] = 14; // assignation de 14 à la position 2, 1
ind = 0
tant que (ind < SIZE-1)
    Trouver le minimum du tableau, tab_min = min([ind:SIZE-1]).
    Échanger tab_min avec tab[ind]
    ind += 1
```

# Tableau à deux dimensions (3/4)
# Tri par sélection (2/3)

## Exercice: déclarer et initialiser aléatoirement un tableau `50x100`
## Quel est l'algorithme du tri par sélection?

. . .

```C
#define NX 50
#define NY 100
int tab[NX][NY];
for (int i = 0; i < NX; ++i) {
    for (int j = 0; j < NY; ++j) {
        tab[i][j] = rand() % 256; // 256 niveaux de gris
    }
}
```
1. Soit un tableau d'entiers, `tab[0:SIZE-1]` et `i = 0`.
2. Trouver l'indice, `j`, de `tab[i:SIZE-1]` où la valeur est minimale.
3. Échanger `tab[i]` et `tab[j]`.
4. `i += 1` et revenir à 2, tant que `i < SIZE-1`.

## Exercice: afficher le tableau
# Tri par sélection (3/3)

. . .
## Implémentation par groupe de 3

```C
for (int i = 0; i < NX; ++i) {
    for (int j = 0; j < NY; ++j) {
        printf("%d ", tab[i][j]);
    }
    printf("\n");
}
```
* Initialiser aléatoirement un tableau de `double` de taille 10;
* Afficher le tableau;
* Trier par sélection le tableau;
* Afficher le résultat trié;
* Vérifier algorithmiquement que le résultat est bien trié.

# Les chaînes de caractères

# Tableau à deux dimensions (4/4)
\Huge Les chaînes de caractères

## Attention
# Un type de tableau particulier

* Les éléments ne sont **jamais** initialisés.
* Les bornes ne sont **jamais** vérifiées.
## Les chaînes de caractères

```C
    int tab[3][2] = { {1, 2}, {3, 4}, {5, 6} };
    printf("%d\n", tab[2][1]);  // affiche?
    printf("%d\n", tab[10][9]); // affiche?
    printf("%d\n", tab[3][1]);  // affiche?
string = tableau + char + magie noire
```

# La couverture de la reine

* Aux échecs la reine peut se déplacer horizontalement et verticalement
* Pour un échiquier `5x6`, elle *couvre* les cases comme ci-dessous

+-----+-----+-----+-----+-----+-----+-----+
| ` ` | `0` | `1` | `2` | `3` | `4` | `5` |
+-----+-----+-----+-----+-----+-----+-----+
| `0` | `*` | ` ` | `*` | ` ` | `*` | ` ` |
+-----+-----+-----+-----+-----+-----+-----+
| `1` | ` ` | `*` | `*` | `*` | ` ` | ` ` |
+-----+-----+-----+-----+-----+-----+-----+
| `2` | `*` | `*` | `R` | `*` | `*` | `*` |
+-----+-----+-----+-----+-----+-----+-----+
| `3` | ` ` | `*` | `*` | `*` | ` ` | ` ` |
+-----+-----+-----+-----+-----+-----+-----+
| `4` | `*` | ` ` | `*` | ` ` | `*` | ` ` |
+-----+-----+-----+-----+-----+-----+-----+

## Exercice

* En utilisant les conditions, les tableaux à deux dimensions, et des
  `char` uniquement.
* Implémenter un programme qui demande à l'utilisateur d'entrer les
  coordonnées de la reine et affiche un tableau comme ci-dessus pour un
  échiquier `8x8`.
# Le type `char`{.C}

## Poster le résultat sur `Element`

# Types énumérés (1/2)

* Un **type énuméré**: ensemble de *variantes* (valeurs constantes).
* En `C` les variantes sont des entiers numérotés à partir de 0.
- Le type `char`{.C} est utilisé pour représenter un caractère.
- C'est un entier 8 bits signé.
- En particulier:
    - Écrire
        
        ```C
    enum days {
        monday, tuesday, wednesday,
        thursday, friday, saturday, sunday
    };
        char c = 'A';
        ```
* On peut aussi donner des valeurs "custom"
    - Est équivalent à:

        ```C
    enum days {
        monday = 2, tuesday = 8, wednesday = -2,
        thursday = 1, friday = 3, saturday = 12, sunday = 9
    };
        char c = 65;
        ```
* S'utilise comme un type standard et un entier
- Les fonctions d'affichage interprètent le nombre comme sa valeur ASCII.

    ```C
    enum days d = monday;
    (d + 2) == tuesday + tuesday; // true
    ```
# Chaînes de caractères (strings)

# Types énumérés (2/2)
- Chaîne de caractère `==` tableau de caractères **terminé par la valeur** `'\0'`{.C} ou `0`{.C}.

* Très utile dans les `switch ... case`{.C}
## Exemple

```C
    enum days d = monday;
    switch (d) {
        case monday:
            // trucs
            break;
        case tuesday:
            printf("0 ou 1\n");
            break;
    }
char *str  = "HELLO !";
char str[] = "HELLO !";
```
* Le compilateur vous prévient qu'il en manque!

# Utilisation des types énumérés

## Réusiner votre couverture de la reine avec des `enum`

# Représentation des nombres (1/2)

* Le nombre `247`.

## Nombres décimaux: Les nombres en base 10 

+--------+--------+--------+
| $10^2$ | $10^1$ | $10^0$ |
+--------+--------+--------+
| `2`    | `4`    | `7`    |
+--------+--------+--------+

$$
247 = 2\cdot 10^2 + 4\cdot 10^1 + 7\cdot 10^0.
$$

# Représentation des nombres (2/2)

* Le nombre `11110111`.
Est représenté par

## Nombres binaires: Les nombres en base 2

+-------+-------+-------+-------+-------+-------+-------+-------+
| $2^7$ | $2^6$ | $2^5$ | $2^4$ | $2^3$ | $2^2$ | $2^1$ | $2^0$ |
+-------+-------+-------+-------+-------+-------+-------+-------+
| `1`   | `1`   | `1`   | `1`   | `0`   | `1`   | `1`   | `1`   |
+-------+-------+-------+-------+-------+-------+-------+-------+
 
$$
1\cdot 2^7 + 1\cdot 2^6 +1\cdot 2^5 +1\cdot 2^4 +0\cdot 2^3 +1\cdot 2^2
+1\cdot 2^1 +1\cdot 2^0
$$
| `char`  | `H`  | `E`  | `L`  | `L`  | `O`  |      | `!`  | `\0`|
|---------|------|------|------|------|------|------|------|-----|
| `ASCII` | `72` | `69` | `76` | `76` | `79` | `32` | `33` | `0` |

. . .

$$
= 247.
$$

# Conversion de décimal à binaire (1/2)

## Convertir 11 en binaire?
## A quoi sert le `\0`?

. . .

* On décompose en puissances de 2 en partant de la plus grande possible

    ```
    11 / 8 = 1, 11 % 8 = 3
    3  / 4 = 0,  3 % 4 = 3
    3  / 2 = 1,  3 % 2 = 1
    1  / 1 = 1,  1 % 1 = 0
    ```
* On a donc

    $$
    1011 \Rightarrow 1\cdot 2^3 + 0\cdot 2^2 + 1\cdot 2^1 + 1\cdot
    2^0=11.
    $$

# Conversion de décimal à binaire (2/2)
Permet de connaître la fin de la chaîne de caractères (pas le cas des autres
sortes de tableaux).

## Convertir un nombre arbitraire en binaire: 247?

* Par groupe établir un algorithme.

. . .

## Algorithme

1. Initialisation
    
    ```C
    num = 247
    while (2^N < num) {
        N += 1
    }
    ```

. . .

2. Boucle
# Syntaxe

```C
    while (N >= 0) {
        bit = num / 2^N
        num = num % 2^N
        N += 1
    }
    ```

# Les additions en binaire

Que donne l'addition `1101` avec `0110`?

* L'addition est la même que dans le système décimal

char name[5];
name[0] = 'P';  // = 70;
name[1] = 'a';  // = 97;
name[2] = 'u';  // = 117;
name[3] = 'l';  // = 108;
name[4] = '\0'; // = 0;
char name[] = {'P', 'a', 'u', 'l', '\0'};
char name[5] = "Paul";
char name[] = "Paul";
char name[100] = "Paul is not 100 characters long.";
```
       1101         8+4+0+1 = 13
    +  0110    +    0+4+2+0 =  6
    -------    -----------------
      10011      16+0+0+2+1 = 19
    ```
* Les entiers sur un ordinateur ont une précision **fixée** (ici 4 bits).
* Que se passe-t-il donc ici?

. . .

## Dépassement de capacité: le nombre est "tronqué"

* `10011 (19) -> 0011 (3)`.
* On fait "le tour"."

# Entier non-signés minimal/maximal

* Quel est l'entier non-signé maximal représentable avec 4 bit?

. . .

$$
(1111)_2 = 8+4+2+1 = 15
$$
# Fonctions

* Quel est l'entier non-signé minimal représentable avec 4 bit?

. . .

$$
(0000)_2 = 0+0+0+0 = 0
$$

* Quel est l'entier non-signé min/max représentable avec N bit?

. . .

$$
0\mbox{ et  }2^N-1.
$$

* Donc `uint32_t?` maximal est?

. . .

$$
4294967295
$$


# Les multiplications en binaire (1/2)

Que donne la multiplication de `1101` avec `0110`?
\footnotesize

* L'addition est la même que dans le système décimal
- Il existe une grande quantités de fonction pour la manipulation de chaînes de caractères dans `string.h`.
- Fonctions principales:

    ```C
    // longueur de la chaîne (sans le \0)
    size_t strlen(char *str);
    // copie jusqu'à un \0
    char *strcpy(char *dest, const char *src);
     // copie len char
    char *strncpy(char *dest, const char *src, size_t len);
    // compare len chars
    int strncmp(char *str1, char *str2, size_t len);
    // compare jusqu'à un \0
    int strcmp(char *str1, char *str2);
    ```
         1101                13
    *    0110    *            6
    ---------    --------------
         0000                78
        11010
       110100
    + 0000000
    ---------    --------------
      1001110    64+0+0+8+4+2+0
    ```

# Les multiplications en binaire (2/2)

## Que fait la multiplication par 2?
- Pour avoir la liste complète: `man 3 string`.

. . .

* Décalage de un bit vers la gauche!

    ```
         0110
    *    0010
    ---------
         0000
    +   01100
    ---------
        01100
    ```
## Quel problème peut se produire avec `strlen`, `strcpy`, `strcmp`?

. . .

## Que fait la multiplication par $2^N$?
- Si `\0` est absent... on a un comportement indéfini.

. . .
# Les anagrammes

* Décalade de $N$ bits vers la gauche!
\Huge Les anagrammes

# Entiers signés (1/2)
# Les anagrammes

Pas de nombres négatifs encore...
## Définition

## Comment faire?
Deux mots sont des anagrammes l'un de l'autre quand ils contiennent les mêmes 
lettres mais dans un ordre différent.

. . .
## Exemple

## Solution naïve:
| `t`  | `u`  | `t`  | `u`  | `t`  | `\0` | ` `  | ` ` |
|------|------|------|------|------|------|------|-----|
| `t`  | `u`  | `t`  | `t`  | `u`  | `\0` | ` `  | ` ` |

* On ajoute un bit de signe (le bit de poids fort):

    ```
    00000010: +2
    10000010: -2
    ```
## Problème: Trouvez un algorithme pour déterminer si deux mots sont des anagrammes.

## Problèmes?
# Les anagrammes

. . .

* Il y a deux zéros (pas trop grave): `10000000` et `00000000`
* Les additions différentes que pour les non-signés (très grave)
    
    ```
      00000010              2    
    + 10000100           + -4
    ----------           ----
      10000110 = -6  !=    -2
    ```

# Entiers signés (2/2)

## Beaucoup mieux

* Complément à un:
    * on inverse tous les bits: `1001 => 0110`.

## Encore un peu mieux

* Complément à deux:
    * on inverse tous les bits,
    * on ajoute 1 (on ignore les dépassements).

. . .
## Il suffit de:

* Comment écrit-on `-4` en 8 bits?
1. Trier les deux mots.
2. Vérifier s'ils contiennent les mêmes lettres.

. . .

```
     4 =  00000100
            ________
    -4 =>   00000100
            
            11111011
          + 00000001 
          ----------
            11111100
```

# Le complément à 2 (1/2)

## Questions:
## Implémentation ensemble

* Comment on écrit `+0` et `-0`?
* Comment calcule-t-on `2 + (-4)`?
* Quel est le complément à 2 de `1000 0000`?

. . .

## Réponses

* Comment on écrit `+0` et `-0`?

    ```
    +0 = 00000000
    -0 = 11111111 + 00000001 = 100000000 => 00000000 
```C
int main() { // pseudo C
    tri(mot1);
    tri(mot2);
    if egalite(mot1, mot2) {
        // anagrammes
    } else {
        // pas anagrammes
    }
}
```
* Comment calcule-t-on `2 + (-4)`?

    ```
      00000010            2
    + 11111100        +  -4
    ----------        -----
      11111110           -2
    ```
* En effet
# Les palindromes

    ```
    11111110 => 00000001 + 00000001 = 00000010 = 2.
    ```
\Huge Les palindromes

# Le complément à 2 (1/2)
# Les palindromes

## Quels sont les entiers représentables en 8 bits?
Mot qui se lit pareil de droite à gauche que de gauche à droite:

. . .

```
01111111 =>  127
10000000 => -128 // par définition
```
* rotor, kayak, ressasser, ...

## Quels sont les entiers représentables sur $N$ bits?
## Problème: proposer un algorithme pour détecter un palindrome

. . .

$$
-2^{N-1} ... 2^{N-1}-1.
$$

## Remarque: dépassement de capacité en `C`

* Comportement indéfini!


<!-- # TODO --

<!-- ## Entiers, entiers non-signés -->

<!-- ## Complément à 1, 2 -->

<!-- ## Nombres à virgule flottante, simple/double précision -->

# Types composés: `struct`{.C} (1/6)

## Fractions

* Numérateur: `int num`;
* Dénominateur: `int denom`.

## Addition
## Solution 1

```C
int num1 = 1, denom1 = 2;
int num2 = 1, denom2 = 3;
int num3 = num1 * denom2 + num2 * denom1;
int denom3 = denom1 * denom2;
```

## Pas super pratique....

# Types composés: `struct`{.C} (2/6)

## On peut faire mieux

* Plusieurs variables qu'on aimerait regrouper dans un seul type: `struct`{.C}.

```C
struct fraction { // déclaration du type
    int32_t num, denom;
while (first_index < last_index) {
    if (mot[first_index] != mot [last_index]) {
        return false;
    }

struct fraction frac; // déclaration de frac
```

# Types composés: `struct`{.C} (3/6)

## Simplifications

- `typedef`{.C} permet de définir un nouveau type.

    ```C
    typedef unsinged int uint;
    typedef struct fraction fraction_t;
    typedef struct fraction {
        int32_t num, denom;
    } fraction_t;
    ```
- L'initialisation peut aussi se faire avec

    ```C
    fraction_t frac = {1, -2}; // num = 1, denom = -2
    fraction_t frac = {.denom = 1, .num = -2};
    fraction_t frac = {.denom = 1}; // argl! .num non initialisé 
    fraction_t frac2 = frac; // copie
    first_index += 1;
    last_index -= 1;
}
return true;
```

# Types composés: `struct`{.C} (4/6)

## Pointeurs
. . .

- Comme pour tout type, on peut avoir des pointeurs vers un `struct`{.C}.
- Les champs sont accessible avec le sélecteur `->`{.C}
## Solution 2

```C
    fraction_t *frac; // on crée un pointeur
    frac->num = 1;    // seg fault...
    frac->denom = -1; // mémoire pas allouée.
mot_tmp = revert(mot);
return mot == mot_tmp;
```

![La représentation mémoire de
`fraction_t`.](figs/pointer_struct.svg){width=50%}
# Le crible d'Ératosthène

# Types composés: `struct`{.C} (5/6)
\Huge Le crible d'Ératosthène

## Initialisation
# Crible d'Ératosthène

- Avec le passage par **référence** on peut modifier un struct *en place*.
- Les champs sont accessible avec le sélecteur `->`{.C}
Algorithme de génération de nombres premiers.

    ```C
    void fraction_init(fraction_t *frac, 
                      int32_t re, int32_t im) 
    {
        // frac a déjà été allouée
        frac->num   = frac;
        frac->denom = denom;
    }
    int main() {
        fraction_t frac; // on alloue une fraction
        fraction_init(&frac, 2, -1); // on l'initialise
    }
    ```
## Exercice

# Types composés: `struct`{.C} (6/6)
* À l'aide d'un tableau de booléens,
* Générer les nombres premiers plus petits qu'un nombre $N$

## Initialisation version copie
## Pseudo-code

* On peut allouer une fraction, l'initialiser et le retourner.
* La valeur retournée peut être copiée dans une nouvelle structure.
* Par groupe de trois, réfléchir à un algorithme.

    ```C
    fraction_t fraction_create(int32_t re, int32_t im) {
        fraction_t frac;
        frac.num = re;
        frac.denom = im;
        return frac;
    }
    int main() {
        // on crée une fraction et on l'initialise
        // en copiant la fraction créé par fraction_create
        // deux allocation et une copie
        fraction_t frac = fraction_create(2, -1); 
    }
    ```
## Programme en C

<!-- # TODO jusqu'aux vacances -->
* Implémenter l'algorithme et le poster sur le salon `Element`.
<!-- * Refactorisation -->
<!-- * Tris et complexité -->
<!-- * Récursivité -->
Original line number Diff line number Diff line
version: "3.3"
services:
    slides:
        #To use dockerfile : build: . 
        image:  omalaspinas/pandoc:latest
        environment:
            USER: 1000
            GROUP: 1000
        user: 1000:1000
        container_name: slides
        volumes:
            - ./:/data
        # entrypoint: ["make", "all"]
        entrypoint: ["make"]
        working_dir: /data
        # user: "$(id -u):$(id -g)"
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ for i in *.md; do
        fail "Error title field not found"
    fi
    i="${i%.*}"
    class="[${date} ${comp}](${PREFIX}${i}.pdf)"
    class="[${date}: ${comp}](${PREFIX}${i}.pdf)"
    classes+=("$class")
done
IFS=$'\n'
+21 −38
Original line number Diff line number Diff line
---
title: "Introduction générale"
date: "2020-09-16"
date: "2025-09-16"
---

# La hotline
@@ -11,59 +11,42 @@ Paul Albuquerque paul.albuquerque@hesge.ch B410
Orestis Malaspinas     orestis.malaspinas@hesge.ch       A401
--------------------   ------------------------------    --------------------

Utilisez le libre service (l'horaire sera fixé prochainement).
- Utilisez le libre service (l'horaire sera fixé prochainement).
- On va intensivement utiliser *Element*, installez le et utilisez le!
- Espace de discussion Matrix: <https://rb.gy/ku5es>, installez [element.io](https://element.io).

Salon de discussion [Matrix](https://matrix.to/#/!tuZtXjUSPbnRfBsFXv:matrix.org?via=matrix.org), installez [element.io](https://element.io).

![](figs/matrix.png){width=20%}
    ![](figs/matrix_qr.png){width=20%}

# Cyberlearn

Tout le contenu de ce qu'on raconte se trouve sur cyberlearn:

- Algorithmes et structures de données
  - <https://cyberlearn.hes-so.ch/course/view.php?id=13941>
  - Clé d'inscription: algo_2020_21
  - <https://cyberlearn.hes-so.ch/course/view.php?id=7276>
  - Clé d'inscription: algo_2025_26

- Programmation séquentielle en C
  - <https://cyberlearn.hes-so.ch/course/view.php?id=7282>
  - Clé d'inscription: prog_seq_2025_26

- Programmation Sequentielle en C
  - <https://cyberlearn.hes-so.ch/course/view.php?id=12399>
  - Clé d'inscription: PS_2018

# Organisation du module

* Deux cours, 50% chacun.
1. Algorithmes et structures de données:
## Cinq cours, 20% chacun.

1. Algorithmes et structures de données (2 semestres):
    * 1er semestre:
        * bases de programmation en C jusqu'à Noël.
        * bases de programmation en C jusqu'à Noël,
        * algorithmique jusqu'à fin janvier.
    * 2e semestre:
    * 2ème semestre:
        * algorithmique.
    * Deux évaluations écrites par semestre.
2. Programmation séquentielle en C
    * Deux évaluations écrites par semestre (1er sem.: novembre et janvier).
2. Programmation séquentielle en C (2 semestres)
    * Familiarisation avec l'environnement Linux.
    * Travaux pratiques en C.
    * Apprentissage du gestionnaire de versions: git.
    * Plusieurs "petits" exercices illustrant les concepts d'algorithmique 
      (1-2 séances).
    * Évaluations:
        * Un projet de programmation.
        * Une évaluation machine.

# Sondage: expérience de programmation

## [Sondage: expérience de linux](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1291283)

## [Sondage: expérience de programmation](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1035242)

**Installez un lecteur de QR code s'il-vous-plaît.**

# Questions?

- N'hésitez pas à poser des *questions*, nous sommes là pour ça! [^1]
- Ne restez pas coincés pendant des jours sur un problème.
- Utilisez le *libre-service*!
- N'hésitez pas à faire des *retours*: *négatifs* ou *positifs*.

[^1]: Chaque étudiant·e·s a un quota de 5 questions par semestre.
    * Plusieurs exercices illustrant les concepts d'algorithmique.
    * Évaluations (4 tests machine).
3. Programmation système (semestre de printemps)

Original line number Diff line number Diff line
---
subtitle: "Algorithmique et structures de données, 2021-2022"
author: "Paul Albuquerque (B410), Pierre Künzli et Orestis Malaspinas (A401), ISC, HEPIA"
institute: En partie inspirés des supports de cours de P. Albuquerque
subtitle: "Algorithmique et structures de données, 2025-2026"
author: "P. Albuquerque (B410) et O. Malaspinas (A401), ISC, HEPIA"
institute: En partie inspiré des supports de cours de P. Albuquerque
lang: fr-CH
revealjs-url: /reveal.js
mathjaxurl: "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML"

slides_2021/.gitignore

0 → 100644
+6 −0
Original line number Diff line number Diff line
*.pdf
*.err
*.markdown
*.html
index.md
.puppeteer.json

slides_2021/Makefile

0 → 100644
+71 −0
Original line number Diff line number Diff line
PDFOPTIONS = -t beamer
# PDFOPTIONS += -F pantable
PDFOPTIONS += -F mermaid-filter
PDFOPTIONS += --highlight-style my_highlight.theme
PDFOPTIONS += --pdf-engine xelatex
PDFOPTIONS += -V theme:metropolis
PDFOPTIONS += -V themeoptions:numbering=none -V themeoptions:progressbar=foot
PDFOPTIONS += -V fontsize=smaller
PDFOPTIONS += -V urlcolor=blue

REVEALOPTIONS = -t revealjs
REVEALOPTIONS += -F mermaid-filter
REVEALOPTIONS += --self-contained
REVEALOPTIONS += -V revealjs-url=reveal.js
REVEALOPTIONS += -V theme=white
REVEALOPTIONS += -V width=1920
REVEALOPTIONS += -V margin=0
REVEALOPTIONS += --slide-level=1

MD=$(wildcard *.md) # Tous les fichiers .md
PDF=$(MD:%.md=%.pdf) # Pour les fichier pdf on transforme .md -> .pdf
HTML=$(MD:%.md=%.html) # Pour les fichier html on transforme .md -> .html
MARKDOWN=$(MD:%.md=%.markdown) # Pour les fichier markdown on transforme .md -> .markdown
CHROMIUM:=$(shell which chromium || which chromium-browser)

all: puppeteer $(PDF) 
# all: puppeteer $(PDF) $(HTML) # La cible par défaut (all) exécute les cibles %.pdf

docker: docker-compose.yml
	docker-compose run slides make puppeteer -k || true
	docker-compose run slides make all -k || true

docker_clean: docker-compose.yml
	docker-compose run slides make clean -k || true

puppeteer:
	@echo "Setting chromium to $(CHROMIUM) for puppeteer"
	@echo -e "{\n\"executablePath\":" \"$(CHROMIUM)\" ",\n\"args\": [\"--no-sandbox\"]\n}" > .puppeteer.json

index:
	rm -f index.md
	./gen_index.sh

markdown: $(MARKDOWN) # La markdown les cibles %.markdown

%.pdf: %.md metadata.yaml # %.pdf (chaque fichier %.md génère un fichier avec le même nom mais l'extension .pdf et la dépendance metadata.yaml)
	pandoc -s $(OPTIONS) $(PDFOPTIONS) -o $@ $^

%.html: %.md metadata.yaml
	pandoc -s $(OPTIONS) $(REVEALOPTIONS) -o $@ $^

%.markdown: %.md metadata.yaml yq
	sed '1 { /^---/ { :a N; /\n---/! ba; d} }' $< > no_header
	grep -v -F -x -f  no_header $< > header.yaml
	echo "---" > tmp.yaml
	./yq_linux_amd64 merge metadata.yaml header.yaml >> tmp.yaml
	cat tmp.yaml no_header > $@
	rm no_header header.yaml tmp.yaml

yq: # On peut même télécharger un petit programme avec notre makefile
	wget -nc https://github.com/mikefarah/yq/releases/download/3.4.1/yq_linux_amd64
	chmod "u+x" yq_linux_amd64 

deploy: all 
	mkdir -p algo_cours
	cp *.pdf algo_cours

clean:
	rm -f *.html *.pdf *.markdown yq_linux_amd64* index.md .puppeteer.json

.PHONY:	clean index puppeteer yq

slides_2021/cours_1.md

0 → 100644
+693 −0
Original line number Diff line number Diff line
---
title: "Introduction aux algorithmes"
date: "2021-09-22"
---

# Qu'est-ce qu'un algorithme?

## Définition informelle (recette)

* des entrées (les ingrédients, le matériel utilisé) ;
* des instructions élémentaires simples (frire, flamber, etc.), dont les 
  exécutions dans un ordre précis amènent au résultat voulu ;
* un résultat : le plat préparé.

. . .

## Histoire et étymologie

- Existent depuis 4500 ans au moins (algorithme de division, crible 
  d'Eratosthène).
- Le mot algorithme est dérivé du nom du mathématicien perse
    *Muḥammad ibn Musā al-Khwārizmī*, qui a été "latinisé" comme 
    *Algoritmi*.

. . .

## Définition formelle

En partant d'un état initial et d'entrées (peut-être vides), une séquence finie 
d'instruction bien définies (ordonnées) implémentables sur un ordinateur, afin 
de résoudre typiquement une classe de problèmes ou effectuer un calcul.

# Notions de base d'algorithmique

## Variable

. . .

* Paire: identifiant - valeur (assignation);

## Séquence d'instructions / expressions

. . .

* Opérateurs (arthimétiques / booléens)
* Boucles;
* Structures de contrôle;
* Fonctions;


# Algorithme de vérification qu'un nombre est premier (1/3)

Nombre premier: nombre possédant deux diviseurs entiers distincts.

. . .

## Algorithme naïf (problème)

```C
est_premier(nombre) {
    si {
        pour tout i, t.q. 1 < i < nombre {
            i ne divise pas nombre
        }
    } alors vrai
    sinon faux
}
```

. . .

## Pas vraiment un algorithme: pas une séquence ordonnée et bien définie

. . .

## Problème: Comment écrire ça sous une forme algorithmique?

# Algorithme de vérification qu'un nombre est premier (2/3)

## Algorithme naïf (une solution)

```C
est_premier(nombre) { // fonction
    soit i := 2;       // variable, type, assignation
    tant que i < nombre { // boucle
        si nombre modulo i = 0 { // expression typée
            retourne faux    // expression typée
        }
        i := i + 1
    }
    retourne vrai // expression typée
```

# Algorithme de vérification qu'un nombre est premier (3/3)

## Algorithme naïf (une solution en C)

```C
bool est_premier(int nombre) {
    int i; // i est un entier
    i = 2; // assignation i à 2
    while (i < nombre) { // boucle avec condition
        if (0 == nombre % i) { // is i divise nombre
            return false; // i n'est pas premier
        }
        i += 1; // sinon on incrémente i
    }
    return true;
}
```

. . .

## Exercice: Comment faire plus rapide?

# Génération d'un exécutable

- Pour pouvoir être exécuté un code C doit être d'abord compilé (avec `gcc` ou `clang`).
- Pour un code `prog.c` la compilation "minimale" est

    ```bash
    $ gcc prog.c
    $ ./a.out # exécutable par défaut
    ```

- Il existe une multitude d'options de compilation:

    ```bash
    $ gcc -O1 -std=c11 -Wall -Wextra -g porg.c -o prog -fsanitize=address 
    -fsanitize=leak -fsanitize=undefined
    ```
    1. `-std=c11` utilisation de C11.
    2. `-Wall et -Wextra` activation des warnings.
    3. `-fsanitize=…`  contrôles d’erreurs à l’exécution (coût en performance).
    4. `-g` symboles de débogages sont gardés.
    5. `-o` défini le fichier exécutable à produire en sortie.
    6. `-O1`, `-O2`, `-O3`: activation de divers degrés d'optimisation



# La simplicité de C?

## 32 mots-clé et c'est tout

---------------- -------------- ---------------- ---------------
`auto`{.C}       `double`{.C}   `int`{.C}        `struct`{.C}   
`break`{.C}      `else`{.C}     `long`{.C}       `switch`{.C}   
`case`{.C}       `enum`{.C}     `register`{.C}   `typedef`{.C}  
`char`{.C}       `extern`{.C}   `return`{.C}     `union`{.C}    
`const`{.C}      `float`{.C}    `short`{.C}      `unsigned`{.C} 
`continue`{.C}   `for`{.C}      `signed`{.C}     `void`{.C}
`default`{.C}    `goto`{.C}     `sizeof`{.C}     `volatile`{.C}
`do`{.C}         `if`{.C}       `static`{.C}     `while`{.C}
---------------- -------------- ---------------- ---------------

# Déclaration et typage

En C lorsqu'on veut utiliser une variable (ou une constante), on doit déclarer son type

```C
const double two = 2.0; // déclaration et init.
int x;   // déclaration (instruction)
char c;  // déclaration (instruction)
x = 1;   // affectation (expression)
c = 'a'; // affectation (expression)
int y = x; // déclaration et initialisation en même temps
int a, b, c; // déclarations multiples
a = b = c = 1; // init. multiples
```

# Les variables (1/2)

## Variables et portée

- Une variable est un identifiant, qui peut être liée à une valeur (un expression).
- Une variable a une **portée** qui définit où elle est *visible* (où elle peut être accédée).
- La portée est **globale** ou **locale**.
- Une variable est **globale** est accessible à tout endroit d'un programme et doit être déclarée en dehors de toute fonction.
- Une variable est **locale** lorsqu'elle est déclarée dans un **bloc**, `{...}`{.C}.
- Une variable est dans la portée **après** avoir été déclarée.

# Les variables (2/2)

## Exemple 

```C
float max; // variable globale accessible partout
int foo() {
    // max est visible ici
    float a = max; // valide
    // par contre les varibles du main() ne sont pas visibles
}
int main() {
    // max est visible ici
    int x = 1; // x est locale à main
    {
        // x est visible ici, y pas encore
        // on peut par exemple pas faire x = y;
        int y = 2;
    } // y est détruite à la sortie du bloc
} // x est à la sortie de main

```

<!-- TODO: quiz, compile, compile pas -->
<!-- ```C
int main() {
    global = 1;
} // COMPILE PAS
```

```C
int main() {
    int global = 1;
    {
        printf("global = %d", global);
    }
} // COMPILE
```

```C
int local;

int main() {
    local = 1;
    {
        printf("local = %d", local);
    }
} // COMPILE
```

```C
#include <stdio.h>
int local = 0;

int main() {
    int local = -1;
    {
        int local = 1;
        printf("local = %d\n", local);
    }
} // COMPILE
``` -->

# Quiz: compile ou compile pas?

## [Quiz: compile ou compile pas](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033948)

# Types de base (1/4)

## Numériques

Type                               Signification (**gcc pour x86-64**)            
---------------------------------- ---------------------------------------------
`char`{.C}, `unsigned char`{.C}    Entier signé/non-signé 8-bit
`short`{.C}, `unsigned short`{.C}  Entier signé/non-signé 16-bit
`int`{.C}, `unsigned int`{.C}      Entier signé/non-signé 32-bit
`long`{.C}, `unsigned long`{.C}    Entier signé/non-signé 64-bit
`float`{.C}                        Nombre à virgule flottante, simple précision
`double`{.C}                       Nombre à virgule flottante, double précision
---------------------------------- ---------------------------------------------

**La signification de `short`{.C}, `int`{.C}, ... dépend du compilateur et de l'architecture.**

# Types de base (2/4)

Voir `<stdint.h>` pour des représentations **portables**

Type                               Signification
---------------------------------- ---------------------------------------------
`int8_t`{.C}, `uint8_t`{.C}        Entier signé/non-signé 8-bit
`int16_t`{.C}, `uint16_t`{.C}      Entier signé/non-signé 16-bit
`int32_t`{.C}, `uint32_t`{.C}      Entier signé/non-signé 32-bit
`int64_t`{.C}, `uint64_t`{.C}      Entier signé/non-signé 64-bit
---------------------------------- ---------------------------------------------

. . .

## Prenez l'habitude d'utiliser ces types-là!

# Types de base (3/4)

## Booléens

- Le ANSI C n'offre pas de booléens.
- L'entier `0`{.C} signifie *faux*, tout le reste *vrai*.
- Depuis C99, la librairie `stdbool` met à disposition un type `bool`{.C}.
- En réalité c'est un entier:
  - $1 \Rightarrow$ `true`{.C}
  - $0 \Rightarrow$ `false`{.C}
- On peut les manipuler comme des entier (les sommer, les multiplier, ...).

# Quiz: booléens

## [Quiz: booléens](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1032492)

<!-- TODO Quiz en ligne -->
<!-- ```C
if (42) { /* vrai */ }

int x = 100;
if (x == 4) { /* faux */ }
if (x) { /* vrai */ }

int x = 100;
while (x−−) { /* répète tant que x est différent de 0 */ }

if (0) { /* faux */ }
if (i = 4) { /* vrai */ }
if (i = 0) { /* faux */ }

#include <stdbool.h>

bool x = true;
if (x) { /* vrai */ }
``` -->

# Types de base (4/4)

## Conversions

- Les conversions se font de manière:
  - Explicite:
    ```C
    int a = (int)2.8;
    double b = (double)a;
    int c = (int)(2.8+0.5);
    ```
  - Implicite:
    ```C
    int a = 2.8; // warning, si activés, avec clang
    double b = a + 0.5;
    char c = b; // pas de warning...
    int d = 'c';
    ```

# Quiz: conversions

## [Quiz: conversions](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033446)

<!-- TODO Quiz en ligne -->
<!-- ```C
int a = (int)2.8; // 2

double b = 2.85;
int c = b + 0.5; // 3

int d = a + 0.5; // 2

bool d = 2.78; // 1
bool e = 1.0; // 1
``` -->

# Expressions et opérateurs (1/6)

Une expression est tout bout de code qui est **évalué**.

## Expressions simples

- Pas d'opérateurs impliqués.
- Les littéraux, les variables, et les constantes.

```C
const int L = -1; // 'L' est une constante, -1 un littéral
int x = 0;        // '0' est un litéral
int y = x;        // 'x' est une variable
int z = L;        // 'L' est une constante
```

## Expressions complexes

- Obtenues en combinant des *opérandes* avec des *opérateurs*

```C
int x;     // pas une expression (une instruction)
x = 4 + 5; // 4 + 5 est une expression
           // dont le résultat est affecté à 'x'
```

# Expressions et opérateurs (2/6)

## Opérateurs relationnels

Opérateurs testant la relation entre deux *expressions*:

  - `(a opérateur b)` retourne `1`{.C} si l'expression s'évalue à `true`{.C}, `0`{.C} si l'expression s'évalue à `false`{.C}.

| Opérateur | Syntaxe      | Résultat             |
|-----------|--------------|----------------------|
| `<`{.C}   | `a < b`{.C}  | 1 si a <  b; 0 sinon |
| `>`{.C}   | `a > b`{.C}  | 1 si a >  b; 0 sinon |
| `<=`{.C}  | `a <= b`{.C} | 1 si a <= b; 0 sinon |
| `>=`{.C}  | `a >= b`{.C} | 1 si a >= b; 0 sinon |
| `==`{.C}  | `a == b`{.C} | 1 si a == b; 0 sinon |
| `!=`{.C}  | `a != b`{.C} | 1 si a != b; 0 sinon |

# Expressions et opérateurs (3/6)

## Opérateurs logiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `&&`{.C}  | `a && b`{.C} | ET logique           |
| `||`{.C}  | `a || b`{.C} | OU logique           |
| `!`{.C}   | `!a`{.C}     | NON logique          |

# Quiz: opérateurs logiques

## [Quiz: opérateurs logiques](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033629)

<!-- TODO: Quiz -->
<!-- ```C
1 && 0 == 0
7 && 3 == 1
4 || 3 == 1
!34 == 0
!0 == 1

Soit n un unsigned char initialisé à 127:
!n == 0
``` -->

# Expressions et opérateurs (4/6)

## Opérateurs arithmétiques

| Opérateur | Syntaxe      | Signification        |
|-----------|--------------|----------------------|
| `+`{.C}   | `a + b`{.C}  | Addition             |
| `-`{.C}   | `a - b`{.C}  | Soustraction         |
| `*`{.C}   | `a * b`{.C}  | Multiplication       |
| `/`{.C}   | `a / b`{.C}  | Division             |
| `%`{.C}   | `a % b`{.C}  | Modulo               |

# Expressions et opérateurs (5/6)

## Opérateurs d'assignation

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `=`{.C}   | `a = b`{.C}  | Affecte la valeur `b` à la variable `a`     |
|           |              | et retourne la valeur de `b`                |
| `+=`{.C}  | `a += b`{.C} | Additionne la valeur de `b` à `a` et        |
|           |              | assigne le résultat à `a`.                  |
| `-=`{.C}  | `a -= b`{.C} | Soustrait la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `*=`{.C}  | `a *= b`{.C} | Multiplie la valeur de `b` à `a` et         |
|           |              | assigne le résultat à `a`.                  |
| `/=`{.C}  | `a /= b`{.C} | Divise la valeur de `b` à `a` et            |
|           |              | assigne le résultat à `a`.                  |
| `%=`{.C}  | `a %= b`{.C} | Calcule le modulo la valeur de `b` à `a` et |
|           |              | assigne le résultat à `a`.                  |

# Expressions et opérateurs (6/6)

## Opérateurs d'assignation (suite)

| Opérateur | Syntaxe      | Signification                               |
|-----------|--------------|---------------------------------------------|
| `++`{.C}  | `++a`{.C}    | Incrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a += 1`).            |
| `--`{.C}  | `--a`{.C}    | Décrémente la valeur de `a` de 1 et         |
|           |              | retourne le résultat (`a -= 1`).            |
| `++`{.C}  | `a++`{.C}    | Retourne `a`{.C} et incrémente `a` de 1.    |
| `--`{.C}  | `a--`{.C}    | Retourne `a`{.C} et décrémente `a` de 1.    |


# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (1/2)

## Syntaxe

```C
if (expression) {
    instructions;
} else if (expression) { // optionnel
                         // il peut y en avoir plusieurs
    instructions;
} else {
    instructions; // optionnel
}
```

```C
if (x) { // si x s'évalue à `vrai`
    printf("x s'évalue à vrai.\n");
} else if (y == 8) { // si y vaut 8
    printf("y vaut 8.\n");
} else {
    printf("Ni l'un ni l'autre.\n");
}
```

# Structures de contrôle: `if`{.C} .. `else if`{.C} .. `else`{.C} (2/2)

## Pièges

```C
int x, y;
x = y = 3;
if (x = 2)
    printf("x = 2 est vrai.\n");
else if (y < 8)
    printf("y < 8.\n");
else if (y == 3)
    printf("y vaut 3 mais cela ne sera jamais affiché.\n");
else
    printf("Ni l'un ni l'autre.\n");
    x = -1; // toujours évalué
```

# Quiz: `if ... else`{.C}

## [Quiz: `if ... else`{.C}](https://cyberlearn.hes-so.ch/mod/evoting/view.php?id=1033916)


# Structures de contrôle: `while`{.C}

## La boucle `while`{.C}

```C
while (condition) {
    instructions;
}
do {
    instructions;
} while (condition);
```

## La boucle `while`{.C}, un exemple

```C
int sum = 0; // syntaxe C99
while (sum < 10) {
    sum += 1;
}
do {
    sum += 10;
} while (sum < 100)
```

# Structures de contrôle: `for`{.C}

## La boucle `for`{.C}

```C
for (expression1; expression2; expression3) {
    instructions;
}
```

## La boucle `for`{.C}

```C
int sum = 0; // syntaxe C99
for (int i = 0; i < 10; i++) {
    sum += i;
}

for (int i = 0; i != 1; i = rand() % 4) { // ésotérique
    printf("C'est plus ésotérique.\n");
}
```

# Exercice: la factorielle

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un pseudo-code

. . .

```C
int factorielle(int n) {
    i = 1;
    fact = 1;
    pour i <= n {
        fact *= i;
        i += 1;
    }
}
```

# Exercice: la factorielle

\footnotesize

Écrire un programme qui calcule la factorielle d'un nombre
$$
N! = 1\cdot 2\cdot ... \cdot (N-1)\cdot N.
$$

## Par groupe de 3: écrire un code en C

Quand vous avez fini postez le code sur le salon matrix.

. . .

```C
#include <stdio.h>
int main() {
   int nb = 10;
   int fact = 1;
   int iter = 2;
   while (iter <= nb) {
      fact *= iter;
      iter++;
   }
}
```

. . .

## Comment améliorer ce code? (notez ça sur une feuille)


# Entrées/sorties: `printf()`{.C} (1/2)

## Généralités

- La fonction `printf()`{.C} permet d'afficher du texte sur le terminal:

    ```C
    int printf(const char *format, ...);
    ```
- Nombre d'arguments variables.
- `format`{.C} est le texte, ainsi que le format (type) des variables à afficher.
- Les arguments suivants sont les expressions à afficher.

# Entrées/sorties: `printf()`{.C} (2/2)

## Exemple

```C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Hello world.\n");
    int val = 1;
    printf("Hello world %d time.\n", val);
    printf("%f squared is equal to %f.\n", 2.5, 2.5*2.5);
    return EXIT_SUCCESS;
}
```

# Entrées/sorties: `scanf()`{.C} (1/2)

## Généralités

- La fonction `scanf()`{.C} permet de lire du texte formaté entré au clavier:

    ```C
    int scanf(const char *format, ...);
    ```

- `format`{.C} est le format des variables à lire (comme `printf()`{.C}).
- Les arguments suivants sont les variables où sont stockées les valeurs lues.

# Entrées/sorties: `scanf()`{.C} (2/2)

## Exemple

```C
#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Enter 3 numbers: \n");
    int i, j, k;
    scanf("%d %d %d", &i, &j, &k);
    printf("You entered: %d %d %d\n", i, j, k);
    
    return EXIT_SUCCESS;
}
```

# Exercice: la factorielle en mieux

## Individuellement

1. Ajoutez des fonctionnalités à votre code.
2. Écrivez l'algorithme de calcul de deux façon différentes.
3. Pour celles et ceux qui ont fini pendant que les autres essaient: faites-le 
   en récursif (sans aide).

. . .

## Postez vos solutions sur matrix!

slides_2021/cours_2.md

0 → 100644
+374 −0
Original line number Diff line number Diff line
---
title: "Introduction aux algorithmes"
date: "2021-09-29"
---

# Exercice: test si un nombre est premier

## Avec tout ce que vous avez appris la dernière fois:

* Écrivez le code testant si un nombre est premier.
* Quels sont les ajouts possibles par rapport au code de la semaine passée?
* Rencontrez-vous des problèmes éventuels de compilation?
* Voyez-vous une façon de générer des nombres premiers avec votre programme?

. . .

## Implémentez-la et postez votre code sur le salon matrix (10 min).

# Corrigé: enfin pas vraiment mais juste un possible

\footnotesize 

```C
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
int main() {
   int nb = 1;
   printf("Entrez un nombre: ");
   scanf("%d", &nb);
   bool premier = true;
   for (int div = 2; div <= sqrt(nb); div++) {
      if (nb % div == 0) {
         premier = false;
         break;
      }
   }
   if (premier) {
      printf("Le nombre %d est premier\n", nb);
   } else {
      printf("Le nombre %d n'est pas premier\n", nb);
   }
   return 0;
}
```

# Quelques algorithmes simples

## Voyons quelques algorithmes supplémentaires

- Plus petit commun multiple (PPCM) de deux nombres
- Autre algorithme de calcul du PPCM de deux nombres
- Plus grand commun diviseur (PGCD) de deux nombres

# Le calcul du PPCM (1/5)

## Définition

Le plus petit commun multiple (PPCM), `p`, de deux entiers non nuls, `a` et `b`,
est le plus petit entier strictement positif qui soit multiple de ces deux
nombres.

Exemples:

```C
PPCM(3, 4) = 12,
PPCM(4, 6) = 12,
PPCM(5, 15) = 15.
```

. . .

## Mathématiquement

Décomposition en nombres premiers:

$$
36 = 2^2\cdot 3^2,\quad 90=2\cdot 5\cdot 3^2,
$$
On garde tous les premiers à la puissance la plus élevée
$$
PPCM(36, 90)=2^2\cdot 3^2\cdot 5=180.
$$

# Le calcul du PPCM (2/5)

## Exemple d'algorithme

```C
PPCM(36, 90):
36  < 90  // 36  + 36
72  < 90  // 72  + 36
108 > 90  // 90  + 90
108 < 180 // 108 + 36
144 < 180 // 144 + 36
180 = 180 // The End!
```

* 5 additions, 5 assignations, et 6 comparaisons.

. . .

## Transcrivez cet exemple en algorithme (groupe de 3), 5min

. . .

## et codez-le!


# Le calcul du PPCM (3/5)

## Tentative de correction

```C
int main() { 
    int m = 15, n = 12;
    int mult_m = m, mult_n = n;
    while (mult_m != mult_n) {
        if (mult_m > mult_n) {
            mult_n += n;
        } else {
            mult_m += m;
        }
    }
    printf("Le ppcm de %d et %d est %d\n", n, m, mult_m);
}
```

. . .

* Combien d'additions / comparaisons au pire?

# Le calcul du PPCM (4/5)

## Réusinage: Comment décrire une fonction qui ferait ce calcul (arguments, sorties)?

. . .

En `C` on pourrait la décrire comme

```C
int ppcm(int a, int b); // La **signature** de cette fonction
```

. . .

## Algorithme

Par groupe de 3 (5-10min):

* réfléchissez à un algorithme alternatif donnant le PPCM de deux nombres;
* écrivez l'algorithme en pseudo-code.

# Le calcul du PPCM (5/5)

## Indication

Si un nombre, `p`, est multiple de `a` et de `b` alors il peut s'écrire `p = a
* i = b * j`  ou encore `p / a = i` et `p / b = j`.

<!-- Si un nombre, $p$, est multiple de $a$ et de $b$ alors il peut s'écrire -->
<!-- $$ -->
<!-- p = a \cdot i = b \cdot j, -->
<!-- $$ -->
<!-- ou encore $p / a = i$ et $p / b = j$. -->

. . .

## Pseudo-code

```C
int ppcm(int a, int b) {
    for (i in [1, b]) {
        if a * i is divisible by b {
            return a * i
        }
    }
}
```

# Le code du PPCM de 2 nombres (1/2)

## Implémentez le pseudo-code et postez le code sur matrix (5min).

. . .

## Un corrigé possible


```C
#include <stdio.h>
#include <stdlib.h> 

int main() { 
   int n = 15, m = 12;
   int i = 1;
   while (n * i % m != 0) {
      i++;
   }
   printf("Le ppcm de %d et %d est %d\n", n, m, n*i);
}
```

# Le code du PPCM de 2 nombres (2/2)

## Corrigé alternatif

```C
#include <stdio.h>
#include <stdlib.h> 

int main() { 
   int res = n*m;
   for (int i = 2; i <= m; i++) {
     if (n * i % m == 0) {
        res = n * i;
        break;
     }
   }
   printf("Le ppcm de %d et %d est %d\n", n, m, res);
}
```

# Le calcul du PGCD (1/5)

## Définition

Le plus grand commun diviseur (PGCD) de deux nombres entiers non nuls est le
plus grand entier qui les divise en même temps. 

## Exemples:

```C
PGCD(3, 4) = 1,
PGCD(4, 6) = 2,
PGCD(5, 15) = 5.
```

. . .

## Mathématiquement

Décomposition en nombres premiers:

$$
36 = 2^2\cdot 3^2,\quad 90=2\cdot 5\cdot 3^2,
$$
On garde tous les premiers à la puissance la plus basse
$$
PGCD(36, 90)=2^{\min{1,2}}\cdot 3^{\min{2,2}}\cdot 5^{\min{0,1}}=18.
$$

# Le calcul du PGCD (2/5)

## Algorithme

Par groupe de 3 (5-10min):

* réfléchissez à un algorithme alternatif donnant le PGCD de deux nombres;
* écrivez l'algorithme en pseudo-code.

. . .

## Exemple d'algorithme

```C
PGCD(36, 90):
90 % 36 != 0 // otherwise 36 would be PGCD
90 % 35 != 0 // otherwise 35 would be PGCD
90 % 34 != 0 // otherwise 34 would be PGCD
...
90 % 19 != 0 // otherwise 19 would be PGCD
90 % 18 == 0 // The end!
```

* 18 modulos, 18 assignations, et 18 comparaisons.

# Le calcul du PGCD (3/5)

## Transcrivez cet exemple en algorithme (groupe de 3) et codez-le (5-10min)!

. . .

## Optimisation

* Combien d'additions / comparaisons au pire?
* Un moyen de le rendre plus efficace?

. . .

## Tentative de correction

```C
void main() {
   int n = 90, m = 78;
   int gcd = 1;
   for (int div = n; div >= 2; div--) { // div = m, sqrt(n)
      if (n % div == 0 && m % div == 0) {
         gcd = div;
         break;
      }
   }
   printf("Le pgcd de %d et %d est %d\n", n, m, gcd);
}
```

# Le calcul du PGCD (4/5)

## Réusinage: l'algorithme d'Euclide

`Dividende = Diviseur * Quotient + Reste`

```C
PGCD(35, 60):
35 = 60 * 0 + 35 // 60 -> 35, 35 -> 60
60 = 35 * 1 + 25 // 35 -> 60, 25 -> 35
35 = 25 * 1 + 10 // 25 -> 35, 20 -> 25
25 = 10 * 2 +  5 // 10 -> 25, 5  -> 10
10 =  5 * 2 +  0 // PGCD = 5!
```

. . .

## Algorithme

Par groupe de 3 (5-10min):

* analysez l'exemple ci-dessus;
* transcrivez le en pseudo-code.

# Le calcul du PGCD (5/5)

## Pseudo-code

```C
int pgcd(int a, int b) {
    tmp_n = n
    tmp_m = m
    while (tmp_m does not divide tmp_n) {
        tmp   = tmp_n
        tmp_n = tmp_m
        tmp_m = tmp modulo tmp_m
    }
    return tmp_m
}
```

# Le code du PGCD de 2 nombres

## Implémentez le pseudo-code et postez le code sur matrix (5min).

. . .

## Un corrigé possible

```C
#include <stdio.h>
void main() {
   int n = 90;
   int m = 78;
   printf("n = %d et m = %d\n", n, m);
   int tmp_n = n;
   int tmp_m = m;
   while (tmp_n%tmp_m > 0) {
      int tmp = tmp_n;
      tmp_n = tmp_m;
      tmp_m = tmp % tmp_m;
   }
   printf("Le pgcd de %d et %d est %d\n", n, m, tmp_m);
}
```

+602 −0
Original line number Diff line number Diff line
---
title: "B-Arbres"
date: "2022-04-13"
patat:
  eval:
    tai:
      command: fish
      fragment: false
      replace: true
    ccc:
      command: fish
      fragment: false
      replace: true
  images:
    backend: auto
---

# Les B-arbres

## Problématique

* Grands jeux de données (en 1970).
* Stockage dans un arbre, mais l'arbre tiens pas en mémoire.
* Regrouper les sous-arbres en **pages** qui tiennent en mémoire.

## Exemple

* 100 noeuds par page et l'arbre comporte $10^6$ noeuds:
    * Recherche B-arbre: $\log_{100}(10^6)=3$;
    * Recherche ABR: $\log_2(10^6)=20$.
* Si on doit lire depuis le disque: $10\mathrm{ms}$ par recherche+lecture:
    * $30\mathrm{ms}$ (lecture beaucoup plus rapide que recherche) vs $200\mathrm{ms}=0.2\mathrm{s}$.

## Remarques

* On sait pas ce que veut dire `B`: Bayer, Boeing, Balanced?
* Variante plus récente B+-arbres.

# Les B-arbres

## Illustration, arbre divisé en pages de 3 noeuds

![Arbre divisé en pages de 3 noeuds](figs/barbres_page3.png)

. . .

## Utilisation

* Bases de données (souvent très grandes donc sur le disque);
* Système de fichier.

# Les B-arbres

## Avantages

* Arbres moins profonds;
* Diminue les opération de rééquilibrage;
* Complexité toujours en $\log(N)$;

. . .

## Définition: B-arbre d'ordre $n$

* Chaque page d'un arbre contient au plus $2\cdot n$ *clés*;
* Chaque page (excepté la racine) contient au moins $n$ clés;
* Chaque page qui contient $m$ clés contient soit:
    * $0$ descendants;
    * $m+1$ descendants.
* Toutes les pages terminales apparaissent au même niveau.

# Les B-arbres

## Est-ce un B-arbre?

![B-arbre d'ordre 2.](figs/barbres_exemple.png)

. . .

## Oui!

* Dans chaque noeud les clés sont **triées**.
* Chaque page contient au plus $n$ noeuds: check;
* Chaque noeud avec $m$ clés a $m+1$ descendants;
* Toutes les feuilles apparaissent au même niveau.

# Les B-arbres

## Exemple de recherche: trouver `32`

![B-arbre d'ordre 2.](figs/barbres_exemple.png)
 
. . .

* Si `n` plus petit que la 1e clé ou plus grand que la dernière descendre.
* Sinon parcourir (par bissection ou séquentiellement) jusqu'à trouver ou descendre entre 2 éléments.

# Les B-arbres

## La recherche de la clé `C` algorithme 

0. En partant de la racine.
1. Si on est dans une feuille:
    * Si la `C` est dans une page, retourner la page;
    * Sinon c'est perdu.
2. Sinon:
    * Tant que `C > page` passer à la page suivante
    * Descendre

# Les B-arbres

## Disclaimer

* Inspiration de <https://en.wikipedia.org/wiki/B-tree>

## Exemples d'insertion: `1`

![B-arbre d'ordre 1.](figs/barbres_1.svg)
 
. . .

* L'arbre est vide, on insère juste dans la première page.

# Les B-arbres

## Exemples d'insertion: `2`

![B-arbre d'ordre 1. Nombre pages max = 2.](figs/barbres_2.svg)
 
. . .

* La première page est pas pleine, on insère dans l'ordre (après 1).

# Les B-arbres

## Exemples d'insertion: `3`

![B-arbre d'ordre 1.](figs/barbres_2.svg){width=50%}

* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `3`

![B-arbre d'ordre 1. Nombre pages max = 2.](figs/barbres_3.svg){width=50%}
 
. . .

* La page est pleine, on crée deux enfants.
* On choisit, `2`, la médiane de `1, 2, 3` et il est inséré à la racine.
* `1` descend à gauche, `3` descend à droite.

# Les B-arbres

## Exemples d'insertion: `4`

![B-arbre d'ordre 1.](figs/barbres_3.svg){width=50%}
 
* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `4`

![B-arbre d'ordre 1. Nombre enfants 0 ou 2.](figs/barbres_4.svg){width=50%}
 
. . .

* On pourrait insérer à droite de `2`, mais... ça ferait 2 parents pour 2 enfants (mais `m` parents => `m+1` enfants ou `0`);
* On descend à droite (`4 > 2`);
* On insère à droite de `3`.

# Les B-arbres

## Exemples d'insertion: `5`

![B-arbre d'ordre 1.](figs/barbres_4.svg){width=50%}
 
* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `5`

![B-arbre d'ordre 2.](figs/barbres_5.svg)
 
. . .

* On descend à droite (on peut pas insérer à la racine comme pour `4`);
* On dépasse la capacité de l'enfant droite;
* `4`, médiane de `3, 4, 5`, remonte à la racine;
* On crée un nouveau noeud à droite de `4`;
* La règle `m => m+1` est ok.

# Les B-arbres

## Exemples d'insertion: `6`

![B-arbre d'ordre 1.](figs/barbres_5.svg){width=50%}
 
* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `6`

![B-arbre d'ordre 2.](figs/barbres_6.svg)
 
. . .

* `6 > 4` on descend à droite;
* `6 > 5` et on a à la place à droite, on insère.

# Les B-arbres

## Exemples d'insertion: `7`

![B-arbre d'ordre 1.](figs/barbres_6.svg){width=50%}
 
* Comment on insère (1min de réflexion avant de donner une réponse!)?

# Les B-arbres

## Exemples d'insertion: `7`

![B-arbre d'ordre 2.](figs/barbres_7.svg){width=50%}
 
. . .

* `7 > 4` on descend à droite;
* `7 > 6` mais on a dépassé la capacité;
* `6` est la médiane de `5, 6, 7`, remonte à la racine;
* `5` reste à gauche, `7` à droite, mais `6` fait dépasser la capacité de la racine;
* `4` est la médiane de `2, 4, 6`, `4` remonte, `2` reste à gauche, `6` à droite.

# Les B-arbres

## L'algorithme d'insertion

0. Rechercher la feuille (la page a aucun enfant) où insérer;
1. Si la page n'est pas pleine insérer dans l'ordre croissant.
2. Si la page est pleine, on sépare la page en son milieu :
    1. On trouve la médiane, `M`, de la page;
    2. On met les éléments `< M` dans la page de gauche de `M` et les `> M` dans la page de droite de `M`;
    3. `M` est insérée récursivement dans la page parent.

# Les B-arbres

## Exercice: insérer `22, 45, 50` dans l'arbre d'ordre 2 (3min matrix)

![](figs/barbres_ex1.png)

. . .

![](figs/barbres_ex2.png)


# Les B-arbres

## Exercice: insérer `5` dans l'arbre d'ordre 2 (3min matrix)

![](figs/barbres_ex2.png)

. . .

![](figs/barbres_ex3.png)

# Les B-arbres

## Exercice: insérer `32, 55, 60` dans l'arbre d'ordre 2 (3min matrix)

![](figs/barbres_ex3.png)

. . .

![](figs/barbres_ex4.png)

# Les B-arbres

## Exercice: insérer `41` dans l'arbre d'ordre 2 (3min matrix)

![](figs/barbres_ex4.png)

. . .

![](figs/barbres_ex5.png)

# Les B-arbres

## Exercice (matrix, 15min)

* Insérer 20, 40, 10, 30, 15, 35, 7, 26, 18, 22, 5, 42, 13, 46, 27, 8, 32, 38, 24, 45, 25, 2, 14, 28, 32, 41,
* Dans un B-arbre d'ordre 2.

# Les B-arbres

## Structure de données

* Chaque page a une contrainte de remplissage, par rapport à l'ordre de l'arbre;
* Un noeud (page) est composé d'un tableau de clés/pointeurs vers les enfants;

```
P_0 | K_1 | P_1 | K_2 |  | P_i | K_{i+1} |  | P_{m-1} | K_m | P_m
```

* `P_0`, ..., `P_m` pointeurs vers enfants;
* `K_1`, ..., `K_m` les clés.
* Il y a `m+1` pointeurs mais `m` clés.
* Comment faire pour gérer l'insertion?

# Les B-arbres

## Faire un dessin de la structure de données (3min matrix)?

. . .

![Strcture d'une page de B-arbre d'ordre 2.](figs/barbres_struct.png)

1. On veut un tableau de `P_i, K_i => struct`;
2. `K_0` va être en "trop";
3. Pour simplifier l'insertion dans une page, on ajoute un élément de plus.

# Les B-arbres

## L'insertion cas noeud pas plein, insertion `4`?

![](figs/barbres_insert_easy.svg){width=50%}

. . .

## Solution

![](figs/barbres_insert_easy_after.svg){width=50%}

# Les B-arbres

## L'insertion cas noeud pas plein, insertion `N`

* On décale les éléments plus grand que `N`;
* On insère `N` dans la place "vide";
* Si la page n'est pas pleine, on a terminé.

# Les B-arbres

## L'insertion cas noeud plein, insertion `2`?

![](figs/barbres_insert_hard_before.svg){width=50%}

. . .

## Solution

![](figs/barbres_insert_hard_during.svg){width=50%}

# Les B-arbres

## L'insertion cas noeud plein, promotion `3`?

![](figs/barbres_insert_hard_during.svg){width=50%}

. . .

## Solution

![](figs/barbres_insert_hard_after.svg)

# Les B-arbres

## L'insertion cas noeud plein, insertion `N`

* On décale les éléments plus grand que `N`;
* On insère `N` dans la place "vide";
* Si la page est pleine:
    * On trouve la valent médiance `M` de la page (quel indice?);
    * On crée une nouvelle page de droite;
    * On copie les valeur à droite de `M` dans la nouvelle page;
    * On promeut `M` dans la page du dessus;
    * On connecte le pointeur de gauche de `M` et de droite de `M` avec l'ancienne et la nouvelle page respectivement.

# Les B-arbres

## Pseudo-code structure de données (3min, matrix)?

. . .

```C
struct page
    entier ordre, nb
    element tab[2*ordre + 2]
```

```C
struct element
    int clé
    page pg
```

# Les B-arbres

\footnotesize

## Les fonctions utilitaires (5min matrix)

```C
booléen est_feuille(page)     // la page est elle une feuille?
entier position(page, valeur) // à quelle indice on insère?
booléen est_dans_page(page, valeur) // la valeur est dans la page
```

. . .

```C
booléen est_feuille(page) 
    retourne (page.tab[0].pg == vide)

entier position(page, valeur)
    i = 0
    tant que i < page.nb && val >= page.tab[i+1].clef
        i += 1
    retourne i

booléen est_dans_page(page, valeur)
    i = position(page, valeur)
    retourne (page.nb > 0 && page.tab[i].val == valeur)
```

# Les B-arbres

\footnotesize

## Les fonctions utilitaires (5min matrix)

```C
page nouvelle_page(ordre)  // creer une page
rien liberer_memoire(page) // liberer tout un arbre!
```
. . .

```C
page nouvelle_page(ordre)
    page = allouer(page)
    page.ordre = ordre
    page.nb = 0
    page.tab = allouer(2*ordre+2)
    retourner page

rien liberer_memoire(page)
    si est_feuille(page)
        liberer(page.tab)
        liberer(page)
    sinon
        pour fille dans page.tab
            liberer_memoire(fille)
        liberer(page.tab)
        liberer(page)
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
page recherche(page, valeur) // retourner la page contenant
                             // la valeur ou vide 
```

. . .

```C
page recherche(page, valeur)
    si est_dans_page(page, valeur)
        retourne page
    sinon si est_feuille(page) 
        retourne vide
    sinon
        recherche(page.tab[position(page, valeur)], valeur)
```

# Les B-arbres

## Les fonctions

```C
page inserer_valeur(page, valeur) // inserer une valeur
```

. . .

```C
page inserer_valeur(page, valeur)
    element = nouvel_element(valeur)
    // on change element pour savoir s'il faut le remonter
    inserer_element(page, element) 
    si element.page != vide && page.nb > 2*page.ordre
        // si on atteint le sommet!
        page = ajouter_niveau(page, element) 
    retourne page
```

# Les B-arbres

## Les fonctions

```C
rien inserer_element(page, element) // inserer un element et voir s'il remonte
```

. . .

```C
rien inserer_element(page, element)
    si est_feuille(page)
        placer(page, element)
    sinon
        sous_page = page.tab[position(page, element)].page
        inserer_element(sous_page, element)
        // un element a été promu
        si element.page != vide
            placer(page, element)
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
rien placer(page, element) // inserer un élément
```

. . .

```C
rien placer(page, element)
    pos = position(page, element.clé)
    pour i de 2*page.ordre à pos+1
        page.tab[i+1] = page.tab[i]
    page.tab[pos+1] = element
    page.nb += 1
    si page.nb > 2*page.ordre
        scinder(page, element)
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
rien scinder(page, element) // casser une page et remonter
```

. . .

```C
rien scinder(page, element)
    new_page = new_page(page.ordre)
    new_page.nb = page.ordre
    pour i de 0 à ordre inclu
        new_page.tab[i] = page.tab[i+ordre+1]
    element.clé = page.tab[ordre+1].clé
    element.page = new_page
```

# Les B-arbres

## Les fonctions (5min matrix)

```C
page ajouter_niveau(page, element) // si on remonte à la racine...
                                   // on doit créer une nouvelle racine
```

. . .

```C
page ajouter_niveau(page, element) 
    tmp = nouvelle_page(page.ordre)
    tmp.tab[0].page = page
    tmp.tab[1].clé = element.clé
    tmp.tab[1].page = element.page
    retourne tmp
```


<!-- # Les B-arbres -->

<!-- ## Structure de données en C (3min, matrix) -->

<!-- . . . -->

<!-- ```C -->
<!-- typedef struct _page { -->
<!--     int order, nb; -->
<!--     struct _element *tab; -->
<!-- } page; -->
<!-- ``` -->

<!-- ```C -->
<!-- typedef struct element { -->
<!--     int key; -->
<!--     struct _page *pg; -->
<!-- } element; -->
<!-- ``` -->
+445 −0

File added.

Preview size limit exceeded, changes collapsed.

+883 −0

File added.

Preview size limit exceeded, changes collapsed.

+579 −0

File added.

Preview size limit exceeded, changes collapsed.

+776 −0

File added.

Preview size limit exceeded, changes collapsed.

+681 −0

File added.

Preview size limit exceeded, changes collapsed.

slides_2021/cours_3.md

0 → 100644
+339 −0

File added.

Preview size limit exceeded, changes collapsed.

slides_2021/cours_4.md

0 → 100644
+672 −0

File added.

Preview size limit exceeded, changes collapsed.

+14 −0
Original line number Diff line number Diff line
version: "3.3"
services:
    slides:
        #To use dockerfile : build: . 
        image:  omalaspinas/pandoc:latest
        environment:
            USER: 1000
            GROUP: 1000
        container_name: slides
        volumes:
            - ./:/data
        # entrypoint: ["make", "all"]
        working_dir: /data
        # user: "$(id -u):$(id -g)"