Initial copy

This commit is contained in:
Julian M. Kunkel 2018-05-05 23:18:02 +01:00
parent 86d2e00bf0
commit 5cf362c910
1359 changed files with 170737 additions and 54 deletions

View File

@ -5,9 +5,22 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y apache2
RUN rm /etc/apache2/sites-enabled/000-default.conf
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y postgresql libapache2-mod-wsgi-py3
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y virtualenv
# make for testing
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y virtualenv make sudo
RUN ln -s /data/dev/apache-local.conf /etc/apache2/sites-enabled/
#RUN a2enmod rewrite
RUN sed -i "s#data_directory = '.*'#data_directory = '/data/run/postgres'#" /etc/postgresql/10/main/postgresql.conf
RUN echo "host all all 0.0.0.0/0 md5" >> /etc/postgresql/10/main/pg_hba.conf
RUN echo "listen_addresses='*'" >> /etc/postgresql/10/main/postgresql.conf
RUN /etc/init.d/postgresql restart
RUN sudo -u postgres psql -c "CREATE USER hoou WITH PASSWORD 'hoohoohoo123';"
RUN sudo -u postgres psql -c "CREATE DATABASE hoou;"
RUN sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE hoou to hoou;"
# psql -h localhost -U hoou hoou # should work
CMD /data/dev/run-internal.sh

View File

@ -1,61 +1,24 @@
<VirtualHost *:80>
ServerAdmin admin@wr.informatik.uni-hamburg.de
ServerName oer.wr.informatik.uni-hamburg.de
ServerAdmin admin@hps.vi4io.org
#ServerName oer.hps.vi4io.org
Redirect permanent / https://oer.wr.informatik.uni-hamburg.de/
WSGIScriptAlias / "/data/src/main/wsgi.py"
WSGIDaemonProcess hoou python-home=/data/run/virtualenv python-path=/data/src/ home=/data/src/ inactivity-timeout=10 request-timeout=10
WSGIProcessGroup hoou
WSGIApplicationGroup %{GLOBAL}
<Directory />
Options SymLinksIfOwnerMatch
AllowOverride None
Require all denied
DocumentRoot /data/src/
Alias /static/ "/data/run/static/"
<Directory "/data/run/static/">
Require all granted
</Directory>
<Directory "/data/src/main/">
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin admin@wr.informatik.uni-hamburg.de
ServerName oer.wr.informatik.uni-hamburg.de
#RewriteEngine on
#RewriteRule "^/$" "http://cluster.wr.informatik.uni-hamburg.de:8000/" [R,L]
#RewriteRule "^/(.+)$" "http://cluster.wr.informatik.uni-hamburg.de:8000/$1" [R,L]
WSGIScriptAlias / "/home/hoou/git/HOOU/django-platform/main/wsgi.py"
WSGIDaemonProcess hoou python-home=/home/hoou/git/HOOU/virtualenv python-path=/home/hoou/git/HOOU/django-platform/ home=/home/hoou/git/HOOU/django-platform/ inactivity-timeout=10 request-timeout=10
WSGIProcessGroup hoou
WSGIApplicationGroup %{GLOBAL}
DocumentRoot /home/hoou/git/HOOU/django-platform/
Alias /static/ "/home/hoou/git/HOOU/django-platform/apache/static/"
<Directory "/home/hoou/git/HOOU/django-platform/apache/static/">
Require all granted
</Directory>
<Directory "/home/hoou/git/HOOU/django-platform/main/">
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error-oer.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/oer-access.log combined
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/oer.wr.informatik.uni-hamburg.de/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/oer.wr.informatik.uni-hamburg.de/privkey.pem
Alias "/.well-known/acme-challenge/" "/var/www/certbot/.well-known/acme-challenge/"
<Directory /var/www/certbot>
Options SymLinksIfOwnerMatch
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
</IfModule>

View File

@ -7,5 +7,5 @@ Sphinx
pymongo
celery
markdown
psycopg2
psycopg2-binary
social-auth-app-django

View File

