题目:遍历单向链表的后N个节点,要求算法时间复杂度小于等于O(n),空间复杂度为O(1)。
很久以前前任经理问的问题。当时没明白,经理也没给空间复杂度的要求。
当时的想法就是用个向量(vector)保存所有节点的位置(相当于建立索引),然后再从向量的倒数第n个元素遍历。
今天逛网站看到别人给的算法,很不错,特别是两行LISP的代码,更令我觉得LISP必须要坚持学了。
原文网址:遍历单向链表的后N个节点。
下面是我看过别人代码后写的C代码:
tail.h
#ifndef __TAIL_H_
#define __TAIL_H_
typedef long T;
typedef struct node_s
{
struct node_s *next;
T data;
} node_t;
typedef void visitor_t(const node_t *node);
T data(const node_t *node);
node_t *next(const node_t *node);
node_t *list(node_t *node, visitor_t visitor);
node_t *tail(node_t *header, int n);
#endif //__TAIL_H_
tail.c
#include "tail.h"
T data(const node_t *node)
{
return node->data;
}
node_t *next(const node_t *node)
{
return node->next;
}
node_t *list(node_t *node, visitor_t visitor)
{
while (node)
{
visitor(node);
node = next(node);
}
return node;
}
node_t *tail(node_t *header, int n)
{
node_t *first = header;
for (int i = 0; (first) && (i < n); ++i)
first = next(first);
node_t *second = header;
while (first)
{
first = next(first);
second = next(second);
}
return second;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "tail.h"
void print_node(const node_t *node)
{
printf("%ld, ", data(node));
}
node_t *create_list(int size)
{
node_t *nodes = (node_t *)calloc(size, sizeof(node_t));
for (int i = 0; i < size; ++i)
{
nodes[i].data = i + 1;
nodes[i].next = &(nodes[i + 1]);
}
nodes[size - 1].next = NULL;
return nodes;
}
void destroy_list(node_t *header)
{
free(header);
}
void usage(const char *cmd)
{
printf("Usage: %s size n\n", cmd);
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
usage(argv[0]);
return 0;
}
int size = atoi(argv[1]);
int n = atoi(argv[2]);
node_t *nodes = create_list(size);
node_t *tail_node = tail(nodes, n);
list(tail_node, print_node);
destroy_list(nodes);
return 0;
}