Skip to content

Commit 69de21b

Browse files
authored
Add files via upload
1 parent 48835b7 commit 69de21b

File tree

2 files changed

+147
-12
lines changed

2 files changed

+147
-12
lines changed

samples/code/README.md

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
1-
# Πρόγραμμα Περιστροφής Εικόνας
2-
3-
Το πρόγραμμα δέχεται το ωμό περιεχόμενο μιας bitmap εικόνας και στέλνει στο standard output μια εκδοχή της που έχει περιστραφεί δεξιόστροφα, κατά 90 μοίρες.
4-
Αρχικά διαβάζω την τιμή `pixel_array_offset` για να αποθηκεύσω το πλήθος των bytes που απαιτούνται για την αποθήκευση του header και του other data.
5-
Αμέσως μετά δημιουργώ ένα αντίγραφο των δεδομένων, διαβάζω τις χρήσιμες πληροφορίες χρησιμοποιώντας casting σε uint32_t pointer, και κάνω malloc μια δισδιάστατη λίστα για
6-
να αποθηκεύσω και να τροποποιήσω τα περιεχόμενα των pixels. Υπολογίζω το νέο padding έτσι ώστε κάθε στήλη να έχει μέγεθος πολλαπλάσιο του τέσσερα και στέλνω τις αλλαγές μου στο standard output.
7-
8-
Για να καταλάβω πως θα υλοποιήσω το transformation, περιέγραψα σε χαρτί την διαδικασία περιστροφής μιας οποιοασδήποτε εικόνας και μετέφερα το σκεπτικό στο πρόγραμμα δίνοντας ιδιαίτερη προσοχή στον τρόπο με τον οποίο κάνω iterate τις στήλες και τις γραμμές. Ουσιαστικά μετατρέπω κάθε στήλη σε γραμμή, αφού πρώτα αντιστρέψω την σειρά των pixels της.
9-
10-
Αφού τελειώσω με την επεξεργασία των δεδομένων κάνω `free()` για να αποφύγω τα πιθανά μαίμωρει λειξ. Αρχικά είχα προσπαθήσει να κάνω χρήση της `fseek(stdin, padding, SEEK_SET)` για να αποφύγω την ανάγνωση των κενών, αλλά η συγκεκριμένη συνάρτηση δεν λειτουργούσε για pipes αλλά μόνο σε απλές περιπτώσεις ανακατεύθυνσης.
11-
12-
Χρησιμοποίησα τον preprocessor (#define) για να μην περιλάβω magic numbers στο πρόγραμμά μου. Επιπλέον, αν ποτέ χρειαστεί να διορθώσω οποιοδήποτε offset αρκεί μονάχα να αλλάξω την γραμμή του declaration του, και όχι όλες τις περιπτώσεις που αυτή χρησιμοποιείται!
1+
# Εργασία 2 - Άσκηση 2: DNA Matching
2+
3+
### Σχόλιο 1 - Η πρώτη σκέψη
4+
Για να βρούμε τη μέγιστη κοινή αλυσίδα, πρέπει να συγκρίνουμε κάθε χαρακτήρα του dna2 με κάθε χαρακτήρα του dna1 και να βρούμε ποιος είναι ο μέγιστος αριθμός διαδοχικών βάσεων που είναι ίδιες και στα δύο dna.
5+
Θα βοηθούσε να κάναμε τη σύγκριση αυτή με ένα δισδιάστο πίνακα dnas[dna1_length][dna2_length], του οποίου η εγγραφή dnas[i][j] θα ήταν ίση με 1 μόνο αν dna1[i] == dna2[j], αλλιώς 0. Μετά, θα ήταν εύκολο να βρούμε τη μέγιστη κοινή αλυσίδα, αφού αυτή θα αντιστοίχουσε στη μακρύτερη διαγώνιο από άσσους.<br>
6+
Π.χ. A C T G C G G<br>
7+
A 1 0 0 0 0 0 0 <br>
8+
G 0 0 0 1 0 1 1<br>
9+
T 0 0 <strong>1</strong> 0 0 0 0 <br>
10+
G 0 0 0 <strong>1</strong> 0 1 1 <br>
11+
C 0 1 0 0 <strong>1</strong> 0 0 <br>
12+
A 1 0 0 0 0 0 0 <br>
13+
Ωστόσο, για μεγάλες αλυσίδες, αυτή η τεχνική οδηγεί σε άσκοπη σπατάλη μνήμης, η δέσμευση της οποίας ακόμη και στο σωρό υπάρχει πιθανότητα να αποτύχει .<br>
14+
15+
### Σχόλιο 2 - Προσπάθεια εξοικονόμησης μνήμης - η συνάρτηση find_longest_common_sequence
16+
Παρατήρωντας τον παραπάνω πίνακα από κάτω προς τα πάνω, φαίνεται ότι ίσως να μπορούσαμε να ξεφορτωθούμε περιττές γραμμές, αν σε κάθε επόμενη αθροίζαμε τα μέγιστα μήκη κοινών ακολουθιών που είχαμε εντοπίσει ως την προηγούμενη.
17+
Έτσι, δημιουργούμε έναν πίνακα common_suffixes με μέγεθος dna1_length, τον οποίο ανανεώνουμε dna2_length φορές, προσθέτωντας κάθε φορά τις νέες κοινές βάσεις (που αλλάζουν τα μήκη των μέγιστων κοινών καταλήξεων) και ανανεώνοντας σε κάθε αλλαγή τις global μεταβλητές max_length και starting_index. <br>
18+
Κατά την εκτέλεση του προγράμματος για το παραπάνω παράδειγμα, ο πίνακας θα είχε αυτή την εξέλιξη:
19+
<br><br>
20+
1 0 0 0 0 0 0 <br>
21+
0 1 0 0 1 0 0 <br>
22+
0 0 0 2 0 1 1
23+
0 0 3 0 0 0 0 <br>
24+
0 0 0 1 0 1 1 <br>
25+
1 0 0 0 0 0 0 <br>
26+
27+
Ιδιαίτερη σημασία έχει το γεγονός ότι η ανανέωση του common_suffixes πραγματοποιείται κατά μήκος διαγωνίων και όχι καθέτως, αφού αν dna1[i] == dna2[j] δεν θέλουμε dna1[i] = dna2[j+1], αλλά dna1[i+1] = dna2[j+1], ώστε οι κοινές βάσεις να είναι διαδοχικές και στα δύο dna.<br>
28+
Αν κάποιο ζεύγος βάσεων δεν είναι κοινό, τότε διακόπτεται και η κοινή αλυσίδα βάσεων (η διάγωνιος) που οδηγούσε σε αυτό και η τιμή του αντίστοιχου στοιχείου στον πίνακα common_suffixes γίνεται 0. Ωστόσο, αν το μήκος της ακολουθίας που είχε δημιουργηθεί μέχρι εκείνη τη στιγμή ήταν μέγιστο, αυτό έχει αποθηκευτεί.<br>
29+
30+
Μετά τον τερματισμό της συνάρτησης (όταν δεν υπάρχουν πια άλλες βάσεις στο dna2 για να συγκριθούν), γνωρίζουμε και το μέγιστο μήκος και το σημείο του dna1 όπου αρχίζει η μέγιστη κοινή ακολουθία, άρα μπορούμε να την προσδιόρισουμε και να την τυπώσουμε.<br>
31+
Με αυτόν τον τρόπο, κατάφεραμε από Ο(n * m) μνήμη να χρησιμοποιούμε μόνο Ο(n), όπου n = dna1_length και m = dna2_length.

samples/code/dna.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
Φοιτήτρια: Ματίνα Ναδάλη
3+
Καθηγητής: Αυγερινός Αθανάσιος
4+
Μάθημα: Εισαγωγή στον προγραμματισμό
5+
Πρόγραμμα dna.c : Εκτυπώνει την μέγιστη κοινή αλυσίδα DNA ανάμεσα σε δύο
6+
δείγματα
7+
*/
8+
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
int dna1_length, dna2_length;
12+
int max_length = 0;
13+
int starting_index = 0; //η θέση του πρώτου στοιχείου της μέγιστης κοινής ακολουθίας στο dna1
14+
15+
//ελέγχει αν ο χαρακτήρας είναι κάποια έγκυρη βάση
16+
int is_base(char character) {
17+
return character == 'A' ||
18+
character == 'C' ||
19+
character == 'G' ||
20+
character == 'T';
21+
}
22+
23+
//θέτει τη global μεταβλητή starting_index στο index του χαρακτήρα του dna1, από
24+
//τον οποίο αρχίζει η μέγιστη κοινή ακολουθία σχόλιο 2 στο README.md
25+
void find_longest_common_sequence(int *common_suffixes, int dna2_index,char *dna1, char *dna2) {
26+
//συνθήκη τερματισμού - δεν υπάρχουν άλλες βάσεις στο dna2 για να συγκριθούν
27+
if (dna2_index < 0) {
28+
free(common_suffixes);
29+
return;
30+
}
31+
//δεσμεύει μνήμη για τα νέα μήκη των μέγιστων κοινών καταλήξεων - όλες οι
32+
//τιμές αρχικοποιούνται στο 0
33+
int *new_common_suffixes = calloc(dna1_length, sizeof(int));
34+
for (int i = 0; i < dna1_length; i++) {
35+
if (dna1[i] == dna2[dna2_index]) {
36+
//βρέθηκε νέος κοινός χαρακτήρας - η κοινή ακολουθία συνεχίζεται και το
37+
//μήκος της αυξάνεται κατά 1
38+
new_common_suffixes[i] = 1;
39+
if (i < dna1_length - 1) {
40+
new_common_suffixes[i] += common_suffixes[i + 1];
41+
}
42+
//ανανεώνει το μέγιστο μήκος της κοινής ακολουθίας και το starting_index
43+
if (new_common_suffixes[i] > max_length) {
44+
max_length = new_common_suffixes[i];
45+
starting_index = i;
46+
}
47+
}
48+
}
49+
//ελευθέρωνει τη μνήμη για τα προηγούμενα μήκη των κοινών καταλήξεων
50+
free(common_suffixes);
51+
//ξανακαλεί τη συνάρτηση για τον προηγούμενο χαρακτήρα του dna2
52+
find_longest_common_sequence(new_common_suffixes, dna2_index - 1, dna1, dna2);
53+
}
54+
55+
int main(int argc, char **argv) {
56+
//ελέγχει τον αριθμό των ορισμάτων
57+
if (argc != 3) {
58+
perror("Error: arguments missing. Usage: ./dna dnafile1 dnafile2");
59+
exit(1);
60+
}
61+
FILE *dna1_in = fopen(argv[1], "r");
62+
FILE *dna2_in = fopen(argv[2], "r");
63+
if (!dna1_in || !dna2_in) {
64+
perror("Error: Could not open files");
65+
exit(1);
66+
}
67+
//δεσμεύει μνήμη στο σωρό για την αποθήκευση των ακολουθιών DNA - χρησιμοποιεί
68+
//το μέγιστο δυνατό μήκος
69+
char *dna1 = malloc(100000 * sizeof(char));
70+
char *dna2 = malloc(100000 * sizeof(char));
71+
if (!dna1 || !dna2) {
72+
perror("Memory allocation failed");
73+
exit(1);
74+
}
75+
char new_character;
76+
77+
//διαβάζει τους χαρακτήρες από τα αρχεία και τα καταχωρεί στους αντίστοιχους
78+
//πίνακες μόνο αν αντιστοιχούν σε έγκυρη βάση
79+
while (fscanf(dna1_in, "%c", &new_character) != EOF) {
80+
if (is_base(new_character)) {
81+
dna1[dna1_length] = new_character;
82+
dna1_length++;
83+
}
84+
}
85+
while (fscanf(dna2_in, "%c", &new_character) != EOF) {
86+
if (is_base(new_character)) {
87+
dna2[dna2_length] = new_character;
88+
dna2_length++;
89+
}
90+
}
91+
92+
//δεσμεύει μνήμη για να αποθηκεύσει τα μήκη των μέγιστων ακολουθιών που
93+
//περιέχουν κάθε χαρακτήρα του dna1 η δέσμευση γίνεται με την calloc ώστε οι
94+
//τιμές να αρχικοποιηθούν στο 0
95+
int *common_suffixes = calloc(dna1_length, sizeof(int));
96+
97+
for (int i = 0; i < dna1_length; i++) {
98+
if (dna1[i] == dna2[dna2_length - 1]) {
99+
common_suffixes[i] = 1;
100+
}
101+
}
102+
find_longest_common_sequence(common_suffixes, dna2_length - 2, dna1, dna2);
103+
104+
//εκτυπώνει τη μέγιστη κοινή ακολουθία
105+
for (int i = starting_index; i < starting_index + max_length; i++) {
106+
printf("%c", dna1[i]);
107+
}
108+
printf("\n");
109+
//απελευθερώνει τη δεσμευμένη μνήμη
110+
free(dna1);
111+
free(dna2);
112+
113+
fclose(dna1_in);
114+
fclose(dna2_in);
115+
return 0;
116+
}

0 commit comments

Comments
 (0)