@ -1,9 +1,16 @@
#!/bin/bash -e
adduser --system --no-create-home --home /data --uid 1000 www-user
sed -i "s/APACHE_RUN_USER=www-data/APACHE_RUN_USER=www-user/" /etc/apache2/envvars
sed -i "s#data_directory = '.*'#data_directory = '/data/run/postgres'#" /etc/postgresql/10/main/postgresql.conf
/etc/init.d/postgresql restart
/etc/init.d/apache2 start
tail -f /var/log/apache2/error.log &
export OER_SRC_DIR=/data/oer
export PLATFORM_PATH=/data/src
V="/data/run/virtualenv"
if [[ ! -e $V ]] ; then
mkdir -p $V
@ -11,6 +18,10 @@ if [[ ! -e $V ]] ; then
cd $V
source $V/bin/activate
pip3 install -U -r /data/dev/requirements.txt
python3 ./manage.py migrate
python3 ./manage.py collectstatic
fi
source $V/bin/activate
/bin/bash

16
oer/README.md Normal file
View File

@ -0,0 +1,16 @@
# Open Educational Resources
While many standards for open educational resources (OER) are available.
Unfortunetly many ignore the special needs for automatic evaluation and grading
for programming courses and parallel programming in particular. As such, until
a more universal format is determined, this project sticks with a very
simple file and directory based format and mostly plaintext based metadata.
Tools to work with the web platform and execution runners are provided.
## Structure
Lectures/courses and exercises are decoupled, to allow for multiple courses to
use the same exercise.
./courses # a course allows to specify a sequence or directed graph of excercises
./exercises # provides a pool of exercises which can be used to create courses

View File

@ -0,0 +1 @@
{"title": "C Advanced", "description": "Some further material for the C-Programming-Language"}

View File

@ -0,0 +1,10 @@
Welcome to the C-Advanced course. This course is targeted for those,
who feel comfortable with pointers, memory management and all the basic
c syntax.
We will guide you on, how to use c to implement your own data-structures,
writing your own libraries and give you some more advanced task to
test your abilities.
Most of these task can take some time to get everything right. So don't be discouraged, whenn
need to take a break. Often those breaks help one see the mistakes or misunderstandings.

View File

@ -0,0 +1 @@
{"title": "Introduction"}

View File

@ -0,0 +1 @@
text/html

View File

@ -0,0 +1,8 @@
all:
gcc program.c -o program
#gcc solution.c -o solution
clean:
rm -f program
rm -f solution

View File

@ -0,0 +1,28 @@
The first basic data-structure everybody should learn is the singly linked list.
In a singly linked list you save your data in nodes, a combination of data and a pointer
to the next node. To add nodes you simply allocate them and rewire the pointers,
such that it appears in the right spot in the list.
To remove an element you have to rewire the previous and next node, such that their
pointers point to each other, and then free the memory.
The idea behind this data-structures is, that you can add and remove elements easily
from the end, front and middle of the list. And because you just allocate more memory,
the list can grow dynamically.
The problem is to get to the elements.
Because they are allocated on the heap the elements are all over the place and can only
be found via the pointers. So, when you want to get to the middle, you have to traverse
the linked list.
Another downside of singly linked list is, that you can't go backwards.
That is were the doubly linked list comes in, but more on that later.
The last disadvantage is, when you want to process lot's of data in a short amount of time,
you are often limited by cache misses. And linked list in general are terrible for that kind
of work, because most elements aren't in the same cache line.
Your task will be to implement the functions for add, insert_after, remove and get.
It is often helpful to draw the operations you want to do on paper or
look at some pictures.

View File

@ -0,0 +1 @@
{"title": "Singly Linked List"}

View File

@ -0,0 +1,66 @@
#include <stdio.h>
typedef struct node
{
char Character;
struct node *Next;
}node;
// NOTE: adds an element to the beginning
void list_add(node **Head, char c)
{
// TODO: implement this
}
// NOTE: inserts after a specific node
void list_insert_after(node *Node, char c)
{
// TODO: implement this
}
// NOTE: get's a node with the specified character
node *list_get(node **Head, char c)
{
// TODO: implement this
return 0;
}
// NOTE: removes a specific node from the list
void list_remove(node **Head, node *Node)
{
// TODO: implement this
}
// NOTE: frees the whole list
void list_free(node **Head)
{
// TODO: implement this
}
int main(int argc, char **argv)
{
// NOTE: beginning of the list
// right now the list is empty
node *Head = 0;
list_add(&Head, 'c');
list_add(&Head, 'y');
list_add(&Head, 'b');
node *ToBeRemoved = list_get(&Head, 'y');
list_remove(Head, ToBeRemoved);
list_add(&Head, 'a');
node *InsertAfter = list_get(&Head, 'c');
list_insert_after(InsertAfter, 'd');
for(node *Iter = Head; Iter; Iter = Iter->Next)
{
printf("%c ", Iter->Character);
}
printf("\n");
list_free(Head);
}

