【DS专题活动】第三期解答及第四期(10月20日~10月26日)题目

frankzch 2003-10-20 04:40:05
先说本期的题目:
1、在无头结点单链表上实现线性表基本操作
int Insert(LinkList L,int i,ElemType b)和Delete(LinkList L,int i)

2、已知线性表中元素以值递增有序排列,并以单链表做存储结构。写一算法,删除表中所有值大于mink且小于maxk的元素(若表中存在这样的元素),同时释放被删结点空间,并分析你的算法的时间复杂度。

3、同上题条件,删除表中所有值相同的多余元素,使删除后的表中元素各不相同,同时释放被删结点空间,并分析你算法的时间复杂度(这一点不能忘记,只有学会分析自己的复杂度,才能有助于你写出高效率的程序)

*********************************************
上期题目比较少难度也不大,相信是新手练级的绝佳机会,只要这些题目熟练了,就会为以后的学习打下一个牢固的基础
答案明天给出,没有做的今天可以思考一下
...全文
146 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
StepBy 2003-10-25
  • 打赏
  • 举报
回复
up 一下
frankzch 2003-10-23
  • 打赏
  • 举报
回复
1
xiaoyige886 2003-10-23
  • 打赏
  • 举报
回复
up
tuxw 2003-10-22
  • 打赏
  • 举报
回复
请问题目中的在第i个位置插入或删除,这个i是从0还是从1计记呀
frankzch 2003-10-22
  • 打赏
  • 举报
回复
是不是大家觉得没有难度所有不做?我的组竟然没有一个人给我发来答案的,难道就把我写的贴出来?郁闷,就贴我的吧
注意:EQ(),LT()等是比较函数,由于elemtype类型不一定是数字或字符,所以用EQ(),LT()比较适应面更广些,至于具体实现则根据具体数据类型确定,我们不必深究

第一题:
LNode* Locate(LinkList L,ElemType e)
{//在带头结点的单链表结构上实现线性表元素的定位
LNode *p=L;
while(p&&!EQ(p->data,e))p=p->next;
return(p);
}//Locate

int Lengh(LinkList L)
{//在带头结点的单链表结构上实现求线性表元素的长度
int i=0;
LNode p=L->next;
for(;p;i++);
return(i);
}//Lengh

第二题:
void List_Concat(LinkList ha,LinkList hb,LinkList &hc)
{//将两个链表ha、hb连接在一起,用指针hc返回连接后的链表的头结点
LinkList pa=ha;
while(pa->next)pa=pa->next;
pa->next=hb->next;
free(hb);
hc=ha;
}//List_ConCat

第三题:
书上都有答案,我就不献丑了;关键是:没有头结点的链表对首元结点要特殊处理
短歌如风 2003-10-21
  • 打赏
  • 举报
回复
带头节点的链表必须有一个头节点,对是否为空的判断是Head->next == NULL。
不带头节点的链表才是Head == NULL。

头节点不需要动态分配时可以在定义变量时初始化:
LNode Head = {0, NULL};
如果是动态分配的,要记得在分配成功后加一句pHead -> next = NULL。
kevin_pan 2003-10-21
  • 打赏
  • 举报
回复
我想可能是我一直都习惯于声明变量的时候都习惯直接声明一个实体,而不是一个指针,对于链表头结点看来还是声明一个指针比较好,然后马上把它副职NULL;初始化的时候分配头结点的内存(好象越走越歪了啊)

这样就可以实现判断了,不知道这个方法好不好,太烦琐了吧,这个是适用于带头接点的链表
对于不需要头接点的就好办多了。

kevin_pan 2003-10-21
  • 打赏
  • 举报
回复
node == NULL? 是判断表头的指针值么,我看上面的人都这么做的,可是,当我声明一个变量的时候他的值不是NULL,如果我们声明后马上对它开始操作(非初始化),不也是很严重的错误么。
ZhangYv 2003-10-21
  • 打赏
  • 举报
回复
直接用if (node == NULL)判断可以吧?
kevin_pan 2003-10-21
  • 打赏
  • 举报
回复
请问大家,如何区分一个链式存储结构的表——“空集”和“非法表”

typedef struct LNode{
ElemType data;
LNode* next;
}*Link,LNode;

typedef struct{
Link head,tail;
int length;
}LinkList;

我理解的初始化表的操作一定要分配内存,这样会带来非常多的麻烦,可是从另一个角度来说链表的特点就是应该根据元素来动态分配内存,这样想,初始化的时候又不应该分配内存,而只是把表头的相应元素初始化为NULL,NULL,0。但是这样一来,问题又出现了,如何区分空表和非法表呢,总不能不允许对空表进行操作吧。

