インタビューの質問: 長さが不明な単一リンクリストの中間ノードを素早く見つけるにはどうすればよいですか?
バックグラウンド
私は偶然、インタビューの質問に遭遇しました。「長さが不明な単一リンクリストの中間ノードを素早く見つけるにはどうすればよいですか?」
方法
最初に思いついたのは非常に単純なトラバース方法で、その後、高速ポインタと低速ポインタの方法を学びました。
一般的な方法
原理
一般的な方法は非常に簡単で、まず単一リンク リストを走査して、単一リンク リストの長さを決定します。次に、ヘッド ノードから開始して再度 N/2 回ループし、単一リンク リストの中間ノードを見つけます。
アルゴリズムの複雑さは O(N+N/2)=O(3N/2) です。
コード
void common_found_List(Linklist *L,int len)
{
Linklist *mid;
int i = 0;
Elemtype e;
mid = L;
len = len/2;
while(i<=len)
{
mid = mid->next;
i++;
}
e = mid->data;
printf("The middle data of the list is :%d\n",e);
}
高度な方法
共通検索方法の最適化→★★★ポインタの速度と速度の遅さ★★★
原理
2 つのポインターp とMid を、単一リンク リストのヘッド ノードを指すように設定します。このうちpの移動速度はmidの2倍です。*p が終了ノードを指す場合、*mid も中間ノードを指します。
アルゴリズムの複雑さは O(N/2) です。
コード
void fast_slow_List(Linklist *L)
{
Linklist *f,*mid;
Elemtype e;
f = L;
mid = L;
while(f->next)
{
if(f->next->next)
{
f = f->next->next;
mid = mid->next;
}
else
{
f = f->next;
}
}
e = mid->next->data;
printf("The middle data of the list is :%d\n",e);
}
実験の過程と結果
合計コード
//<库函数>
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
//<相关参数的宏定义>
#define Len sizeof(Node)
#define N 20
typedef int Elemtype;
typedef struct Node
{
Elemtype data;
struct Node* next;
}Node;
typedef struct Node Linklist;
//功能函数
Linklist* Creat_L();
void Out_Linklist(Linklist *h);
void fast_slow_List(Linklist *L);
void common_found_List(Linklist *L,int len);
int Length_list(Linklist *L);
void main()
{
Linklist *L;
int k ;
int i ;
int len;
Elemtype x;
printf(" 《 Welcome to use the founction 》\n");
printf(" The founction can offer following service\n");
printf(" *******Please first Initlist*******\n\n");
printf(" 1、Initlist ->创建单链表\n");
printf(" 2、Insertlist ->输出链表长度操作\n");
printf(" 3、common_Foundlist ->普通方法查找中间元素操作\n");
printf(" 4、fast_Foundlist ->高级方法查找中间元素操作\n");
printf(" 0、Exitlist ->退出操作\n\n\n");
printf(" Please choose following digital:1、2、3、0\n");
printf(" Finish your idea!!!!!!\n");
do
{
printf("\n\nPlease Input your choice:");
scanf("%d",&k);
switch(k)
{
case 1:
{
L = Creat_L();
Out_Linklist(L);
}break;
case 2:
{
len = Length_list(L);
printf("The length of the list is:%d\n",len);
}break;
case 3:
{
len = Length_list(L);
common_found_List(L,len);
}break;
case 4:
{
fast_slow_List(L);
Out_Linklist(L);
}break;
}
}while(k!=0);
}
// <随机创建单链表>
Linklist* Creat_L()
{
int count = 0;
Linklist *h,*p,*s;
Elemtype x;
h = (Node*)malloc(Len);
h->next = NULL;
p = h;
//printf("Please Enter the FIRST Node data: ");
//scanf("%d",&x);
while(count < N) //假设终止条件
{
x = rand() % 50; //随机生成各节点,创建单链表
s = (Node*)malloc(Len);
s->data = x; //赋值
s->next = NULL;
p->next = s;
p = s;
//printf("Please Enter the NEXT Node data: ");
//scanf("%d",&x);
count++;
}
return h;
}
//<输出函数>
void Out_Linklist(Linklist *h)
{
Linklist *p;
p = h->next;
printf("Output Linklist:\n");
while(p)
{
if(p->next!=NULL)
{
printf("%d -> ",p->data);
p = p->next;
}
else
{
printf("%d",p->data);
p = p->next;
}
}
}
// <快慢指针查找函数:使用快慢指针查找中间值的操作,时间复杂度为O(N/2)>
void fast_slow_List(Linklist *L)
{
Linklist *f,*mid;
Elemtype e;
f = L;
mid = L;
while(f->next)
{
if(f->next->next)
{
f = f->next->next;
mid = mid->next;
}
else
{
f = f->next;
}
}
e = mid->next->data;
printf("The middle data of the list is :%d\n",e);
}
//<长度函数>
int Length_list(Linklist *L)
{
int count = 0;
Linklist *p;
p = L;
while(p->next)
{
p = p->next;
count++;
}
//printf("The length of the list is:%d\n",count);
return count;
}
// <普通方法函数>
void common_found_List(Linklist *L,int len)
{
Linklist *mid;
int i = 0;
Elemtype e;
mid = L;
len = len/2;
while(i<=len)
{
mid = mid->next;
i++;
}
e = mid->data;
printf("The middle data of the list is :%d\n",e);
}
演算結果
要約する
高速ポインタ アルゴリズムと低速ポインタ アルゴリズムを使用して単一リンク リストの中間ノードを見つけると、一般的なアルゴリズムよりも約 3 倍高速になります。もちろん、この例では速度差はありませんが、要素が多い場合には、より顕著に差が生じます。
さらに高度な方法で面接時に加点!!!!!!