View File

@ -0,0 +1 @@
^a b c d $

View File

@ -0,0 +1 @@
program/match-regex

View File

@ -0,0 +1,8 @@
all:
gcc program.c -o program
#gcc solution.c -o solution
clean:
rm -f program
rm -f solution

View File

@ -0,0 +1,11 @@
The next step up from a sinlgy linked list is the double linked list.
It is basically the same. It just stores another pointer for the previous node.
This makes some operations way easier and some a little harder.
But most of the time it is a trade of worth taking.
A common thing people do is to make double linked list(in short dlist) circular.
To mark the head and the tail they use a special node called the sentinel.
This makes some operations easier, but for now we will concentrate on the basic dlist.
Your task is to change the singly linked list to a double linked list.

View File

@ -0,0 +1 @@
{"title": "Double Linked List"}

View File

@ -0,0 +1,111 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char Character;
struct node *Next;
struct node *Prev;
}node;
// TODO: change all the function to use a dlinked list
node *alloc_node(char c, node *Next, node *Prev)
{
node *NewNode = malloc(sizeof(node));
NewNode->Character = c;
NewNode->Next = Next;
return NewNode;
}
// TIP: In the next 2 function you probably need to check for null-pointers
// NOTE: adds an element to the beginning
void list_add(node **Head, char c)
{
node *NewNode = alloc_node(c, *Head, 0);
*Head = NewNode;
}
// NOTE: inserts after a specific node
void list_insert_after(node *Node, char c)
{
node *NewNode = alloc_node(c, Node->Next, 0);
Node->Next = NewNode;
}
// NOTE: get's a node with the specified character
node *list_get(node **Head, char c)
{
node *Result;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter->Character == c)
{
Result = Iter;
break;
}
}
return Result;
}
// NOTE: removes a specific node from the list
void list_remove(node **Head, node *Node)
{
// NOTE: this should get simpler
// Find prev node
node *Prev = 0;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter == Node)
break;
Prev = Iter;
}
if(Prev)
Prev->Next = Node->Next;
free(Node);
}
// NOTE: frees the whole list
void list_free(node **Head)
{
for(node *Iter = *Head; Iter; )
{
node *ToFree = Iter;
Iter = Iter->Next;
free(ToFree);
}
}
int main(int argc, char **argv)
{
node *Head = 0;
list_add(&Head, 'c');
list_add(&Head, 'y');
list_add(&Head, 'b');
node *ToBeRemoved = list_get(&Head, 'y');
list_remove(&Head, ToBeRemoved);
list_add(&Head, 'a');
node *InsertAfter = list_get(&Head, 'c');
list_insert_after(InsertAfter, 'd');
// NOTE: prints out the whole list
for(node *Iter = Head; Iter; Iter = Iter->Next)
{
printf("%c ", Iter->Character);
}
printf("\n");
// NOTE: prints out the previous Node of B, B and the next one
node *B = list_get(&Head, 'b');
if(B)
{
printf("%s %c %s\n",B->Prev? B->Prev: "Null", B->Character, B->Next? B->Next: "Null");
}
list_free(&Head);
}

View File

@ -0,0 +1 @@
^a b c d\s*a b c\s*$

View File