这个问题一直捆饶我很久了,一直不敢提出来,怕被笑话:),在树或者别的链式存储结构的时候都会遇到这个问题,请大家帮助我理解一下。
短歌如风 2003-10-21
  • 打赏
  • 举报
回复
“指向指针的指针”可能不太好理解,我再给出一个一般的实现:

int LinkList_Move(LinkList *la, LinkList *lb, int i, int j,int len)
{
LinkList First, Last, InsertPos, Temp;
LinkList PreFirst = NULL, PreLast = NULL, PreInsert = NULL;
int n;
assert(i > 0 && j > 0 && len > 0);
assert(la != NULL && lb != NULL);

//找到要删除的第一个节点
First = *la;
while (i > 1 && First != NULL)
{
--i;
PreFirst = First;
First = First -> next;
}

//找到要删除的最后一个节点的下一个节点
Last = First;
n = len;
while (n > 0 && Last != NULL)
{
--n;
PreLast = Last;
Last = Last -> next;
}

//寻找插入点
InsertPos = *lb;
while(j > 1 && InsertPos != NULL)
{
--j;
PreInsert = InsertPos;
InsertPos = InsertPos -> next);
}

//把[First, Last)从A链断开并加入到B链。
if (PreLast != NULL)//序列非空。这个判断把寻找插入点的循环包括进来也可以,不过这样清晰一些。
{
if (PreFirst == NULL)
*la = Last;
else
PreFirst -> next = Last;

PreLast -> next = InsertPos;
if (PreInsert == NULL)
*lb = First;
else
PreInsert -> next = First;
}
return len - n;
}
frankzch 2003-10-21
  • 打赏
  • 举报
回复
好,每组做好之后自己贴上来
下面是plainsong组的解答:
这一期的解答发现普遍对头节点的问题理解不够,在处理有头链表的Locate、Length时都把头节点也参与比较/计数,在连接时错误地把第二个链表的头节点也连接进来。而在处理无头链表的插入和删除时没有考虑到对首节点的处理。
第一、二题,完成者xiaoyige886(修改过)
int Length(LinkList L) //函数返回 k 值为链表长度
{
assert(L != NULL)
LinkList p = L -> next;
int k = 0;
while(p)
{
p = p-> next;
k++;
}
return k;
}

LinkList Locate(LinkList L, ElemType X)// 查找元素x
{
assert(L != NULL)
LinkList p = L -> Next;
while(p && p-> data != X)
p = p-> next;
return p; //若找到返回该指针,若找不到返回 NULL
}

/*把hb连接到ha后,形成链表hc,不过形成的hc 好象已经没有意义了,
因为ha在次之后已经和hc完全一样了 */
LinkList Union(LinkList ha, LinkList hb, LinkList hc)
{
assert(ha != NULL && hb != NULL)
hc = ha;
LinkList p = ha;
while(p-> next)//判断末尾指针是否为NULL
p = p-> next;
p-> next = hb -> next;

return hc ;

}
第三题的完成都不理想,我给出我的实现:
/******************************************************************
函数:LineList_Move
功能:把链表la的第i个元素开始的len个元素插入到链表lb的第j个元素之前
并从la中删除。
参数:
la:链表指针(指向节点指针的指针),无头节点的链表;不可为NULL。
lb:链表指针,无头节点的链表,不要为NULL
i:移动序列的首元素在la中的索引,1-Based
j:在lb中的插入点索引,1-Based
len:移动的元素个数。
返回值:移动的元素个数
其它:
当i=1时会改变la中的值;
当j=1时会改变lb中的值。
如la元素数不足i + len,则移动从第i个元素开始的所有元素。
如la元素数不足i则不发生移动。
如lb元素数不足j,则添加到末尾。

由于使用的是无头节点的链表,一般情况下在插入和删除时需要对第一个元素进行特殊处理,
为了避免这一特殊处理,使用了“指向指针的指针”进行操作。
******************************************************************/
int LinkList_Move(LinkList *la, LinkList *lb, int i, int j,int len)
{
LinkList * First, * Last, * InsertPos, Temp;
int n;
assert(i > 0 && j > 0 && len > 0);
assert(la != NULL && lb != NULL);

//找到要删除的第一个节点
First = la;
while (i > 1 && *First != NULL)
{
--i;
First = &((*First) -> next);
}

//找到要删除的最后一个节点的下一个节点
Last = First;
n = len;
while (n > 0 && *Last != NULL)
{
--n;
Last = &((*Last) -> next);
}

//寻找插入点
InsertPos = lb;
while(j > 1 && *InsertPos != NULL)
{
--j;
InsertPos = &((*InsertPos) -> next);
}

//把[First, Last)从A链断开并加入到B链。
if (Last != First)//序列非空。这个判断把寻找插入点的循环包括进来也可以,不过这样清晰一些。
{
Temp = *Last;
*Last = *InsertPos;
*InsertPos = *First;
*First = Temp;
}
return len - n;
}
短歌如风 2003-10-21
  • 打赏
  • 举报
