最近在學回顧之前學到的知識,正好碰到了關於鏈表查找的一道面試題,在此貼出來,與小伙伴們共同交流~
在剛看到題目,其實很容易就想到一個方法,就是先求鏈表的長度(length),然后去超找第length-k+1個節點的值,再進行查找,先貼代碼如下。
#include <stdio.h> #include <malloc.h> /*鏈表節點結構*/ typedef struct node{ int data; struct node * pNext; }NODE,*PNODE; /*函數聲明*/ PNODE create_list(); void show_list(PNODE p); void show_list_list(PNODE p); int serch_k(PNODE p,int k); /*主函數*/ int main(){ int k; int len; PNODE pHead=NULL; pHead=create_list(); show_list(pHead); len=show_list_length(pHead); printf("\n%d",len); k=serch_k(pHead,2);//查找倒數第K個值 printf("\n%d",k); return 0; } /*生產鏈表*/ PNODE create_list(void){ int len; int val; int i; scanf("%d\n",&len); PNODE pHead=(PNODE)malloc(sizeof(NODE)); if(pHead==NULL){ printf("error"); } PNODE pTail=pHead; pTail->pNext=NULL; for(i=0;i<len;i++){ scanf("%d",&val); PNODE pNew=(PNODE)malloc(sizeof(NODE)); if(pNew==NULL){ printf("error"); } pNew->data=val; pTail->pNext=pNew; pNew->pNext=NULL; pTail=pNew; } return pHead; } /*顯示鏈表*/ void show_list(PNODE p){ PNODE p1=p->pNext; if(p1==NULL){ printf("error"); } while(p1){ printf("%d",p1->data); p1=p1->pNext; } } /*顯示鏈表長度*/ int show_list_length(PNODE p){ int count=0; PNODE p1=p->pNext; if(p1==NULL){ printf("error"); } while(p1){ count++; p1=p1->pNext; } return count; } /*查找第k個節點的值*/ int serch_k(PNODE p,int k){ int i=0; PNODE p1=p; int len=show_list_length(p); if(k>len){ printf("error"); } /*循環len-k+1次*/ for(i=0;i<len-k+1;i++){ p1=p1->pNext; } return p1->data; }
這個算法需要對鏈表進行兩次遍歷,導致時間復雜度為O(N^2),那有沒有只需要一次遍歷的呢,答案是有的。
首先先看下思路:p1和p2分別都是head指針,先將p2向右移動k次,如圖2所示
圖1
圖2
這時候,只需要繼續保持p1和p2等間距的右移,當p2的next為null,則證明p1所指的結點的值為倒數第k個節點的值
圖3
這就是一次遍歷找出倒數第k個節點的值,其時間復雜度為O(N)
具體代碼如下所示
int serch_k(PNODE p,int k){ int i; PNODE p1 = p; PNODE p2 = p; for (i = 0; i < k; i++) { p2 = p2->pNext; } while (p2 != NULL) { p1 = p1->pNext; p2 = p2->pNext; } return p1->data; }
這是測試結果
圖4
這就是單鏈表找倒數第k個結點的值的兩種方法。