我必须执行著名的LS命令 我之所以陷入困境,是因为对于每个我要排序的文件夹(ASCII,时间或反向顺序),最后的链接列表都非常长
这是我的链表结构,
typedef struct s_list
{
void *content;
size_t content_size;
struct s_list *next;
} t_list
在void *content
里面放了我的Ls结构,
typedef struct s_dir
{
unsigned int i;
quad_t blocks;
char *pathname;
char *name;
ino_t ino;
uint8_t type;
uint16_t mode;
unsigned char nlink;
char *usrname;
char *grpname;
long long size;
time_t time;
struct s_dir *rec;
struct s_dir *next;
int error;
} t_dir
我目前正在使用此功能对列表进行排序。
static void sort_ascii(t_list **head)
{
t_dir *rep;
t_list *curr;
void *tmp;
t_dir *rep_next;
curr = *head;
while (curr && curr->next && (rep = (t_dir *)curr->content)
&& (rep_next = (t_dir *)curr->next->content))
{
if (ft_strcmp(rep->pathname, rep_next->pathname) > 0)
{
tmp = curr->content;
curr->content = curr->next->content;
curr->next->content = tmp;
curr = *head;
}
curr = curr->next;
}
}
我的问题是,这个速度非常慢。
我想实现另一种排序算法 合并排序或快速排序,我不知道哪种方式最适合我的情况
我根本不知道如何实现这些排序方法 对我来说是全新的。
感谢您的帮助!
答案 0 :(得分:2)
您的排序代码不正确:您交换了content
字段,但没有交换content_size
。您应该通过更新列表元素next
和更新*head
参数来对列表元素进行排序。
您的方法具有二次方复杂度,即使不是更糟。相反,您应该使用 O(N.log(N))的时间复杂度要低得多的mergesort。
这是一个示例(自上而下的合并排序):
/* return the comparison status: 0 for equal, <0 if a < b, >0 if a>b */
int compare_ascii(t_list *a, t_list *b) {
return ft_strcmp(((t_dir *)a->content)->pathname, ((t_dir *)b->content)->pathname);
}
t_list *merge(t_list *a, t_list *b, int (*cmp)(t_list *a, t_list *b)) {
t_list *head = NULL; /* head of the merged list */
t_list **r = &head; /* pointer to the node link */
if (a && b) {
for (;;) {
if ((*cmp)(a, b) <= 0) {
/* link the head node of list a */
*r = a;
r = &a->next;
a = a->next;
if (!a)
break;
} else {
/* link the head node of list b */
*r = b;
r = &b->next;
b = b->next;
if (!b)
break;
}
}
}
/* link the remaining part of a or b if any */
*r = (a == NULL) ? b : a;
return head;
}
t_list *mergesort(t_list *p, int (*cmp)(t_list *a, t_list *b)) {
t_list *a, *b, *last = NULL;
/* find the middle with 2 finger method: a moves twice as fast as b */
for (a = b = p; a && a->next; a = a->next->next, b = b->next)
last = b;
if (last == NULL) {
/* empty list or single element */
return p;
}
/* split in the middle (before b) */
last->next = NULL;
/* sort each half and merge the sorted sublists */
return merge(mergesort(p, cmp), mergesort(b, cmp), cmp);
}
void sort_ascii(t_list **head) {
*head = mergesort(*head, compare_ascii);
}
如 rcgldr 所述,自下而上的合并排序通常更快,因为它不需要扫描列表来查找中间元素,由于缓存不匹配,这可能会很昂贵。与此相对的是,它可能执行更多比较,但时间复杂度为 O(N.log(N)),并且不是递归的。
这是mergesort
的一种版本,使用自下而上的合并排序方式:
t_list *mergesort(t_list *head, int (*cmp)(t_list *a, t_list *b)) {
t_list *array[32]; // sorted sublists: array[i] has 2**i length if not null
t_list *result = head;
int i, top = 0;
// merge nodes into array
while (result != NULL) {
t_list *next = result->next;
result->next = NULL;
// merge sorted sublists by increasing power of 2 sizes
for (i = 0; i < top && array[i] != NULL; i++) {
result = merge(array[i], result, cmp);
array[i] = NULL;
}
// store the merged list, update top, do not go past end of array
if (i == top) {
if (top < 32)
top++;
else
i--;
}
array[i] = result;
result = next;
}
// merge all sorted sublists into single list
result = NULL;
for (i = 0; i < top; i++) {
result = merge(array[i], result, cmp);
}
return result;
}