回复
B组的答案我发给frankzch了,是在E-Mail中直接写的,自己没留备份,只有麻烦frankzch贴上来了。

是不是以后都要把每一组的答案都贴出来?如果这样,以后我就不用发给frankzch了。
ZhangYv 2003-10-20
  • 打赏
  • 举报
回复
plainsong(短歌) 说得对,确实有错误。但是目前我组才上交这一份,我自己还没有写就先贴上来了。明天我会写自己一份完整的。
短歌如风 2003-10-20
  • 打赏
  • 举报
回复
关于ZhangYv组的答案,我觉得:
1:Locate中的L是头节点,它的data不应参与比较。
2:MergeList中的hb也是头节点,hb->next才是第一个元素的节点,应该连接进来的是它。
3:DeleInse中虽然说不进行错误检测,但我觉得i或j为1不应该认为是错误,而这时是不存在第i-1和第j-1个节点的(两个链表都是无头节点的),应该作特殊处理。
frankzch 2003-10-20
  • 打赏
  • 举报
回复
请大家写程序的时候使用我们给出的类的标准定义:
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef struct {//顺序表
ElemType *elem;
int length;
int listsize;
} SqList;


typedef struct LNode {//链表
ElemType data;
struct LNode *next;
} LNode,*LinkList;

ZhangYv:刚才我突然发现我的题目出错了,赶紧把它删了,你的回复也被我删了,不好意思!
现在我重新发了一遍!
frankzch 2003-10-20
  • 打赏
  • 举报
回复
ZhangYv组的解答:
给一份偶组里的程序,我自己还没有写 :<
#define ElemType int
#define Status int
#define NULL 0
#define FALSE 0
#define TRUE 1

typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;


/*第一题:在带头结点的单链表结构上实现线性表的基本操作LOCATE(L,X)和LENGTH(L).
(L为线性表,X为表内元素) */

LinkList LOCATE(LinkList L,ElemType X)
{
LinkList p;
if(L==NULL) return FALSE;
else
for(p=L; p->data != X; p=p->next)
if(!p) return FALSE;
return p;
}

int LENGTH(LinkList L)
{
int length;
for(length=0; L->next; length++)
L=L->next;
return length;
}


/*第二题:已知指针ha和hb分别指向两个单链表的头结点,并且已知两个链表的长度分别
为m和n。写一算法将两个链表连接在一起,用指针hc返回连接后的链表的头结点 */

void MergeList(LinkList ha,LinkList hb,LinkList hc)
{
hc=ha;
while(ha->next)
ha=ha->next;
ha->next=hb; //将b接在a后面
}


/*第三题:已知指针la和lb分别指向两个无头结点单链表中的首元结点。编写算法从表la
中删除自第i个元素起共len个元素后,将他们插入到表lb中第j个元素之前(la、lb、i、j、
len均由函数参数表传入) */

void DeleInse(LinkList la,LinkList lb,int i,int j,int len)
{
/*la中删除len个元素后,第i-1个元素指向i+len个元素;而lb中第j-1个元素指向la中
的原第i个元素,原la第i+len个元素指向lb第j个元素,本程序不检验参数的合法性 */

int ta; //循环记数
LinkList lai,laj,lbj1,lbj2; //标记断点位置
for(ta=1,lai=la,lai=la;lai->next!=NULL && ta<i;ta++)
lai=lai->next; //使lai指向la的第i-1个元素,若i=1则等于la
for(laj=lai;lai->next!=NULL && ta<i+len;ta++)
laj=laj->next; //继续上面循环,使laj指向la的第i+len-1个元素
for(ta=1,lbj1=lb;lbj1->next!=NULL && ta<j;ta++)
lbj1=lbj1->next; //使lbj1指向lb的第j-1个元素
lbj2=lbj1->next; //使lbj2指向lb的第j 个元素

lbj1->next=lai->next; //lb中第j-1个元素指向la中的原第i个元素
lai->next=laj->next; //la中第i-1个元素指向i+len个元素
laj->next=lbj2; //原la第i+len个元素指向lb第j个元素
}

33,006

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