问题:有单链表LinkNode,请写一算法返回该链表的倒数第n个节点.
由于是单向链表,倒数往回数的可能性好像不大.于是诞生以下三种思路,借以参考。
假设单链表的头指针为root,链表定义的两个域(data,next),为简化讨论,假设n小于单链表的节点数。
思路1:要做到从尾往回数,就必须让单链表逆向。这可谓是最愚蠢的想法,因为把单链表逆向之后,很快能够得到第n个,但是好像返回结果后,我们必须恢复现场,这样算来最坏的情况下有O(3n)的时间复杂度.完成这个思路的代码大致像:
//第1步.逆向单链表
LinkNode *newRoot=NULL;
LinkNode *temp=root;
while(root != NULL){
temp = root->next;
root->next = newRoot;
newRoot = root;;
root = temp;
}
root = newRoot;
//第2步:顺序查找第n个元素
temp = root;
while((temp=temp->next) && n-->0);
if(n==0) return temp;
//第3步:如果需要恢复,执行第1步中的代码
思路2:不管是顺数n个还是倒数n个,其实都是距离-标尺问题。
标尺是一段距离可以用线段的两个端点来衡量,我们能够判断倒数第一个节点,因为他的next==NULL。
如果我们用两个指针,并保持他们的距离为n,那么当这个线段的右端指向末尾节点时,左端节点就指向倒数第n个节点。
真是进了一大步,这个思路的算法时间复杂度为O(n).代码大致像这样:
//第1步:建立标尺
LinkNode *pLeft,*pRight;
pLeft=pRight=root;
while(n-->0) pRight=pRight->next;
//第2步:让标尺向右移动,直到右端指向末尾.左端即结果
while(pRight->next != NULL){
pLeft = pLeft->next;
pRight = pRight->next;
}
return pLeft;
思路3:偷懒最省事的办法!让单链表有一个头节点,并在头节点中保存该单向列表的节点数目。
这个思路的时间复杂度最小,只跟参数n有关系.代码大致为:
//第1步:计算顺数的位置
int reN = count-n;
//第2步:向右移动reN的节点即是.
LinkNode * temp=root;
while(reN-->0) temp = temp->next;