contributed by < timsong1 >
$ gcc --version
gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 39 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Vendor ID: GenuineIntel
Model name: Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz
CPU family: 6
Model: 126
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
Stepping: 5
CPU(s) scaling MHz: 33%
CPU max MHz: 3600.0000
CPU min MHz: 400.0000
BogoMIPS: 2380.80
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge m
ca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 s
s ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc
art arch_perfmon pebs bts rep_good nopl xtopology nons
top_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq
dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16
xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_d
eadline_timer aes xsave avx f16c rdrand lahf_lm abm 3d
nowprefetch cpuid_fault epb ssbd ibrs ibpb stibp ibrs_
enhanced tpr_shadow flexpriority ept vpid ept_ad fsgsb
ase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512
f avx512dq rdseed adx smap avx512ifma clflushopt intel
_pt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec
xgetbv1 xsaves split_lock_detect dtherm ida arat pln p
ts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req v
nmi avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes v
pclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq r
dpid fsrm md_clear flush_l1d arch_capabilities
Virtualization features:
Virtualization: VT-x
Caches (sum of all):
L1d: 192 KiB (4 instances)
L1i: 128 KiB (4 instances)
L2: 2 MiB (4 instances)
L3: 6 MiB (1 instance)
NUMA:
NUMA node(s): 1
NUMA node0 CPU(s): 0-7
Vulnerabilities:
Gather data sampling: Mitigation; Microcode
Itlb multihit: KVM: Mitigation: VMX disabled
L1tf: Not affected
Mds: Not affected
Meltdown: Not affected
Mmio stale data: Mitigation; Clear CPU buffers; SMT vulnerable
Reg file data sampling: Not affected
Retbleed: Mitigation; Enhanced IBRS
Spec rstack overflow: Not affected
Spec store bypass: Mitigation; Speculative Store Bypass disabled via prct
l
Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointe
r sanitization
Spectre v2: Mitigation; Enhanced / Automatic IBRS; IBPB conditiona
l; RSB filling; PBRSB-eIBRS SW sequence; BHI SW loop,
KVM SW loop
Srbds: Mitigation; Microcode
Tsx async abort: Not affected
Create an empty queue
struct list_head *q_new()
{
struct list_head *head =
(struct list_head *) malloc(sizeof(struct list_head));
if (head) {
head->prev = head;
head->next = head;
}
return head;
}
Free all storage used by queue
void q_free(struct list_head *head)
{
if (!head)
return;
if (list_empty(head)) {
free(head);
return;
}
while (!list_empty(head)) {
struct list_head *curr = head->next;
list_del(curr);
element_t *element = container_of(curr, element_t, list);
q_release_element(element);
}
free(head);
}
Insert an element at head of queue
bool q_insert_head(struct list_head *head, char *s)
{
if (!head || !s)
return false;
const char *cs = s;
element_t *element = (element_t *) malloc(sizeof(element_t));
if (!element)
return false;
element->value = strdup(cs);
if (!element->value) {
free(element);
return false;
}
list_add(&element->list, head);
return true;
}
Insert an element at tail of queue
bool q_insert_head(struct list_head *head, char *s)
{
if (!head || !s)
return false;
const char *cs = s;
element_t *element = (element_t *) malloc(sizeof(element_t));
if (!element)
return false;
element->value = strdup(cs);
if (!element->value) {
free(element);
return false;
}
list_add_tail(&element->list, head);
return true;
}
Remove an element from head of queue
element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || list_empty(head))
return NULL;
element_t *curr = container_of(head->next, element_t, list);
curr->list.next->prev = head;
head->next = curr->list.next;
curr->list.next = curr->list.prev = NULL;
if (sp && bufsize > 0) {
strncpy(sp, curr->value, bufsize - 1);
sp[bufsize - 1] = '\0';
}
return curr;
}
Remove an element from tail of queue
element_t *q_remove_tail(struct list_head *head, char *sp, size_t bufsize)
{
if (!head || list_empty(head))
return NULL;
element_t *curr = container_of(head->prev, element_t, list);
curr->list.prev->next = head;
head->prev = curr->list.prev;
curr->list.next = curr->list.prev = NULL;
if (sp && bufsize > 0) {
strncpy(sp, curr->value, bufsize - 1);
sp[bufsize - 1] = '\0';
}
return curr;
}
Return number of elements in queue
int q_size(struct list_head *head)
{
if (!head)
return 0;
int len = 0;
struct list_head *li;
list_for_each (li, head)
len++;
return len;
}
Delete the middle node in queue
bool q_delete_mid(struct list_head *head)
{
if (!head || list_empty(head))
return false;
struct list_head *left, *right;
left = head->prev;
right = head->next;
while (left != right && left->prev != right) {
left = left->prev;
right = right->next;
}
list_del(left);
q_release_element(list_entry(left, element_t, list));
return true;
}
Delete all nodes that have duplicate string
寫了一個 helper fuction : delete_linked_list() 用來刪除佇列中特定範圍的節點
void delete_linked_list(struct list_head *head,
struct list_head *from,
struct list_head *to)
{
struct list_head *node, *safe;
bool flag = false;
list_for_each_safe (node, safe, head) {
if (node == to)
return;
if (node == from)
flag = true;
if (flag) {
list_del(node);
q_release_element(list_entry(node, element_t, list));
}
}
}
bool q_delete_dup(struct list_head *head)
{
// https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
if (!head || list_empty(head))
return false;
if (head->next == head->prev)
return true;
struct list_head *curr = head->next, *next = curr->next;
while (curr != head && next != head) {
const element_t *element = list_entry(curr, element_t, list);
if (strcmp(element->value, list_entry(next, element_t, list)->value) ==
0) {
while (next != head) {
if (strcmp(list_entry(next, element_t, list)->value,
element->value) != 0)
break;
next = next->next;
}
delete_linked_list(head, curr, next);
curr = next;
next = next->next;
continue;
}
curr = curr->next;
next = curr->next;
}
return true;
}
Swap every two adjacent nodes
void q_swap(struct list_head *head)
{
// https://leetcode.com/problems/swap-nodes-in-pairs/
if (!head || head->next == head->prev) {
return;
}
struct list_head *curr, *next;
curr = head->next;
next = curr->next;
while (curr != head && next != head) {
curr->prev->next = next; // change the curr and next node
next->next->prev = curr;
curr->next = next->next;
next->prev = curr->prev;
curr->prev = next;
next->next = curr;
curr = curr->next; // move the curr and next pointer forward
next = curr->next;
}
}
Reverse elements in queue
void q_reverse(struct list_head *head)
{
if (!head || head->next == head->prev)
return;
struct list_head *node = NULL, *safe;
list_for_each_safe (node, safe, head) {
list_move(node, head);
}
}
Reverse the nodes of the list k at a time
void q_reverseK(struct list_head *head, int k)
{
// https://leetcode.com/problems/reverse-nodes-in-k-group/
// Assume k is a positive integer and is less than or equal to the length of
// the linked list.
if (!head || head->prev == head->next)
return;
int len = 0;
struct list_head *li = head->next, *start = head, *stop;
while (li != head) {
len++;
if (len == k) {
stop = li->next;
struct list_head *curr = start->next, *next = curr->next,
*next_start = stop;
while (curr != stop) {
while (next != stop) {
curr->prev->next = next;
next->next->prev = curr;
curr->next = next->next;
next->prev = curr->prev;
curr->prev = next;
next->next = curr;
next = curr->next;
}
curr = start->next;
next = curr->next;
stop = stop->prev;
}
len = 0;
li = start = next_start->prev;
}
li = li->next;
}
}
想試著修改 reverseK(),在函式裡面可以呼叫 reverse()
程式(以下)還有問題,待編輯
void q_reverseK(struct list_head *head, int k)
{
// https://leetcode.com/problems/reverse-nodes-in-k-group/
// Assume k is a positive integer and is less than or equal to the length of
// the linked list.
if (!head || head->prev == head->next)
return;
int len = 0;
struct list_head *li = head->next, *start = head,
*new_head = head, *new_start;
while (li != head) {
len++;
if (len == k) {
new_start = li->next;
start->next->prev = new_head;
new_start->prev->next = new_head;
new_head->next = start->next;
new_head->prev = new_start->prev;
q_reverse(new_head);
new_head->next->prev = start;
new_head->prev->next = new_start;
len = 0;
start = new_start;
li = new_start;
continue;
}
li = li->next;
}
}
Sort elements of queue in ascending/descending order
目前此方法是採遞迴 top-down merge sort 來排序
正在嘗試引用 lib/list_sort.c
struct list_head *merge_sort(struct list_head *head, bool descend)
{
if (!head || !head->next)
return head;
struct list_head *slow, *fast, *left, *right;
slow = fast = left = head;
// left = head->next;
while (fast && fast->next && fast->next->next) {
slow = slow->next;
fast = fast->next->next;
}
right = slow->next;
slow->next = NULL;
right->prev = NULL;
left = merge_sort(left, descend);
right = merge_sort(right, descend);
struct list_head **ptr = &head;
for (;;) {
if (!left) {
*ptr = right;
break;
}
if (!right) {
*ptr = left;
break;
}
if (strcmp(list_entry(left, element_t, list)->value,
list_entry(right, element_t, list)->value) > 0) {
if (descend) {
*ptr = left;
ptr = &left->next;
left = left->next;
} else {
*ptr = right;
ptr = &right->next;
right = right->next;
}
} else {
if (descend) {
*ptr = right;
ptr = &right->next;
right = right->next;
} else {
*ptr = left;
ptr = &left->next;
left = left->next;
}
}
}
return head;
}
/* Sort elements of queue in ascending/descending order */
void q_sort(struct list_head *head, bool descend)
{
if (!head || head->next == head->prev)
return;
head->prev->next = NULL;
head->next = merge_sort(head->next, descend);
// re-link prev pointer
struct list_head *li = head->next, *prev = head;
while (li) {
li->prev = prev;
li = li->next;
prev = prev->next;
}
prev->next = head;
head->prev = prev;
}
Remove every node which has a node with a strictly less value anywhere to the right side of it
int q_ascend(struct list_head *head)
{
// https://leetcode.com/problems/remove-nodes-from-linked-list/
int count = 1;
if (!head || head->prev == head->next)
return 0;
struct list_head *curr = head->prev, *min = head->prev, *prev = curr->prev;
while (curr->prev != head) {
element_t *previous;
const element_t *min_element;
previous = list_entry(prev, element_t, list);
min_element = list_entry(min, element_t, list);
if (strcmp(previous->value, min_element->value) > 0) {
list_del(prev);
q_release_element(previous);
prev = curr->prev;
} else {
min = curr = prev;
count++;
prev = curr->prev;
}
}
return count;
}
Remove every node which has a node with a strictly greater value anywhere to the right side of it
int q_descend(struct list_head *head)
{
// https://leetcode.com/problems/remove-nodes-from-linked-list/
int count = 1;
if (!head || head->prev == head->next)
return 0;
struct list_head *curr = head->prev, *max = head->prev, *prev = curr->prev;
while (curr->prev != head) {
element_t *previous;
const element_t *max_element;
previous = list_entry(prev, element_t, list);
max_element = list_entry(max, element_t, list);
if (strcmp(previous->value, max_element->value) < 0) {
list_del(prev);
q_release_element(previous);
prev = curr->prev;
} else {
max = curr = prev;
count++;
prev = curr->prev;
}
}
return count;
}
Merge all the queues into one sorted queue, which is in ascending/descending order
queue_contex_t
資料結構中用來串接每個 queue 的 chain
一樣也是會有一個 head
指標當作 dummy node (或叫 sentinel node)
int q_merge(struct list_head *head, bool descend)
{
// https://leetcode.com/problems/merge-k-sorted-lists/
if (!head || list_empty(head))
return 0;
queue_contex_t *context = list_entry(head->next, queue_contex_t, chain);
struct list_head *first_queue;
context->q->prev->next = NULL;
struct list_head *li = context->chain.next;
while (li != head) {
first_queue = context->q->next;
queue_contex_t *li_context = list_entry(li, queue_contex_t, chain);
li_context->q->prev->next = NULL;
struct list_head *curr = li_context->q->next;
struct list_head **ptr = &context->q->next;
for (;;) {
if (!curr) {
*ptr = first_queue;
break;
}
if (!first_queue) {
*ptr = curr;
break;
}
if (strcmp(list_entry(first_queue, element_t, list)->value,
list_entry(curr, element_t, list)->value) > 0) {
if (descend) {
*ptr = first_queue;
ptr = &first_queue->next;
first_queue = first_queue->next;
} else {
*ptr = curr;
ptr = &curr->next;
curr = curr->next;
}
} else {
if (descend) {
*ptr = curr;
ptr = &curr->next;
curr = curr->next;
} else {
*ptr = first_queue;
ptr = &first_queue->next;
first_queue = first_queue->next;
}
}
}
context->size += li_context->size;
INIT_LIST_HEAD(li_context->q);
li_context->size = 0;
li = li->next;
}
struct list_head *index = context->q, *next = index->next;
while (next) {
next->prev = index;
index = index->next;
next = index->next;
}
context->q->prev = index;
index->next = context->q;
return context->size;
}
此方法是使用 buttom up merge sort,並且沒有使用遞迴