@ -0,0 +1,113 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char Character;
struct node *Next;
struct node *Prev;
}node;
// TODO: chane all the function to use a dlinked list
node *alloc_node(char c, node *Next, node *Prev)
{
node *NewNode = malloc(sizeof(node));
NewNode->Character = c;
NewNode->Next = Next;
NewNode->Prev = Prev;
return NewNode;
}
// NOTE: adds an element to the beginning
void list_add(node **Head, char c)
{
node *NewNode = alloc_node(c, *Head, 0);
if(*Head)
(*Head)->Prev = NewNode;
*Head = NewNode;
}
// NOTE: inserts after a specific node
void list_insert_after(node *Node, char c)
{
node *NewNode = alloc_node(c, Node->Next, Node);
node *Next = Node->Next;
if(Next)
{
Next->Prev = NewNode;
}
Node->Next = NewNode;
}
// NOTE: get's a node with the specified character
node *list_get(node **Head, char c)
{
node *Result;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter->Character == c)
{
Result = Iter;
break;
}
}
return Result;
}
// NOTE: removes a specific node from the list
void list_remove(node **Head, node *Node)
{
// NOTE: this should get simpler
// Find prev node
node *Prev = Node->Prev;
if(Prev)
Prev->Next = Node->Next;
node *Next = Node->Next;
Next->Prev = Prev;
free(Node);
}
// NOTE: frees the whole list
void list_free(node **Head)
{
for(node *Iter = *Head; Iter; )
{
node *ToFree = Iter;
Iter = Iter->Next;
free(ToFree);
}
}
int main(int argc, char **argv)
{
node *Head = 0;
list_add(&Head, 'c');
list_add(&Head, 'y');
list_add(&Head, 'b');
node *ToBeRemoved = list_get(&Head, 'y');
list_remove(&Head, ToBeRemoved);
list_add(&Head, 'a');
node *InsertAfter = list_get(&Head, 'c');
list_insert_after(InsertAfter, 'd');
// NOTE: Prints out the whole list
for(node *Iter = Head; Iter; Iter = Iter->Next)
{
printf("%c ", Iter->Character);
}
printf("\n");
node *B = list_get(&Head, 'b');
if(B)
{
printf("%s %c %s\n",B->Prev? B->Prev: "Null", B->Character, B->Next? B->Next: "Null");
}
list_free(&Head);
}

View File

@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char Character;
struct node *Next;
}node;
node *alloc_node(char c, node *Next)
{
node *NewNode = malloc(sizeof(node));
NewNode->Character = c;
NewNode->Next = Next;
return NewNode;
}
// NOTE: adds an element to the beginning
void list_add(node **Head, char c)
{
// TODO: implement this
node *NewNode = alloc_node(c, *Head);
*Head = NewNode;
}
// NOTE: inserts after a specific node
void list_insert_after(node *Node, char c)
{
// TODO: implement this
node *NewNode = alloc_node(c, Node->Next);
Node->Next = NewNode;
}
// NOTE: get's a node with the specified character
node *list_get(node **Head, char c)
{
// TODO: implement this
node *Result;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter->Character == c)
{
Result = Iter;
break;
}
}
return Result;
}
// NOTE: removes a specific node from the list
void list_remove(node **Head, node *Node)
{
// TODO: implement this
// Find prev node
node *Prev = 0;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter == Node)
break;
Prev = Iter;
}
if(Prev)
Prev->Next = Node->Next;
free(Node);
}
// NOTE: frees the whole list
void list_free(node **Head)
{
for(node *Iter = *Head; Iter; )
{
node *ToFree = Iter;
Iter = Iter->Next;
free(ToFree);
}
}
int main(int argc, char **argv)
{
// NOTE: beginning of the list
// right now the list is empty
node *Head = 0;
list_add(&Head, 'c');
list_add(&Head, 'y');
list_add(&Head, 'b');
node *ToBeRemoved = list_get(&Head, 'y');
list_remove(&Head, ToBeRemoved);
list_add(&Head, 'a');
node *InsertAfter = list_get(&Head, 'c');
list_insert_after(InsertAfter, 'd');
for(node *Iter = Head; Iter; Iter = Iter->Next)
{
printf("%c ", Iter->Character);
}
printf("\n");
list_free(&Head);
}

View File

@ -0,0 +1 @@
program/match-regex

View File

@ -0,0 +1,8 @@
all:
gcc program.c -o program
#gcc solution.c -o solution
clean:
rm -f program
rm -f solution

View File

@ -0,0 +1,21 @@
The next data-structure is the hash table.
The hash table solves the problem of off having some key associated with
your data and wanting to get the entry in a table.
In an normal array you would have to search the whole list. The same is
true for linked list. A hash table solves this problem by using the key as the index into an array.
The key is normally referred to as the hash and is computed by putting your data trough a hash-function.
The first problem you can easily imagine is, that two different entries get the same hash. This
is called a collision. There are different strategies of solving those collisions.
Some are inline solutions and use the next indices to store the entry others require other data-structures.
Our hash-table will use a dlinked-list for these collision. If we detect a collision the new entry is
saved as the head of the linked list.
A downside of a hash table is that it is hard to balance wasted space and avoiding collision.
You have to have a good hash function and good testing to determine with what kind of space you can
get away with.
You task is to implement the hash table.

