归并排序循环链表 C
Merge sort circular linked list C
我正在尝试对 C 中的列表进行合并排序。我看到了代码 here on French Wikipedia,但它给了我一个不正确的列表(即未排序)。尽管该函数可以完美编译。请注意,我并没有真正使用 top
,我可能很快就会将其从结构中删除。你能帮我弄清楚这段代码有什么问题吗?我不得不将它从算法伪代码翻译成 C 代码。
谢谢。
P
是未排序的输入列表。
n
是列表的长度。
typedef struct s_stack t_stack;
struct s_stack {
int nbr;
int top;
struct s_stack *previous;
struct s_stack *next;
};
typedef t_stack *Pile;
t_stack *merge_sort(Pile p, int n) {
Pile q;
int Q;
int P;
q = NULL;
Q = n / 2;
P = n - Q;
if (P >= 2) {
q = merge_sort(p, P);
if (Q >= 2)
p = merge_sort(q, Q);
} else {
q = p->next;
}
q = fusion(p, P, q, Q);
return (q);
}
t_stack *fusion(Pile p, int P, Pile q, int Q) {
t_stack *tmp;
tmp = NULL;
while (1) {
if (p->next->nbr > q->next->nbr) {
/* my input list (not sorted) is circular and
I checked it is well linked ! This is the reason
why I need to do all that stuff with the nodes
It is basically supposed to move the node q->next
after node p */
tmp = q->next;
q->next = tmp->next;
q->next->previous = q;
tmp->previous = p;
tmp->next = p->next;
p->next->previous = tmp;
p->next = tmp;
if (Q == 1)
break;
Q = Q - 1;
} else {
if (P == 1) {
while (Q >= 1) {
q = q->next;
Q = Q - 1;
}
break;
}
P = P - 1;
}
p = p->next;
}
return (q);
}
你的方法有点复杂,但问题没那么简单,但是你漏掉了一些必要的步骤:
merge_sort
应该将列表分成两半并递归,除非
该列表很简单。
fusion
必须使用 3 个阶段:通过取最小值合并列表
每个列表中的元素,然后附加第一个的其余部分
列出并最后附加剩余元素形成第二个列表。
- 将指针隐藏在
typedef
后面通常不是一个好主意,它
使代码的可读性降低。
这是一个修正后的版本,带有一个 main
函数用于测试
命令行参数。
#include <stdio.h>
#include <stdlib.h>
typedef struct s_stack t_stack;
struct s_stack {
int nbr;
int top;
struct s_stack *previous;
struct s_stack *next;
};
t_stack *fusion(t_stack *p, int P, t_stack *q, int Q) {
t_stack *s;
t_stack *e;
s = NULL;
while (P > 0 && Q > 0) {
if (p->nbr <= q->nbr) {
/* select element from p list */
e = p;
p = p->next;
P--;
} else {
/* select element from q list */
e = q;
q = q->next;
Q--;
}
/* detach e */
e->previous->next = e->next;
e->next->previous = e->previous;
e->next = e->previous = e;
if (s == NULL) {
s = e;
} else {
/* insert e after s */
e->previous = s->previous;
e->next = s;
s->previous->next = e;
s->previous = e;
}
}
if (P > 0) {
/* insert p at the end of s */
if (s == NULL) {
s = p;
} else {
/* insert p after s */
e = p->previous; /* end element of p */
p->previous = s->previous;
e->next = s;
s->previous->next = p;
s->previous = e;
}
}
if (Q > 0) {
/* insert q at the end of s */
if (s == NULL) {
s = q;
} else {
/* insert q after s */
e = q->previous; /* end element of p */
q->previous = s->previous;
e->next = s;
s->previous->next = q;
s->previous = e;
}
}
return s;
}
t_stack *merge_sort(t_stack *s, int S) {
t_stack *p;
t_stack *q;
int P;
int Q;
if (S < 2) {
/* single or no elements, already sorted */
return s;
}
/* split p in 2 halves: p[0..P] and q[0..Q] */
for (q = p = s, P = 0, Q = S; P < Q; P++, Q--) {
q = q->next;
}
p = merge_sort(p, P);
q = merge_sort(q, Q);
s = fusion(p, P, q, Q);
return s;
}
t_stack *append(t_stack *s, int value) {
t_stack *e = malloc(sizeof(*e));
e->top = 0;
e->nbr = value;
e->next = e->previous = e;
if (s == NULL) {
s = e;
} else {
/* insert e after s */
e->previous = s->previous;
e->next = s;
s->previous->next = e;
s->previous = e;
}
return s;
}
void print_stack(const char *legend, t_stack *s, int S) {
printf("%s:", legend);
while (S-- > 0) {
printf(" %d", s->nbr);
s = s->next;
}
printf("\n");
fflush(stdout);
}
int main(int argc, char *argv[]) {
t_stack *s = NULL;
int S = 0;
int i;
for (i = 1; i < argc; i++) {
s = append(s, atoi(argv[i]));
S++;
}
print_stack("original stack", s, S);
s = merge_sort(s, S);
print_stack("sorted stack", s, S);
return 0;
}
我正在尝试对 C 中的列表进行合并排序。我看到了代码 here on French Wikipedia,但它给了我一个不正确的列表(即未排序)。尽管该函数可以完美编译。请注意,我并没有真正使用 top
,我可能很快就会将其从结构中删除。你能帮我弄清楚这段代码有什么问题吗?我不得不将它从算法伪代码翻译成 C 代码。
谢谢。
P
是未排序的输入列表。
n
是列表的长度。
typedef struct s_stack t_stack;
struct s_stack {
int nbr;
int top;
struct s_stack *previous;
struct s_stack *next;
};
typedef t_stack *Pile;
t_stack *merge_sort(Pile p, int n) {
Pile q;
int Q;
int P;
q = NULL;
Q = n / 2;
P = n - Q;
if (P >= 2) {
q = merge_sort(p, P);
if (Q >= 2)
p = merge_sort(q, Q);
} else {
q = p->next;
}
q = fusion(p, P, q, Q);
return (q);
}
t_stack *fusion(Pile p, int P, Pile q, int Q) {
t_stack *tmp;
tmp = NULL;
while (1) {
if (p->next->nbr > q->next->nbr) {
/* my input list (not sorted) is circular and
I checked it is well linked ! This is the reason
why I need to do all that stuff with the nodes
It is basically supposed to move the node q->next
after node p */
tmp = q->next;
q->next = tmp->next;
q->next->previous = q;
tmp->previous = p;
tmp->next = p->next;
p->next->previous = tmp;
p->next = tmp;
if (Q == 1)
break;
Q = Q - 1;
} else {
if (P == 1) {
while (Q >= 1) {
q = q->next;
Q = Q - 1;
}
break;
}
P = P - 1;
}
p = p->next;
}
return (q);
}
你的方法有点复杂,但问题没那么简单,但是你漏掉了一些必要的步骤:
merge_sort
应该将列表分成两半并递归,除非 该列表很简单。fusion
必须使用 3 个阶段:通过取最小值合并列表 每个列表中的元素,然后附加第一个的其余部分 列出并最后附加剩余元素形成第二个列表。- 将指针隐藏在
typedef
后面通常不是一个好主意,它 使代码的可读性降低。
这是一个修正后的版本,带有一个 main
函数用于测试
命令行参数。
#include <stdio.h>
#include <stdlib.h>
typedef struct s_stack t_stack;
struct s_stack {
int nbr;
int top;
struct s_stack *previous;
struct s_stack *next;
};
t_stack *fusion(t_stack *p, int P, t_stack *q, int Q) {
t_stack *s;
t_stack *e;
s = NULL;
while (P > 0 && Q > 0) {
if (p->nbr <= q->nbr) {
/* select element from p list */
e = p;
p = p->next;
P--;
} else {
/* select element from q list */
e = q;
q = q->next;
Q--;
}
/* detach e */
e->previous->next = e->next;
e->next->previous = e->previous;
e->next = e->previous = e;
if (s == NULL) {
s = e;
} else {
/* insert e after s */
e->previous = s->previous;
e->next = s;
s->previous->next = e;
s->previous = e;
}
}
if (P > 0) {
/* insert p at the end of s */
if (s == NULL) {
s = p;
} else {
/* insert p after s */
e = p->previous; /* end element of p */
p->previous = s->previous;
e->next = s;
s->previous->next = p;
s->previous = e;
}
}
if (Q > 0) {
/* insert q at the end of s */
if (s == NULL) {
s = q;
} else {
/* insert q after s */
e = q->previous; /* end element of p */
q->previous = s->previous;
e->next = s;
s->previous->next = q;
s->previous = e;
}
}
return s;
}
t_stack *merge_sort(t_stack *s, int S) {
t_stack *p;
t_stack *q;
int P;
int Q;
if (S < 2) {
/* single or no elements, already sorted */
return s;
}
/* split p in 2 halves: p[0..P] and q[0..Q] */
for (q = p = s, P = 0, Q = S; P < Q; P++, Q--) {
q = q->next;
}
p = merge_sort(p, P);
q = merge_sort(q, Q);
s = fusion(p, P, q, Q);
return s;
}
t_stack *append(t_stack *s, int value) {
t_stack *e = malloc(sizeof(*e));
e->top = 0;
e->nbr = value;
e->next = e->previous = e;
if (s == NULL) {
s = e;
} else {
/* insert e after s */
e->previous = s->previous;
e->next = s;
s->previous->next = e;
s->previous = e;
}
return s;
}
void print_stack(const char *legend, t_stack *s, int S) {
printf("%s:", legend);
while (S-- > 0) {
printf(" %d", s->nbr);
s = s->next;
}
printf("\n");
fflush(stdout);
}
int main(int argc, char *argv[]) {
t_stack *s = NULL;
int S = 0;
int i;
for (i = 1; i < argc; i++) {
s = append(s, atoi(argv[i]));
S++;
}
print_stack("original stack", s, S);
s = merge_sort(s, S);
print_stack("sorted stack", s, S);
return 0;
}