简单算法 - 找到链表的中间点和倒数第K个节点(普通方法和快慢指针方法开销一样)


1.1.1           单向链表的中间节点

思路一

先遍历一次链表,得到链表长度,求出中间节点的位置,再从链表头开始遍历,直到找到中间节点的位置。

复杂度大概是O(3/2n)

 

思路二

设置两个指针从链表头节点开始往下遍历,其中一个指针一次往下走2个节点,一个指针一次往下走一个节点,当快的指针到达最后一个时,慢的指针正好到达中间的节点。

复杂度大概为O(n)

 

比较两个思路

思路一好比让一个人去找某一个路程的中间位置,思路二好比让两个人去找某一个路程的中间位置。

思路一,这个人需要走1.5倍路程就能找到中间点(假设他到达终点后可以马上到达起点)。

思路二,一个人走完了全程,另一个人走了半程,两个人加起来也是1.5倍的路程。

所以,从这个意思上讲,两个方法花销其实是一样的。

 

1.1.1           找到倒数第K个节点

思路一

先遍历一次链表,得到链表长度,求出倒数第K的位置,再从链表头开始遍历,所以一共走了(2L-K)个节点。

 

思路二

和找到中间点思路有点相同,只是让一个指针先走K个节点,然后两个指针每次都走一个节点,当在前面的指针到达终点时,后面的指针正好在倒数第K个节点。所以也一共走了(2L-K)个节点。

 

所以两个方法复杂度也是一样的。

 

代码如下:

/*
 *
 * Introduction : reverse list
 * Author : Gykimo
 * Date : 20121212
 * 
 */

#include <stdio.h>
#include <malloc.h>

typedef struct Node{
	int data;
	struct Node* next;
}Node;

#define LIST_LEN	12	//链表长度
Node * List = NULL;		//链表

//找到链表的中间点
void find_median_ite(){
	Node * fast = List;//每次走两个节点
	Node * slow = List;//每次走一个节点

	while(fast != NULL){
		fast = fast->next;
		if(fast == NULL)
			break;

		fast = fast->next;

		slow = slow->next;
	}
	printf("the media is %d\n", slow->data);
}

void find_one_reverse(int seq){
	Node * first = List;
	Node * second = List;
	int first_steps = seq;

	//first先走seq个节点
	while(first != NULL && first_steps>0){
		first = first->next;
		first_steps--;
	}

	//说明链表长度小于seq,所以不存在倒数第seq的节点
	if(first_steps > 0){
		printf("the %d node does not exist\n", seq);
		return;
	}

	while(first != NULL){
		first = first->next;
		second = second->next;
	}
	printf("the %d node is %d\n", seq, second->data);
}

//生成链表
void make_list(){
	List = (Node *)malloc(sizeof(Node) * LIST_LEN);
	int i = 0;
	for(i = 0; i < (LIST_LEN - 1); i++){
		(List + i)->data = i + 1;
		(List + i)->next = List + i + 1;
	}
	(List + LIST_LEN - 1)->data = LIST_LEN;
	(List + LIST_LEN - 1)->next = NULL;
}

void print_list(){
	Node * cur = List;
	while(cur!=NULL){
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

int main(){
	make_list();
	print_list();
	find_median_ite();//找到中间节点
	find_one_reverse(4);//找到倒数第4个节点
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值