View File

@ -0,0 +1,53 @@
node *alloc_node(int Value, int x, int y, node *Next)
{
node *NewNode = malloc(sizeof(node));
NewNode->Value = Value;
NewNode->x = x;
NewNode->y = y;
NewNode->Next = Next;
return NewNode;
}
void list_add(node **Head, int Value, int x, int y)
{
node *NewNode = alloc_node(Value, x, y, *Head);
*Head = NewNode;
}
node *list_get(node **Head, int x, int y)
{
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter->x == x && Iter->y == y)
{
return Iter;
}
}
return 0;
}
void list_remove(node **Head, node *Node)
{
node *Prev = 0;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter == Node)
break;
Prev = Iter;
}
if(Prev)
Prev->Next = Node->Next;
free(Node);
}
void list_free(node **Head)
{
for(node *Iter = *Head; Iter; )
{
node *ToFree = Iter;
Iter = Iter->Next;
free(ToFree);
}
}

View File

@ -0,0 +1 @@
{"title": "Hash Table"}

View File

@ -0,0 +1,110 @@
#include <stdio.h>
#include <stdlib.h>
#define HASH_TABLE_SIZE 32
// NOTE: the data is some value, which is on a certain 2D point (x,y)
typedef struct node
{
// the data
int x,y;
float Value;
// next entry in the hash-table, if there were a collision
struct node *Next;
}node;
#include "linked_list.h"
/*
* Linked-list interface
*
* void list_add(node **Head, int Value, int x, int y);
*
* node *list_get(node **Head, int x, int y);
*
* void list_remove(node **Head, node *Node);
*
*/
// NOTE: this computes the hash slot of the entry
int hash(int x, int y)
{
int Result = (x + y)%HASH_TABLE_SIZE;
if(Result < 0)
Result *= -1;
return Result;
}
// NOTE: adds a new entry to the hash table.
// new entries go at the head of the linked-list
void hash_add(node **HashTable, float Value, int x, int y)
{
// Don't forget to update the hash-tables pointer to the head.
}
// NOTE: gets the note at the position (x,y)
node *hash_get(node **HashTable, int x, int y)
{
return 0;
}
// NOTE: removes the node at position (x,y),
// if there is one
void hash_remove(node **HashTable, int x, int y)
{
}
int main(int argc, char *argv)
{
node *HashTable[HASH_TABLE_SIZE] = {};
// NOTE: some test values
hash_add(HashTable, 1.0, 1, 0);
hash_add(HashTable, 3.0, 0, 1);
hash_add(HashTable, 5.0, 3, -2);
hash_add(HashTable, 7.0, 10, 3);
// NOTE: test adding with collisions
node *Node = hash_get(HashTable, 1, 0);
if(Node)
printf("Succesfully added value %f at position (%d,%d) to the HashTable\n", Node->Value, Node->x, Node->y);
else
printf("Failed to add or find value 1 at position (1,0)\n");
Node = hash_get(HashTable, 0, 1);
int added01 = 0;
if(Node)
{
printf("Succesfully added value %f at position (%d,%d) to the HashTable\n", Node->Value, Node->x, Node->y);
added01 = 1;
}
else
printf("Failed to add or find value 3 at position (0,1)\n");
Node = hash_get(HashTable, 3, -2);
if(Node)
printf("Succesfully added value %f at position (%d,%d) to the HashTable\n", Node->Value, Node->x, Node->y);
else
printf("Failed to add or find value 5 at position (-2,-2)\n");
Node = hash_get(HashTable, 10, 3);
if(Node)
printf("Succesfully added value %f at position (%d,%d) to the HashTable\n", Node->Value, Node->x, Node->y);
else
printf("Failed to add or find value 7 at position (10,3)\n");
// NOTE: test removing element
if(added01)
{
hash_remove(HashTable, 0, 1);
Node = hash_get(HashTable, 0, 1);
if(!Node)
printf("Succesfully removed entrie at position (0,1) from the HashTable\n");
else
printf("Failed to remove entrie at position (0,1)\n");
}
}

View File

