任务描述
一个线性表(a1,a2,…,an)(n>3)采用带头结点的单链表L存储。设计一个高效算法
求中间位置的元素(即序号为n/2的元素)。
相关知识
这个问题也是利用了链表的长度无法直接获取的不足做文章,解决办法如下:
一个暴力的办法是,先通过一次遍历去计算链表的长度,这样我们就知道了链表中间位置是第几个。接着再通过一次遍历去查找这个位置的数值。
除此之外,还有一个巧妙的办法,就是利用快慢指针进行处理。其中快指针每次循环向后跳转两次,而慢指针每次向后跳转一次。
解题思路
让 p、q 首先指向首结点,然后在 p 结点后面存在两个结点时循环:p 后移两个结点,q 后移一个结点。当循环结束后,q 指向的就是中间位置的结点。
相关知识
单链表结点类型定义如下:
typedef struct LNode // 结点类型定义
{
ElemType data; //数据域
struct LNode *next; //指针域
}LinkNode;
为了令算法具有通用性,使其尽可能地适用于各种可能的场合,将要处理的数据类型加以抽象,使其适用于不同类型的数据,是提高代码通用性的重要手段。
单链表中数据类型ElemType
可以多种多样,但是在编程实现算法时针对不同数据类型,每类数据元素的输入输出是有区别的,单链表的基本操作算法要在计算机上执行,须针对ElemType
类型数据编写输入、输出、比较等函数。
编程要求
根据提示,在右侧编辑器 Begin-End 区间补充代码,完成单链表求中值的操作,具体要求如下:
- `ElemType Midnode(LinkNode *L); //设计一个高效算法求中间位置的元素
测试说明
平台会对你编写的代码进行测试:
测试一:
测试二:
程序代码
linklist.cpp
#include "linklist.h" //声明单链表结点类型
void CreateListF(LinkNode *&L,ElemType a[],int n)
//头插法建立单链表
{
LinkNode *s;
L=(LinkNode *)malloc(sizeof(LinkNode)); //创建头结点
L->next=NULL;
for (int i=0;i<n;i++)
{
s=(LinkNode *)malloc(sizeof(LinkNode));//创建新结点s
s->data=a[i];
s->next=L->next; //将结点s插在原开始结点之前,头结点之后
L->next=s;
}
}
void CreateListR(LinkNode *&L,ElemType a[],int n)
//尾插法建立单链表
{
LinkNode *s,*r;
L=(LinkNode *)malloc(sizeof(LinkNode)); //创建头结点
L->next=NULL;
r=L; //r始终指向终端结点,开始时指向头结点
for (int i=0;i<n;i++)
{
s=(LinkNode *)malloc(sizeof(LinkNode));//创建新结点s
s->data=a[i];
r->next=s; //将结点s插入结点r之后
r=s;
}
r->next=NULL; //终端结点next域置为NULL
}
void InitList(LinkNode *&L)
{
L=(LinkNode *)malloc(sizeof(LinkNode)); //创建头结点
L->next=NULL;
}
void DestroyList(LinkNode *&L)
{
LinkNode *pre=L,*p=pre->next;
while (p!=NULL)
{ free(pre);
pre=p;
p=pre->next;
}
free(pre); //此时p为NULL,pre指向尾结点,释放它
}
bool ListEmpty(LinkNode *L)
{
return(L->next==NULL);
}
void DispList(LinkNode *L)
{
LinkNode *p=L->next;
while (p!=NULL)
{ printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
bool ListInsert(LinkNode *&L,int i,ElemType e)
{
int j=0;
LinkNode *p=L,*s;
if (i<=0) return false; //i错误返回假
while (j<i-1 && p!=NULL) //查找第i-1个结点p
{ j++;
p=p->next;
}
if (p==NULL) //未找到位序为i-1的结点
return false;
else //找到位序为i-1的结点*p
{ s=(LinkNode *)malloc(sizeof(LinkNode));//创建新结点*s
s->data=e;
s->next=p->next; //将s结点插入到结点p之后
p->next=s;
return true;
}
}
ElemType Midnode(LinkNode *L)
{
/********** Begin **********/
LinkNode *p=L->next,*q=p;
while (p->next!=NULL && p->next->next!=NULL)
{
p=p->next->next;
q=q->next;
}
return q->data;
/********** End **********/
}
linklist.h
#ifndef LINKLIST_H_INCLUDED
#define LINKLIST_H_INCLUDED
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#include <malloc.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next; //指向后继结点
} LinkNode;
void InitList(LinkNode *&L);
void DispList(LinkNode *L);
bool ListInsert(LinkNode *&L,int i,ElemType e);
void CreateListR(LinkNode *&L,ElemType a[],int n);
ElemType Midnode(LinkNode *L);
#endif // LINKLIST_H_INCLUDED
main.cpp
#include "linklist.h"
#define N 5
int main()
{
LinkNode *L;
int i,a[N];
printf("请输入5个用于创建的链表的整数:\n");
for (i=0;i<N;i++)
{
scanf("%d",&a[i]);
}
/********** Begin **********/
printf("L:");
for (i=0;i<N;i++)
{
printf("%d ",a[i]);
}
printf("\n");
//void InitList(LinkNode *&L);
//void DispList(LinkNode *L);
//bool ListInsert(LinkNode *&L,int i,ElemType e);
//void CreateListR(LinkNode *&L,ElemType a[],int n);
//ElemType Midnode(LinkNode *L);
InitList(L);
for (i=0;i<N;i++)
{
ListInsert(L,i,a[i]);
}
printf("中位数为:%d",Midnode(L));