【王道数据结构课后习题代码练习完整版】链表

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

你可能感兴趣的:(数据结构,链表,数据结构)