遍历单向链表的后N个节点

2 篇文章 0 订阅
1 篇文章 0 订阅

题目:遍历单向链表的后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;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值