@ -0,0 +1 @@
^Succesfully added value 1.000000 at position (1,0) to the HashTable\nSuccesfully added value 3.000000 at position (0,1) to the HashTable\nSuccesfully added value 5.000000 at position (3,-2) to the HashTable\nSuccesfully added value 7.000000 at position (10,3) to the HashTable\nSuccesfully removed entrie at position (0,1) from the HashTable$

View File

@ -0,0 +1,116 @@
#include <stdio.h>
#include <stdlib.h>
#define HASH_TABLE_SIZE 32
// NOTE: the data is some value, which is on a certain 2D point (x,y)
typedef struct node
{
// the data
int x,y;
float Value;
// next entrie in the hashtable, if there were a collision
struct node *Next;
}node;
#include "linked_list.h"
/*
* Linked-list interface
*
* void list_add(node **Head, int Value, int x, int y);
*
* node *list_get(node **Head, int x, int y);
*
* void list_remove(node **Head, node *Node);
*
*/
int hash(int x, int y)
{
int Result = (x + y)%HASH_TABLE_SIZE;
if(Result < 0)
Result *= -1;
return Result;
}
void hash_add(node **HashTable, float Value, int x, int y)
{
int Hash = hash(x,y);
node *Head = HashTable[Hash];
list_add(&Head, Value, x, y);
// Don't forget to update the Hashtables pointer to the head.
HashTable[Hash] = Head;
}
node *hash_get(node **HashTable, int x, int y)
{
int Hash = hash(x,y);
node *Head = HashTable[Hash];
node *Result = list_get(&Head, x, y);
return Result;
}
void hash_remove(node **HashTable, int x, int y)
{
int Hash = hash(x,y);
node *Head = HashTable[Hash];
node *Node = list_get(&Head, x, y);
if(Node)
list_remove(&Head, Node);
}
int main(int argc, char *argv)
{
node *HashTable[HASH_TABLE_SIZE] = {};
//payload D1 = {0, 0, 1.0, 0};
hash_add(HashTable, 1.0, 1, 0);
hash_add(HashTable, 3.0, 0, 1);
hash_add(HashTable, 5.0, 3, -2);
hash_add(HashTable, 7.0, 10, 3);
// Note: Test adding with collisions
node *Node = hash_get(HashTable, 1, 0);
if(Node)
printf("Succesfully added value %f at position (%d,%d) to the HashTable\n", Node->Value, Node->x, Node->y);
else
printf("Failed to add or find value 1 at position (1,0)\n");
Node = hash_get(HashTable, 0, 1);
int added01 = 0;
if(Node)
{
printf("Succesfully added value %f at position (%d,%d) to the HashTable\n", Node->Value, Node->x, Node->y);
added01 = 1;
}
else
printf("Failed to add or find value 3 at position (0,1)\n");
Node = hash_get(HashTable, 3, -2);
if(Node)
printf("Succesfully added value %f at position (%d,%d) to the HashTable\n", Node->Value, Node->x, Node->y);
else
printf("Failed to add or find value 5 at position (-2,-2)\n");
Node = hash_get(HashTable, 10, 3);
if(Node)
printf("Succesfully added value %f at position (%d,%d) to the HashTable\n", Node->Value, Node->x, Node->y);
else
printf("Failed to add or find value 7 at position (10,3)\n");
// NOTE: Test removing element
if(added01)
{
hash_remove(HashTable, 0, 1);
Node = hash_get(HashTable, 0, 1);
if(!Node)
printf("Succesfully removed entrie at position (0,1) from the HashTable\n");
else
printf("Failed to remove entrie at position (0,1)\n");
}
}

View File

