题目:快速找到未知长度单链表的中间结点。
既然是面试题就一定有普通方法和高级方法,而高级方法无疑会让面试官大大加分!
普通的方法很简单,首先遍历一遍单链表以确定单链表的长度L。然后再次从头结点出发循环L/2次找到单链表的中间结点。
算法复杂度为:O(L+L/2)=O(3L/2)。
能否再优化呢?有一个很巧的方法:利用快慢指针!
利用快慢指针原理:设置两个指针*search、 *mid 都指向单链表的头结点。其中 *search 的移动速度是 *mid 的2倍。当 *search 指向末尾结点的时候,*mid 正好就在中间了。
实现代码:
GetMidNode.c
int GetMidNode( LinkList L ,ElemType *e )
{
LinkList search,mid;
mid = search = L;
while( search->next != NULL )
{
if( search->next->next != NULL )
{
search = search->next-next;
mid = mid->next;
}
else
{
search = search->next;
}
}
*e = mid->data;
return 1;
}
接下来就写一个完整的代码:实现随机生成20个元素的链表(尾插法或者头插法任意),用我们刚才学到的方法快速查找中间结点的值并且显示。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define OK 1;
typedef struct _Node
{
int data; // 数据域
struct _Node *Next; // 指针域,指针指向的是下一个结点
}Node;
Node* create_list_head( int num )
{
Node *head;
Node *p;
int i;
srand( time(0) ); // 初始化随机数种子
head = (Node *)malloc( sizeof(Node) );
head->Next = NULL;
for( i=0; i<num; i++ )
{
p = (Node *)malloc( sizeof(Node) ); // 新结点
p->data = rand()%100+1;
p->Next = head->Next;
head->Next = p;
}
return head;
}
int get_mid_node( Node *head, int *e )
{
Node *search;
Node *mid;
mid = search = head;
while( search->Next != NULL )
{
if( search->Next->Next != NULL )
{
search = search->Next->Next;
mid = mid->Next;
}
else
{
search = search->Next;
}
}
*e = mid->data;
return OK;
}
int main()
{
Node *L ;
Node *p ;
int *num;
int a;
num = NULL;
L = create_list_head(20);
p = (Node *)malloc( sizeof(Node) ); // 新结点
p = L->Next;
while( p != NULL)
{
printf("%d\n",p->data);
p = p->Next;
}
get_mid_node( L, &a );
printf("The mid data is %d\n", a);
return 0;
}
写代码遇到的问题:
-
结点的问题
我在定义结点结构体的时候,犯了很大的错误,我把Next定成了Node *类型,这样是不行的,我Node是在结构体外面定义的,在结构体里面不能用。所以只能用一开始结构体的名字定义它的类型,应该定义为struct _Node *Next;
-
类型匹配的问题
比如我定义的a是int类型的,而在get_mid_node( Node *head, int *e )
函数里面,e的类型是int * 类型的,所以要类型一致,a是一个值,而指针指向的是地址,所以要写成&a当做形参。最后调用的时候写成get_mid_node( L, &a )