# 2019q1 Homework1 (lab0)
contributed by < `wang0630` >
:::danger
認真看作業要求,除了提及如何逐步達到要求,還需要進行:
1. 改善程式效能
2. 解釋自動評分系統運作的原理
3. 提及 qtest 的行為和裡頭的技巧
還未達成符合預期目標,請繼續付出!
:notes: jserv
:::
## Goal
According to the pdf file, we need to implement the following core operations of queue:
1. Create a queue
2. Free all spaces allocated for the queue
3. Insert a new node at the head of the queue
4. Insert a new node at the tail of the queue
5. Pop out the node at the head of the queue
6. Return the number of nodes in the queue
## Implementation
1. Create a new queue:
```clike
queue_t *q_new()
{
queue_t *q = malloc(sizeof(queue_t));
if (!q)
fprintf(stderr, "Malloc call returns null");
else {
q->head = q->tail = NULL;
q->qsize = 0;
}
return q;
}
```
2. Free all spaces allocated for the queue:
```clike
void q_free(queue_t *q)
{
if (!q)
return;
list_ele_t *prev = NULL;
if (q->qsize) {
for (list_ele_t *iter = q->head; iter;) {
free(iter->value);
prev = iter;
iter = iter->next;
free(prev);
}
}
free(q);
}
```
3. Insert a new node at the head of the queue:
```clike
bool q_insert_head(queue_t *q, char *s)
{
if (!q)
return false;
list_ele_t *newh;
newh = malloc(sizeof(list_ele_t));
if (!newh)
return false;
newh->value = malloc(strlen(s) + 1);
if (!newh->value) {
free(newh); // free the new node since it is allocated spaces
return false;
}
memset(newh->value, 0, strlen(s) + 1);
if (s)
strcpy(newh->value, s);
newh->next = q->head; // new node's next to first element or to null if the
// queue is empty
q->head = newh; // insert new node
// if queue is empty before insertion, q->tail should be pointed to the newh
// as well
q->tail = !q->qsize ? newh : q->tail;
q->qsize++;
return true;
}
```
4. Insert a new node at the tail of the queue:
```clike
bool q_insert_tail(queue_t *q, char *s)
{
// maintain a tail field in the queue_t structure to achieve O(1) insertion
if (!q)
return false;
list_ele_t *newh;
newh = malloc(sizeof(list_ele_t));
if (!newh)
return false;
newh->value = malloc(strlen(s) + 1);
if (!newh->value) {
free(newh);
return false;
}
memset(newh->value, 0, strlen(s) + 1);
if (s)
strcpy(newh->value, s);
newh->next = NULL; // tail node's next must be null
if (q->qsize)
q->tail->next = newh;
q->tail = newh;
// if queue is empty before insertion, q->head should be pointed to the newh
// as well
q->head = q->qsize ? q->head : newh;
q->qsize++;
return true;
}
```
5. Pop out the node at the head of the queue:
```clike
bool q_remove_head(queue_t *q, char *sp, size_t bufsize)
{
if (!q || !q->qsize)
return false;
if (sp) { // if sp is non-NULL
memset(sp, 0, bufsize); // clear sp to safely contain the string
strncpy(sp, q->head->value, bufsize - 1);
}
list_ele_t *tmp = q->head; // hold the target node
q->head = q->head->next; // remove the head
q->qsize--;
// if queue is empty after the removal, q->tail should be null as well
q->tail = q->qsize ? q->tail : NULL;
// free the target node
free(tmp->value);
free(tmp);
return true;
}
```
6. Return the number of nodes in the queue:
```clike
int q_size(queue_t *q)
{
return !q ? 0 : q->qsize;
}
```
7. Reverse the queue:
```clike
void q_reverse(queue_t *q)
{
if (!q || !q->qsize || q->qsize == 1)
return;
list_ele_t *prev, *cur, *nextele;
prev = q->head;
cur = nextele = q->head->next; // q->head->next must exist, there is at least two nodes
while (cur) {
nextele = nextele->next;
cur->next = prev;
prev = cur; // move prev
cur = nextele;
}
list_ele_t *tmpHead = q->head;
q->head->next = NULL;
q->head = q->tail;
q->tail = tmpHead;
}
```
## Tools I learned in this assignment:
1. valgrind:
A analysis tool to discover the partial errors.
Useful flags:
* `--track-fds`: track open file fds
* `--leak-check`: track partial memory leak