@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char Character;
struct node *Next;
}node;
node *alloc_node(char c, node *Next)
{
node *NewNode = malloc(sizeof(node));
NewNode->Character = c;
NewNode->Next = Next;
return NewNode;
}
// NOTE: adds an element to the beginning
void list_add(node **Head, char c)
{
// TODO: implement this
node *NewNode = alloc_node(c, *Head);
*Head = NewNode;
}
// NOTE: inserts after a specific node
void list_insert_after(node *Node, char c)
{
// TODO: implement this
node *NewNode = alloc_node(c, Node->Next);
Node->Next = NewNode;
}
// NOTE: get's a node with the specified character
node *list_get(node **Head, char c)
{
// TODO: implement this
node *Result;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter->Character == c)
{
Result = Iter;
break;
}
}
return Result;
}
// NOTE: removes a specific node from the list
void list_remove(node **Head, node *Node)
{
// TODO: implement this
// Find prev node
node *Prev = 0;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter == Node)
break;
Prev = Iter;
}
if(Prev)
Prev->Next = Node->Next;
free(Node);
}
// NOTE: frees the whole list
void list_free(node **Head)
{
for(node *Iter = *Head; Iter; )
{
node *ToFree = Iter;
Iter = Iter->Next;
free(ToFree);
}
}
int main(int argc, char **argv)
{
// NOTE: beginning of the list
// right now the list is empty
node *Head = 0;
list_add(&Head, 'c');
list_add(&Head, 'y');
list_add(&Head, 'b');
node *ToBeRemoved = list_get(&Head, 'y');
list_remove(&Head, ToBeRemoved);
list_add(&Head, 'a');
node *InsertAfter = list_get(&Head, 'c');
list_insert_after(InsertAfter, 'd');
for(node *Iter = Head; Iter; Iter = Iter->Next)
{
printf("%c ", Iter->Character);
}
printf("\n");
list_free(&Head);
}

View File

@ -0,0 +1 @@
program/match-regex

View File

@ -0,0 +1,8 @@
all:
gcc program.c -o program
#gcc solution.c -o solution
clean:
rm -f program
rm -f solution

View File

@ -0,0 +1,18 @@
As you noticed, we can use our basic data-structures, to form more complex ones, which fit more specific needs.
This time we will take a look at the queue. This data-structures allows you to perform operations on your data
with the **FIFO**(**F**irst **i**n **F**irst **o**ut) principle. This is critical, if you want to
process the oldest data first, just like in a queue in the real world.
The queue data-structure is normally based on a linked list, such that it is also dynamically growing in size.
But this does not have to be true, but usually, if you are using libraries, it is.
For the queue we want to perform three basic operations.
-first we want to put something at the end of the queue. We call that ``enqueue``.
-second we want to take something of the beginning of the queue. We call that ``dequeue``.
-third we want just look at the end of the queue without taking it of. We call that ``peak``.
There are also other kinds of queues, which will not necessarily operate like a FIFO-queue.
For example the priority-queue, which will sort the member with the highest priority
to the beginning of the queue and uses a heap as it's underlying structure.
Your task is to implement the queue on the basis of a singly linked list.

View File

@ -0,0 +1 @@
{"title": "Queue"}

View File

@ -0,0 +1,70 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char Character;
struct node *Next;
}node;
typedef struct
{
node *Head;
node *Tail;
}queue;
node *alloc_node(char c, node *Next)
{
node *NewNode = malloc(sizeof(node));
NewNode->Character = c;
NewNode->Next = Next;
return NewNode;
}
// You could reuse the implementation of the singly linked list,
// but in this case we can optimize our operations,
// because we have pointers to the beginning end of the linked list.
// NOTE: this put elements on the end of the list
// Don't forget to initialize the Head pointer
void enqueue(queue *Queue, char c)
{
// TODO: implement this
}
// NOTE: This returns the char, because we don't want to manage
// the memory in "user code"
// Don't forget to free the node, otherwise this queue has a leak.
char dequeue(queue *Queue)
{
// TODO: implement this
return 0;
}
// NOTE: in this example we only use this to check if the list is empty.
// To do that we could also track the element count, but the peak operation
// has also some other use cases.
node *peak(queue *Queue)
{
// TODO: implement this
return 0;
}
// you can implement the queue-operations without ever searching through the list.
int main(int argc, char **argv)
{
queue Queue = {};
char *String = "HelloWorld!";
// The String should come out as it went in.
while(*String)
{
enqueue(&Queue, *String++);
}
while(peak(&Queue))
{
printf("%c", dequeue(&Queue));
}
}

View File

@ -0,0 +1 @@
^HelloWorld!$

View File

