2.3.7-1 设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点
#include
#include
//设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表:不带头结点
LinkList list_tail_insert(LinkList &L){
L=NULL;
LNode *s,*r;
ElemType x;
printf("input x:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
if(L==NULL){
L=s;
r=L;
}else{
r->next=s;
r=s;
}
scanf("%d",&x);
}
r->next=NULL;
}
//删除单链表删除值x
void delete_list_x(LinkList &L,ElemType x){
LNode *p;//p指向待删除结点
if(L==NULL){ //递归推出条件
return;
}
if(x==L->data){
p=L;
L=L->next;
free(p);
delete_list_x(L,x);
}else{
delete_list_x(L->next,x); //并未改变指针L的值
}
}
//链表打印函数:不带头结点
void print_list(LinkList L){
while(L){
printf("%3d",L->data);
L=L->next;
}
}
int main() {
LinkList L;
list_tail_insert(L);
printf("the old list is:\n");
print_list(L);
delete_list_x(L,2);
printf("\nthe new list is:\n");
print_list(L);
return 0;
}
输出结果:
input x:
2 2 1 3 2 5 9999
the old list is:
2 2 1 3 2 5
the new list is:
1 3 5
进程已结束,退出代码为 0
2.3.7-2 在带头结点的单链表L中,删除所有值为x的结点,并释放其空间。
#include
#include
// 在带头结点的单链表L中,删除所有值为x的结点,并释放其空间。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表:带头结点
void list_tail_insert(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
LNode *s,*r=L;
ElemType x;
printf("input x:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
}
//删除元素x
//算法思想1:设置遍历指针p,以及遍历指针的前驱指针pre,从头遍历链表;如p->data==x,则删除该结点;否则,继续遍历
void delete_list_x1(LinkList L,ElemType x){ //不会修改指针L的值,所以不用加引用
LNode *pre=L,*p=L->next;//p为遍历指针,pre为其前驱指针
LNode *q;//q为指向删除结点的临时指针
while(p){
if(p->data==x){
q=p;
p=p->next;
pre->next=p;
free(q);
}else{
p=p->next;
pre=pre->next;
}
}
}
//采用尾插法的思想,设置遍历指针p,尾指针r,依次遍历单链表;当节点值不是x时,则用尾插法插入链尾;当结点值为x时,则删除该结点;
void delete_list_x2(LinkList L,ElemType x){
LNode *r=L,*p=L->next;//r为链表尾指针,p为遍历指针
LNode *q;//临时指针,指向待删除结点
while(p){
if(p->data!=x){
r=p;
p=p->next;
}else{
q=p;
p=p->next;
r->next=p;
free(q);
}
}
}
//打印链表:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
}
int main() {
LinkList L;
list_tail_insert(L);
printf("the original list is :\n");
print_list(L);
delete_list_x1(L,2);
printf("\nthe modified list is:\n");
print_list(L);
delete_list_x2(L,3);
printf("\nthe modified list is:\n");
print_list(L);
return 0;
}
输出结果:
input x:
1 2 2 3 4 3 5 6 8 3 2 9999
the original list is :
1 2 2 3 4 3 5 6 8 3 2
the modified list is:
1 3 4 3 5 6 8 3
the modified list is:
1 4 5 6 8
进程已结束,退出代码为 0
2.3.7-3 设L为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值。
#include
#include
//设L为带头结点的单链表,编写算法实现从头到尾反向输出每个结点的值
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立带头结点的单链表
void list_tail_insert(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
L->next=NULL;
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
}
//逆序输出链表
//算法思想:借助栈的思想,采用递归函数实现.
void print_reverse_list(LinkList L){
if(L->next){
print_reverse_list(L->next);//如后继元素不为NULL,则先递归输出其后继元素
}
if(L!=NULL){
printf("%3d",L->data);//当后继元素输出完毕后,输出该元素;对于头结点,由于L!=NULL,但没有data值,则会输出一个随机值
}
}
//忽略头结点,逆序输出链表
void print_reverse_list_ignorehead(LinkList L){
if(L->next){
print_reverse_list(L->next); //忽略头结点,从第一个结点开始输出
}
}
//打印函数
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
}
int main() {
LinkList L;
list_tail_insert(L);
printf("the original list is:\n ");
print_list(L);
printf("\nthe reverse list is:\n");
print_reverse_list_ignorehead(L);
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 9999
the original list is:
1 2 3
the reverse list is:
3 2 1
进程已结束,退出代码为 0
2.3.7-4 试编写在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值结点唯一)
#include
#include
//试编写在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值结点唯一)
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//建立单链表
LinkList list_tail_insert(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//删除最小值
//算法思想:单链表删除元素,需要知道最小元素的前驱结点。故设置遍历结点p,其前驱结点pre,以及最小结点minp,及其前驱结点minpre;
// 如结点值小于最小结点值,则记录最小结点及其前驱;否则,则继续向前遍历
LinkList delete_list_min(LinkList L){
LNode *pre=L,*p=L->next;
LNode *minpre=pre,*minp=p;
while(p){ //查找最小结点及其前驱结点
if(p->datadata){
minp=p; //记录最小结点
minpre=pre;
}else{
p=p->next; //继续遍历
pre=pre->next;
}
}
minpre->next=minp->next;
free(minp);
return L;
}
//打印链表
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L;
L= list_tail_insert(L);
printf("the original list is:\n");
print_list(L);
L= delete_list_min(L);
printf("the list that deletes the min element is:\n ");
print_list(L);
return 0;
}
输出结果:
input x,ended with 9999:
2 3 1 5 9999
the original list is:
2 3 1 5
the list that deletes the min element is:
2 3 5
进程已结束,退出代码为 0
2.7.3-5 试编写算法将带头结点的单链表就地逆置
#include
#include
//试编写算法将带头结点的单链表就地逆置
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//原地逆置链表
//算法思想1:采用链表头插法的思想将链表原地逆置,将头结点从原链表摘下,然后用头插法将后续结点依次插入
LinkList reverse_list1(LinkList L){
LNode *p=L->next,*q; //p为链表遍历指针,q为临时指针
L->next=NULL;
while(p){
q=p;
p=p->next;
q->next=L->next;
L->next=q;
}
return L;
}
//算法思想2:设置三个指针,用p指向结点p,用pre指向p结点的前驱结点,用r指向p结点的后继节点;每次将p结点连接到其前驱结点pre的前面,最后将L指向p
LinkList reverse_list2(LinkList L){
LNode *pre,*p=L->next,*r=p->next;
p->next=NULL; //将第一个结点摘下,作为第一个前驱结点
while(r){
pre=p;
p=r;
r=r->next;
p->next=pre;
}
L->next=p; //将头指针指向p
return L;
}
//打印链表:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L;
L= list_tail_insert(L);
printf("the original list is:\n ");
print_list(L);
// L=reverse_list1(L);
L=reverse_list2(L);
printf("the reversed list is :\n");
print_list(L);
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 4 5 9999
the original list is:
1 2 3 4 5
the reversed list is :
5 4 3 2 1
进程已结束,退出代码为 0
2.3.7-6 有一个带头结点的单链表L,设计一个算法使其递增有序
#include
#include
//有一个带头结点的单链表L,设计一个算法使其递增有序
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//链表排序
//算法思想:从第一个结点后断链,然后将后续结点依次摘下,插入前面的链表中。时间复杂度为o(n2)
void sort_list(LinkList L){
LNode *pre,*p=L->next,*r=p->next; //pre为插入的前驱结点,p为待插入结点,r为后继节点
p->next=NULL;
p=r;
while(p){
r=p->next;
pre=L;//如初始化pre=L->next,则会产生循环到最后pre==NULL的情况,即遍历至链尾,此时p->next=pre->next会报错
while(pre->next!=NULL&&pre->next->datadata){
pre=pre->next;
}
p->next=pre->next;
pre->next=p;
p=r;
}
}
//打印链表:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L;
L= list_tail_insert(L);
printf("the original list is:\n");
print_list(L);
sort_list(L);
printf("the sorted list is:\n");
print_list(L);
return 0;
}
输出结果:
input x,ended with 9999:
3 2 1 5 4 9999
the original list is:
3 2 1 5 4
the sorted list is:
1 2 3 4 5
进程已结束,退出代码为 0
2.3.7-7 设在一个带表头结点的单链表中,所有结点的数值无序。试编写一个函数,删除表中所有介于给定的两个值之间的元素。
#include
#include
//设在一个带表头结点的单链表中,所有结点的数值无序。试编写一个函数,删除表中所有介于给定的两个值之间的元素。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//删除无序链表指定元素间的值
//算法思想:删除指定元素间的值,与删除特定元素值的算法思想相同,需要设置pre,p两个指针,分别指向结点的前驱和结点,依次遍历链表,删除符合条件的结点
void delete_range_list(LinkList L,ElemType min,ElemType max){ //删除[min,max]之间的元素值
LNode *pre=L,*p=pre->next,*q;//p指向遍历结点,pre指向p的前驱结点,q指向待删除结点
while(p){
if(p->data>=min&&p->data<=max){
q=p;
p=p->next;
pre->next=p;
free(q);
}else{
pre=p;
p=p->next;
}
}
}
//打印链表:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L;
L= list_tail_insert(L);
printf("the original list is:\n");
print_list(L);
delete_range_list(L,1,3);
printf("the list deleted between min and max is:\n");
print_list(L);
return 0;
}
输出结果:
input x,ended with 9999:
1 3 2 5 4 9999
the original list is:
1 3 2 5 4
the list deleted between min and max is:
5 4
进程已结束,退出代码为 0
2.3.7.8 给定两个单链表,编写算法找出两个单链表的公共结点
#include
#include
//给定两个单链表,编写算法找出两个单链表的公共结点
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//查找两个链表的公共结点
//两个链表有公共结点,即从某一结点开始,结点的next指针都指向同一结点。即从公共结点开始,两个链表结点的地址相同,即结点指针相同,而并非结点数值相同。
//由于结点next指针的唯一性,两个链表从公共结点开始,为公共部分,不可能再出现分叉。
//算法思想:计算两个链表的公共长度,并用longL指向较长的链表,shortL指向较短的链表;使较长的链表先移动|len1-len2|步,
// 然后遍历寻找两个链表对应结点的指针是否相同,第一个指针相同的结点即为第一个公共结点(只要第一个指针相同,则后面的指针一定相同)
//计算链表长度
int length(LinkList L){
L=L->next;
int length=0;
while(L){
length++;
L=L->next;
}
return length;
}
//寻找两个链表的公共结点
LinkList search_common_firstnode(LinkList L1,LinkList L2){
int len1=length(L1),len2=length(L2);
int dist;//记录两个链表的长度差
LNode *longL,*shortL;//分别指向长链表和短链表
if(len1>=len2){ //计算链表的长度差
dist=len1-len2;
longL=L1->next;
shortL=L2->next;
}else{
dist=len2-len1;
longL=L2->next;
shortL=L1->next;
}
while(dist){ //长链表先走dist步
longL=longL->next;
dist--;
}
while(longL){ //判断并查找公共结点
if(longL==shortL){ //如此时结点地址(即指针)相同,则为公共结点
return longL;
}else{
longL=longL->next;
shortL=shortL->next;
}
}
return NULL;//如while循环结束,但未找到公共结点,则返回NULL
}
//创建公共链表
void create_common_list(LinkList L1,LinkList L2){
LNode *r1,*r2,*s;
ElemType x;
while(L1->next){
L1=L1->next;
}
r1=L1;
while(L2->next){
L2=L2->next;
}
r2=L2;
printf("input common node,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r1->next=s;
r2->next=s;
r1=s;
r2=s;
scanf("%d",&x);
}
r1->next=NULL;
r2->next=NULL;
}
//打印链表:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L1,L2;
LNode *p;//用于存储公共结点指针
L1= list_tail_insert(L1);
L2= list_tail_insert(L2);
create_common_list(L1,L2);
printf("the L1 is :\n");
print_list(L1);
printf("the L2 is:\n");
print_list(L2);
p= search_common_firstnode(L1,L2);
if(p){
printf("the common node is %d:\n",p->data);
}else{
printf("the two lists don't have common node");
}
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 4 5 9999
input x,ended with 9999:
4 5 9999
input common node,ended with 9999:
7 8 9 9999
the L1 is :
1 2 3 4 5 7 8 9
the L2 is:
4 5 7 8 9
the common node is 7:
进程已结束,退出代码为 0
2.3.7-9 给定一个带表头结点的单链表,设head为头指针,结点结构为(data,next),试写出算法:按递增次序输出单链表中各节点的数据元素,并释放结点所占空间(要求:不允许使用数组作为辅助空间)。
#include
#include
// 给定一个带表头结点的单链表,设head为头指针,结点结构为(data,next),
// 试写出算法:按递增次序输出单链表中各节点的数据元素,并释放结点所占空间(要求:不允许使用数组作为辅助空间)。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//递增输出结点数据,并释放结点空间
//算法思想:遍历单链表,每次找出最小的数据元素,输出并释放结点空间,以此类推,直到链表为空,然后删除头结点空间
void sort_delete_min(LinkList &head){ //会修改head的值,因此要引用
LNode *pre,*p,*q;//pre指针记录最小结点的前驱,p为工作指针,q为临时指针
while(head->next){
pre=head,p=pre->next;//每次从表头开始遍历
while(p->next!=NULL){ //查找最小元素结点
if(p->next->datanext->data){
pre=p;
}
p=p->next;
}
printf("%3d",pre->next->data);
q=pre->next;
pre->next=q->next;
free(q);
}
free(head);
}
//打印函数:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList head;
head=list_tail_insert(head);
printf("the original list is:\n");
print_list(head);
printf("the sorted list is:\n");
sort_delete_min(head);
return 0;
}
输出结果:
input x,ended with 9999:
2 3 1 4 9999
the original list is:
2 3 1 4
the sorted list is:
1 2 3 4
进程已结束,退出代码为 0
2.3.7-10 将一个带头结点的单链表A分解为两个带头结点的单链表A和B,使得A表中含有原表中序号为奇数的元素,而B表中含有原表中序号为偶数的元素,且保持相对顺序不变。
#include
#include
//将一个带头结点的单链表A分解为两个带头结点的单链表A和B,
// 使得A表中含有原表中序号为奇数的元素,而B表中含有原表中序号为偶数的元素,且保持相对顺序不变。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//分解单链表
//算法思想:链表顺序不变,采用尾插法的思想;
LinkList segment_create(LinkList A){
LinkList B;
B=(LNode *)malloc(sizeof(LNode));
B->next=NULL;
LNode *p=A->next,*rA=A,*rB=B;//链表A和B的尾指针,p为遍历指针
while(p){
rA->next=p; //从A的第一个结点开始遍历(此时序号为奇数),将rA的next指针指向p(此时序号为奇数),然后将尾指针移动到p,将p向前移动
rA=p;
p=p->next;
if(p){
rB->next=p;//将rB的next指针指向p(此时序号为偶数),然后将尾指针移动到p,将p继续向前移动(序号为奇数)
rB=p;
p=p->next;
}
}
rA->next=NULL;
rB->next=NULL;
return B;
}
//打印函数:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList A,B;
A= list_tail_insert(A);
printf("the original list A is:\n");
print_list(A);
B= segment_create(A);
printf("the list A segmented with odd number is:\n");
print_list(A);
printf("the list B segmented with even number is:\n");
print_list(B);
return 0;
}
输出结果:
input x,ended with 9999:
1 2 9999
the original list A is:
1 2
the list A segmented with odd number is:
1
the list B segmented with even number is:
2
进程已结束,退出代码为 0
2.3.7-11 设C={a1,b1,a2,b2,…,an,bn}为线性表,采用带头结点的hc单链表存放,设计一个就地算法,将其拆分为两个线性表,使得A={a1,a2,…,an},B={bn,…,b2,b1}。
#include
#include
// 设C={a1,b1,a2,b2,...,an,bn}为线性表,采用带头结点的hc单链表存放,设计一个就地算法,
// 将其拆分为两个线性表,使得A={a1,a2,...,an},B={bn,...,b2,b1}。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//分解链表
//算法思想:依次遍历链表C,采用尾插法将ai留在链表C中,采用头插法建立链表B
LinkList segment_create(LinkList A){
LinkList hb;
hb=(LNode *)malloc(sizeof(LNode));
hb->next=NULL;
LNode *p=A->next,*ra=A,*q;//p为遍历指针,ra为链表A的尾指针,q为临时指针(防止断链)
while(p){
ra->next=p;
ra=p;
p=p->next;
if(p){
q=p; //为防止头插法断链,需要用临时指针指向p所指结点,然后p移动到下一个结点
p=p->next;
q->next=hb->next;
hb->next=q;
}
}
ra->next=NULL;
return hb;
}
//打印函数:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList hc,hb;
hc= list_tail_insert(hc);
printf("the list c is:\n");
print_list(hc);
hb= segment_create(hc);
printf("the list a is:\n");
print_list(hc);
printf("the list b is:\n");
print_list(hb);
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 4 5 9999
the list c is:
1 2 3 4 5
the list a is:
1 3 5
the list b is:
4 2
进程已结束,退出代码为 0
2.3.7-12 在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。
#include
#include
//在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//删除重复元素
//算法思想:由于是有序线性表,故重复元素是连续的。设置遍历指针p,如p所指结点的值与其后继结点的值相同,则删除其后继结点;否则,p移动向下一个结点
void delete_repeated_element(LinkList L){
LNode *p=L->next,*q;//从第一个结点开始遍历,q为临时指针
if(p==NULL){
return;
}
while(p->next){
if(p->next->data==p->data){
q=p->next;
p->next=q->next;
free(q);
p=p->next;
}else{
p=p->next;
}
}
}
//打印函数:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L;
L= list_tail_insert(L);
printf("the original list is:\n");
print_list(L);
delete_repeated_element(L);
printf("the list that deletes repeated elements is:\n");
print_list(L);
return 0;
}
输出结果:
input x,ended with 9999:
1 2 2 3 4 4 5 9999
the original list is:
1 2 2 3 4 4 5
the list that deletes repeated elements is:
1 2 3 4 5
进程已结束,退出代码为 0
2.7.3-13 假设有两个按元素值递增次数排列的线性表,均以单链表形式存储。请编写算法,将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。
#include
#include
//假设有两个按元素值递增次数排列的线性表,均以单链表形式存储。请编写算法,
// 将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//合并递增有序的单链表为递减有序的单链表
//算法思想:由于待合并的两个链表均是递增有序的,因此只要依次比较两个单链表第一个结点的值的大小,将较小的元素放入链表即可
// 从第一个结点开始,比较两个单链表的值,然后将较小的结点摘下,用头插法插入链表中;如果有一个链表剩余,则将其剩余部分全部插入链表;
// 最后将多余的链表头结点释放掉
void merge_list(LinkList L1,LinkList &L2){ //L1头指针不改变,L2头指针要释放掉,会改变,所以要引用
LNode *p1=L1->next,*p2=L2->next,*q;//p1和p2为遍历指针,q为临时指针(头插法会断链,因此先要用临时指针指向待插入的结点)
L1->next=NULL;//头插法初始化
while(p1&&p2){ //L1和L2均不为空
if(p1->datadata){
q=p1;
p1=p1->next;
q->next=L1->next;
L1->next=q;
}else{
q=p2;
p2=p2->next;
q->next=L1->next;
L1->next=q;
}
}
while(p1){ //L1链表剩余
q=p1;
p1=p1->next;
q->next=L1->next;
L1->next=q;
}
//上面的while循环也可按照书上的写作以下代码,更加简洁
// if(p1){
// p2=p1;
// }
while(p2){ //L2链表剩余
q=p2;
p2=p2->next;
q->next=L1->next;
L1->next=q;
}
free(L2);//释放掉多余的头结点
}
//打印函数:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L1,L2;
L1= list_tail_insert(L1);
L2= list_tail_insert(L2);
printf("L1 is:\n");
print_list(L1);
printf("L2 is:\n");
print_list(L2);
merge_list(L1,L2);
printf("the merged list L is:\n");
print_list(L1);
return 0;
}
输出结果:
input x,ended with 9999:
1 3 5 7 9999
input x,ended with 9999:
2 4 6 8 9999
L1 is:
1 3 5 7
L2 is:
2 4 6 8
the merged list L is:
8 7 6 5 4 3 2 1
进程已结束,退出代码为 0
2.3.7-14 设A和B是两个单链表(带头结点),其中元素递增有序。设计一个算法从A和B中的公共元素产生单链表C,要求不破坏A、B的结点。
#include
#include
//设A和B是两个单链表(带头结点),其中元素递增有序。设计一个算法从A和B中的公共元素产生单链表C,要求不破坏A、B的结点。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//两个链表的公共元素产生单链表
//算法思想:两个链表递增有序,从第一个结点开始比较;如果两个结点值不相等,则值较小的指针后移;如元素相等,则创建一个值等于结点值的新结点,
// 使用尾插法插入新链表中,并将两个链表的指针同时后移一个结点。
LinkList create_common_list(LinkList L1,LinkList L2){
LinkList L;
L=(LNode *)malloc(sizeof(LNode));
LNode *r=L,*s;//r为新链表尾指针,s为新结点指针
LNode *p1=L1->next,*p2=L2->next;//从第一个结点开始遍历
while(p1&&p2){
if(p1->datadata){
p1=p1->next;
}else if(p1->datadata){
p2=p2->next;
}else{
s=(LNode *)malloc(sizeof(LNode));
s->data=p1->data;
r->next=s;
r=s;
p1=p1->next;
p2=p2->next;
}
}
r->next=NULL;
return L;
}
//打印函数:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L1,L2,L;
L1= list_tail_insert(L1);
L2= list_tail_insert(L2);
printf("L1 is :\n");
print_list(L1);
printf("L2 is:\n");
print_list(L2);
printf("the common list of L1 and L2 is:\n");
L= create_common_list(L1,L2);
print_list(L);
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 4 5 6 9999
input x,ended with 9999:
2 4 6 8 9999
L1 is :
1 2 3 4 5 6
L2 is:
2 4 6 8
the common list of L1 and L2 is:
2 4 6
进程已结束,退出代码为 0
2.3.7-15 已知两个链表A和B分别表示两个集合,其元素递增排列。编制函数,求A与B的交集,并存放于A链表中。
#include
#include
//已知两个链表A和B分别表示两个集合,其元素递增排列。编制函数,求A与B的交集,并存放于A链表中。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//合并单链表公共元素至一个链表中
//算法思想:本题与上题不同的地方在于,合并后的元素存放在链表A中,需要把其它结点删除
//从第一个结点开始遍历,如元素不相等,则将较小的元素删除,并将指针后移一个结点;如元素相等,
// 则保留A链表中的元素,删除B链表中的元素,同时将两个链表指针均后移一个结点
void create_common_list(LinkList La,LinkList &Lb){
LNode *pa=La->next,*pb=Lb->next,*r=La,*q;//r为La的尾指针,q为临时结点
while(pa&&pb){
if(pa->datadata){ //较小元素删除,并将指针后移
q=pa;
pa=pa->next;
free(q);
}else if(pa->data>pb->data){
q=pb;
pb=pb->next;
free(q);
}else{ //采用尾插法,保留A链表中元素,同时删除B链表中元素,并将两个链表的元素均后移
r->next=pa;
r=pa;
pa=pa->next;
q=pb;
pb=pb->next;
free(q);
}
}
r->next=NULL;
if(pa){
pb=pa;
}
while(pb){
q=pb;
pb=pb->next;
free(q);
}
free(Lb); //删除B链表的头结点
}
//打印函数:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList La,Lb;
La=list_tail_insert(La);
Lb=list_tail_insert(Lb);
printf("La is:\n");
print_list(La);
printf("Lb is:\n");
print_list(Lb);
create_common_list(La,Lb);
printf("the common list is:\n");
print_list(La);
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 4 5 9999
input x,ended with 9999:
2 4 6 9999
La is:
1 2 3 4 5
Lb is:
2 4 6
the common list is:
2 4
进程已结束,退出代码为 0
2.3.7-16 两个整数序列A=a1,a2,…,am和B=b1,b2,…,bn已经存入两个单链表中,设计一个算法,判断序列B是否是序列A的连续子序列。
#include
#include
//两个整数序列A=a1,a2,...,am和B=b1,b2,...,bn已经存入两个单链表中,设计一个算法,判断序列B是否是序列A的连续子序列。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//判断连续子序列:判断B是否是A的连续子序列
//算法思想:从链表A的第一个结点开始,依次与B的元素比较,如B链表遍历完,A的元素均等于B中的元素,则是子序列;
// 否则,将A的元素后移一个,重新再与B元素依次比较
bool judge_sub_list(LinkList La,LinkList Lb){
LNode *pa=La->next,*pb,*q;
while(pa){
q=pa;
pb=Lb->next;
while(pb&&q&&pb->data==q->data){
q=q->next;//A链表每次从pa所指结点开始遍历
pb=pb->next;
}
if(pb){
pa=pa->next;
}else{
return true; //退出子函数并返回true
}
}
}
//打印函数:带头结点
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList La,Lb;
bool ret;
La= list_tail_insert(La);
Lb= list_tail_insert(Lb);
ret= judge_sub_list(La,Lb);
if(ret){
printf("Lb is the continuous sub_list of La\n");
}else{
printf("Lb is not the continuous sub_list of La\n");
}
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 2 3 4 5 9999
input x,ended with 9999:
2 3 4 9999
Lb is the continuous sub_list of La
进程已结束,退出代码为 0
2.3.7-17 设计一个算法,判断带头结点的循环双链表是否对称。
#include
#include
//设计一个算法,判断带头结点的循环双链表是否对称。
typedef int ElemType;
//循环双链表结构类型定义
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode,*DLinkList;
//尾插法建立循环双链表
DLinkList dlist_tail_insert(DLinkList &L){
L=(DNode *)malloc(sizeof(DNode));
L->next=L;//循环双链表初始化
L->prior=L;
DNode *r=L,*s;//定义尾指针
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(DNode *)malloc(sizeof(DNode));
s->data=x;
s->next=r->next;
r->next->prior=s;
r->next=s;
s->prior=r;
r=s;
scanf("%d",&x);
}
return L;
}
//设计一个算法,判断带头结点的循环双链表是否对称。
//算法思想:由于是循环双链表,故很容易双向遍历并找到尾指针。
// 在表头和表尾分别设置两个指针p和q,两个指针同时向中间结点遍历,如结点数值相等,则一直向中间结点遍历,直到到达同一结点(p==q)或者相邻q->next=p
bool symmetry_dlist(DLinkList L){
DNode *p=L->next,*q=L->prior;
while(p!=q&&q->next!=p){ //如条件改为p->next!=q,则会漏掉判断中间两个节点的值,所以需要p和q多走一步
if(p->data==q->data){
p=p->next;
q=q->prior;
}else{
return false; //退出子函数并返回false
}
}
return true;
}
//打印函数:循环双链表
void print_dlist(DLinkList L){
DNode *p=L->next;
while(p!=L){
printf("%3d",p->data);
p=p->next;
}
printf("\n");
}
int main() {
DLinkList L;
bool ret;
L= dlist_tail_insert(L);
printf("the DLinklist is:\n");
print_dlist(L);
ret= symmetry_dlist(L);
if(ret){
printf("Result:the DLinklist L is a symmetrical list\n");
}else{
printf("Result:the DLinkList is not a symmetrical list");
}
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 4 2 1 9999
the DLinklist is:
1 2 3 4 2 1
Result:the DLinkList is not a symmetrical list
进程已结束,退出代码为 0
2.3.7-18 有两个循环单链表,链表头指针分别为h1和h2,编写一个函数将链表h2链接到链表h1之后,要求链接到的链表仍然保持循环链表形式。
#include
#include
//有两个循环单链表,链表头指针分别为h1和h2,编写一个函数将链表h2链接到链表h1之后,要求链接到的链表仍然保持循环链表形式。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立循环单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
L->next=L;//循环单链表初始化
LNode *r=L,*s;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=L;
return L;
}
//将循环单链表h2连接到h1之后
//算法思想:需要遍历先找到h1和h2的尾指针,然后将h2的第一个结点链接到h1后面,并修改h2的尾结点的next指针指向h1,最后释放掉h2
LinkList link_list(LinkList &h1,LinkList &h2){
LNode *r1=h1,*r2=h2;
while(r1->next!=h1){
r1=r1->next;
}
while(r2->next!=h2){
r2=r2->next;
}
if(h2->next!=h2){ //如h2为空,则直接删除h2头结点
r1->next=h2->next;
r2->next=h1;
}
free(h2);
return h1;
}
//打印函数:循环单链表
void print_list(LinkList L){
LNode *p=L->next;
while(p!=L){
printf("%3d",p->data);
p=p->next;
}
printf("\n");
}
int main() {
LinkList h1,h2;
h1= list_tail_insert(h1);
h2= list_tail_insert(h2);
printf("the list h1 is:\n");
print_list(h1);
printf("the list h2 is:\n");
print_list(h2);
h1= link_list(h1,h2);
printf("the list h1 linked by h2 is:\n");
print_list(h1);
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 9999
input x,ended with 9999:
1 2 9999
the list h1 is:
1 2 3
the list h2 is:
1 2
the list h1 linked by h2 is:
1 2 3 1 2
进程已结束,退出代码为 0
2.3.7-19 设有一个带头结点的循环单链表,其结点值均为正整数,设计一个算法,反复找出单链表中结点值最小的结点并输出,然后将该结点删除,直到单链表为空为止,再删除表头结点。
#include
#include
//设有一个带头结点的循环单链表,其结点值均为正整数,设计一个算法,
// 反复找出单链表中结点值最小的结点并输出,然后将该结点删除,直到单链表为空为止,再删除表头结点。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立循环单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
L->next=L;//循环单链表初始化
LNode *r=L,*s;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=L;
return L;
}
//算法思想:本题与第9题的思路一致
void sort_delete_list(LinkList &L){
LNode *pre,*p,*q;//pre指向最小结点的前驱,p为工作指针,q为临时指针
while(L->next!=L){ //与一般单链表不同的地方在于循环单链表判空的条件
pre=L;p=pre->next;//每次从第一个结点开始比较
while(p->next!=L){
if(p->next->datanext->data){
pre=p;
}
p=p->next;
}
printf("%3d",pre->next->data);
q=pre->next;
pre->next=q->next;
free(q);
}
free(L);
}
//打印函数:循环单链表
void print_list(LinkList L){
LNode *p=L->next;
while(p!=L){
printf("%3d",p->data);
p=p->next;
}
printf("\n");
}
int main() {
LinkList L;
L= list_tail_insert(L);
printf("the list L is:\n");
print_list(L);
printf("the sorted list is:\n");
sort_delete_list(L);
return 0;
}
输出结果:
input x,ended with 9999:
2 3 1 5 4 9999
the list L is:
2 3 1 5 4
the sorted list is:
1 2 3 4 5
进程已结束,退出代码为 0
2.3.7-20 设头指针为L的带有表头结点的非循环双向链表,其每个结点中除有pred(前驱指针)、data(数据)和next(后继指针)外,还有一个访问频度域freq。在链表被启用前,其值均初始化为0。每当在链表中进行过一次Locate(L,x)运算时,令元素值为x的结点中freq的值增加1,并使此链表中结点保持访问频度非增(递减)的顺序排列,同时最近访问的结点排在频度相同的结点前面,以便使频繁访问的结点总是靠近表头。试编写符合上述要求的Locate(L,x)算法,该运算为函数过程,返回找到结点的地址,类型为指针类型。
#include
#include
//设头指针为L的带有表头结点的非循环双向链表,其每个结点中除有pred(前驱指针)、data(数据)和next(后继指针)外,
// 还有一个访问频度域freq。在链表被启用前,其值均初始化为0。每当在链表中进行过一次Locate(L,x)运算时,令元素值
// 为x的结点中freq的值增加1,并使此链表中结点保持访问频度非增(递减)的顺序排列,同时最近访问的结点排在频度相同
// 的结点前面,以便使频繁访问的结点总是靠近表头。试编写符合上述要求的Locate(L,x)算法,该运算为函数过程,
// 返回找到结点的地址,类型为指针类型。
typedef int ElemType;
typedef struct DNode{
ElemType data;
struct DNode *pred,*next;
int freq;
}DNode,*DLinkList;
//尾插法建立带头结点非循环双链表
DLinkList list_tail_insert(DLinkList &L){
L=(DNode *)malloc(sizeof(DNode));
DNode *r=L,*s;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while(x!=9999){
s=(DNode *)malloc(sizeof(DNode));
s->data=x;
s->freq=0;
r->next=s;
s->pred=r;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//带头结点非循环双链表按值查找元素,并统计其访问频度,然后按访问频度排序双链表
//算法思想:从头开始查找元素值为x的结点,找到后其freq+1;然后将该结点摘下,并从该结点开始,向前遍历,
// 直到其前驱结点的freq大于等于该结点的freq,将该结点在找到的前驱结点后面插入。
//双链表需要把握好链表链尾两个边界条件
DLinkList Locate(DLinkList &L,ElemType x){
DNode *p=L->next,*q;//p为工作指针,q指向数值为x的结点
while(p&&p->data!=x){
p=p->next;
}
if(p){
p->freq++;
if(p->pred==L||p->pred->freq>p->freq){ //p是链表第一个结点,或者其前驱结点的访问频率大于p结点,则不移动结点,直接返回
return p;
}
q=p;//移动结点位置,用q记录现在结点的地址
p=p->pred;//向前遍历寻找插入点
p->next=q->next;//将值为x的结点摘下
if(q->next){
q->next->pred=p;
}
while(p!=L&&p->freq<=q->freq){ //如前驱结点的访问频度相同,则仍然需要向前移动
p=p->pred;
}
q->next=p->next;//将q插入至p后面
if(p->next!=NULL){ //如p为表尾结点
p->next->pred=q;
}
q->pred=p;
p->next=q;
return q;//返回该结点最终的指针
}else{
return NULL;
}
}
//打印函数:带头结点
void print_list(DLinkList L){
L=L->next;
printf("data,freq\n");
while(L){
printf("%2d,%3d\n",L->data,L->freq);
L=L->next;
}
printf("\n");
}
int main() {
DLinkList L;
DNode *p;//用于接收子函数返回的地址
L= list_tail_insert(L);
printf("list L is:\n");
print_list(L);
p=Locate(L,2);
p=Locate(L,3);
p=Locate(L,2);
if(p){
printf("element is:data=%d,freq=%d\n",p->data,p->freq);
printf("the new list is:\n");
print_list(L);
}else{
printf("element x doesn't exit\n");
}
return 0;
}
输出结果:
input x,ended with 9999:
2 1 3 9999
list L is:
data,freq
2, 0
1, 0
3, 0
element is:data=2,freq=2
the new list is:
data,freq
2, 2
3, 1
1, 0
进程已结束,退出代码为 0
2.3.7-21 单链表有环,是指单链表的最后一个结点的指针指向了链表中的某个结点(单链表的最后一个结点的指针域一般应为空)。试编写算法判断单链表是否存在环。
#include
#include
//单链表有环,是指单链表的最后一个结点的指针指向了链表中的某个结点(单链表的最后一个结点的指针域一般应为空)。
// 试编写算法判断单链表是否存在环。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//算法思想:设置两个指针slow和fast,slow每次向后走一步,fast每次向后走两步,
// 如果单链表有环,则slow和fast必然在经过多次循环后,在环上相遇,则可知道相遇点的指针。
//知道相遇点指针后,如何知道环的入口点指针呢?
//假设表头L到入环点的距离为a,入环点到相遇点的距离为x,环长为r,相遇时fast绕过了n圈,则可以知道:fast步数=2*slow步数,即2(a+x)=a+n*r+x,
//可得,a=n*r-x;
//即设置指针p1=L从表头移动a步时,恰好处在相遇点的p2=slow指针移动了n*r-x步,即恰好p1和p2指针相遇在入环点处。
LNode* find_loop_start(LinkList L){
LNode *slow=L,*fast=L;
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
break;
}
}
if(fast==NULL||fast->next==NULL){
return NULL;
}
LNode *p1=L,*p2=slow;
while(p1!=p2){
p1=p1->next;
p2=p2->next;
}
return p1;
}
//将单链表设置为有环的链表
void loop_list(LinkList L){
LNode *r=L;
while(r->next){
r=r->next;
}
r->next=L->next->next;
}
//打印函数
void print_list(LinkList L){
L=L->next;
while(L){
printf("%3d",L->data);
L=L->next;
}
printf("\n");
}
int main() {
LinkList L,p;
L= list_tail_insert(L);
print_list(L);
loop_list(L);
p= find_loop_start(L);
if(p){
printf("the loop start node is:%d\n",p->data);
}else{
printf("the list doesn't have loop\n");
}
return 0;
}
输出结果:
input x,ended with 9999:
1 2 3 4 5 9999
1 2 3 4 5
the loop start node is:2
进程已结束,退出代码为 0
2.3.7-22 【2009真题】已知一个带表头结点的单链表,结点结构为:data和link。假设该链表只给出了头指针list。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第k个位置的结点(k为正整数)。若查找成功,算法输出该结点的data值,并返回1;否则,只返回0。
#include
#include
//已知一个带表头结点的单链表,结点结构为:data和next。
// 假设该链表只给出了头指针L。在不改变链表的前提下,请设计一个尽可能高效的算法,
// 查找链表中倒数第k个位置的结点(k为正整数)。若查找成功,算法输出该结点的data值,并返回1;否则,只返回0。
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//尾插法建立单链表
LinkList list_tail_insert(LinkList L){
L=(LNode *)malloc(sizeof(LNode));
LNode *s,*r=L;
ElemType x;
printf("input x,ended with 9999:\n");
scanf("%d",&x);
while (x!=9999){
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL;
return L;
}
//查找单链表倒数第k个结点的值
//算法思想:设置两个工作指针pre和p,初始时均指向头结点;
// 让p指针先后移k个位置;然后,pre指针和p指针同时移动,当p指针为NULL时,pre到达倒数第k个结点
bool search_k(LinkList L,int k){
LNode *pre=L,*p=L;
int count=0;
while(p!=NULL&&countnext;
count++;
}
if(countnext;
p=p->next;
}
printf("search data=%d\n",pre->data);
return 1;
}
int main() {
LinkList L;
bool ret;
L= list_tail_insert(L);
ret=search_k(L,3);
if(ret){
printf("search sucess\n");
}else{
printf("search fail\n");
}
return 0;
}
输出结果:
input x,ended with 9999:
1 2 9999
search fail
进程已结束,退出代码为 0
input x,ended with 9999:
1 2 3 9999
search data=1
search sucess
进程已结束,退出代码为 0
2.3.7-23 假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,可共享相同的后缀空间。设str1和str2分别指向两个单词所在单链表的头结点,请设计一个时间上尽可能高效的算法,找出由str1和str2所指向两个链表共同后缀的起始位置。
与第8题思路一致
2.3.7-24