@ -0,0 +1,69 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char Character;
struct node *Next;
}node;
typedef struct
{
node *Head;
node *Tail;
}queue;
node *alloc_node(char c, node *Next)
{
node *NewNode = malloc(sizeof(node));
NewNode->Character = c;
NewNode->Next = Next;
return NewNode;
}
void enqueue(queue *Queue, char c)
{
// TODO: implement this
node *NewNode = alloc_node(c, 0);
if(Queue->Tail)
Queue->Tail->Next = NewNode;
Queue->Tail = NewNode;
if(!Queue->Head)
{
Queue->Head = NewNode;
}
}
char dequeue(queue *Queue)
{
// TODO: implement this
node *First = Queue->Head;
char Result = First->Character;
Queue->Head = First->Next;
free(First);
return Result;
}
node *peak(queue *Queue)
{
// TODO: implement this
return Queue->Head;
}
int main(int argc, char **argv)
{
queue Queue = {};
char *String = "HelloWorld!";
while(*String)
{
enqueue(&Queue, *String++);
}
while(peak(&Queue))
{
printf("%c", dequeue(&Queue));
}
}

View File

@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char Character;
struct node *Next;
}node;
node *alloc_node(char c, node *Next)
{
node *NewNode = malloc(sizeof(node));
NewNode->Character = c;
NewNode->Next = Next;
return NewNode;
}
// NOTE: adds an element to the beginning
void list_add(node **Head, char c)
{
// TODO: implement this
node *NewNode = alloc_node(c, *Head);
*Head = NewNode;
}
// NOTE: inserts after a specific node
void list_insert_after(node *Node, char c)
{
// TODO: implement this
node *NewNode = alloc_node(c, Node->Next);
Node->Next = NewNode;
}
// NOTE: get's a node with the specified character
node *list_get(node **Head, char c)
{
// TODO: implement this
node *Result;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter->Character == c)
{
Result = Iter;
break;
}
}
return Result;
}
// NOTE: removes a specific node from the list
void list_remove(node **Head, node *Node)
{
// TODO: implement this
// Find prev node
node *Prev = 0;
for(node *Iter = *Head; Iter; Iter = Iter->Next)
{
if(Iter == Node)
break;
Prev = Iter;
}
if(Prev)
Prev->Next = Node->Next;
free(Node);
}
// NOTE: frees the whole list
void list_free(node **Head)
{
for(node *Iter = *Head; Iter; )
{
node *ToFree = Iter;
Iter = Iter->Next;
free(ToFree);
}
}
int main(int argc, char **argv)
{
// NOTE: beginning of the list
// right now the list is empty
node *Head = 0;
list_add(&Head, 'c');
list_add(&Head, 'y');
list_add(&Head, 'b');
node *ToBeRemoved = list_get(&Head, 'y');
list_remove(&Head, ToBeRemoved);
list_add(&Head, 'a');
node *InsertAfter = list_get(&Head, 'c');
list_insert_after(InsertAfter, 'd');
for(node *Iter = Head; Iter; Iter = Iter->Next)
{
printf("%c ", Iter->Character);
}
printf("\n");
list_free(&Head);
}

View File

@ -0,0 +1 @@
program/match-regex

View File

@ -0,0 +1,8 @@
all:
gcc program.c -o program
#gcc solution.c -o solution
clean:
rm -f program
rm -f solution

View File

@ -0,0 +1,17 @@
A data-structure often associated with the queue is the stack.
That's because they are basically the opposite of one another.
While the queue works on the FIFO-principle the stack works
on the **LIFO**-principle (**L**ast **i**n **f**irst **o**ut).
Similar two the queue we have three basic operations, but they are called
different to distinguish between the stack and the queue.
- We put something at the top of the stack. That is called push.
- We take something from the top of the stack. That is called pop.
- As with the queue we sometimes one to just take a look at the top of the stack.
So a peak operation is nice, but not necessary
Stacks are useful data-structures for parsing or when you want follow some data to the end
and then back trace to a previous state, like in depth-fist-search.
These are just some use cases for stacks, but they have many more.
Your task is to implement the push, pop and peak functions for the stack.

View File

@ -0,0 +1 @@
{"title": "Stack"}

View File

@ -0,0 +1,57 @@
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
char Character;
struct node *Next;
}node;
typedef struct
{
node *Top;
}stack;
node *alloc_node(char c, node *Next)
{
node *NewNode = malloc(sizeof(node));
NewNode->Character = c;
NewNode->Next = Next;
return NewNode;
}
void push(stack *Stack,char c)
{
// TODO: implement this
}
// NOTE: as last time free the node here
char pop(stack *Stack)