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

2.3.7-1 设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点

#include <stdio.h>
#include<stdlib.h>

//设计一个递归算法,删除不带头结点的单链表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 <stdio.h>
#include<stdlib.h>

// 在带头结点的单链表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 <stdio.h>
#include<stdlib.h>

//设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 <stdio.h>
#include<stdlib.h>

//试编写在带头结点的单链表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->data<minp->data){
            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 <stdio.h>
#include<stdlib.h>

//试编写算法将带头结点的单链表就地逆置
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 <stdio.h>
#include<stdlib.h>

//有一个带头结点的单链表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->data<p->data){
            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 <stdio.h>
#include<stdlib.h>

//设在一个带表头结点的单链表中,所有结点的数值无序。试编写一个函数,删除表中所有介于给定的两个值之间的元素。
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 <stdio.h>
#include<stdlib.h>

//给定两个单链表,编写算法找出两个单链表的公共结点

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 <stdio.h>
#include<stdlib.h>
// 给定一个带表头结点的单链表,设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->data<pre->next->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 <iostream>
#include<stdlib.h>

//将一个带头结点的单链表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 <stdio.h>
#include<stdlib.h>
// 设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 <stdio.h>
#include<stdlib.h>

//在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素。
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 <stdio.h>
#include<stdlib.h>
//假设有两个按元素值递增次数排列的线性表,均以单链表形式存储。请编写算法,
// 将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。
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->data<p2->data){
            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 <stdio.h>
#include<stdlib.h>
//设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->data<p2->data){
            p1=p1->next;
        }else if(p1->data<p2->data){
            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 <stdio.h>
#include<stdlib.h>

//已知两个链表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->data<pb->data){ //较小元素删除,并将指针后移
            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 <stdio.h>
#include<stdlib.h>
//两个整数序列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 <stdio.h>
#include<stdlib.h>
//设计一个算法,判断带头结点的循环双链表是否对称。
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 <stdio.h>
#include<stdlib.h>
//有两个循环单链表,链表头指针分别为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 <stdio.h>
#include<stdlib.h>
//设有一个带头结点的循环单链表,其结点值均为正整数,设计一个算法,
// 反复找出单链表中结点值最小的结点并输出,然后将该结点删除,直到单链表为空为止,再删除表头结点。
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->data<pre->next->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 <stdio.h>
#include<stdlib.h>

//设头指针为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 <stdio.h>
#include<stdlib.h>
//单链表有环,是指单链表的最后一个结点的指针指向了链表中的某个结点(单链表的最后一个结点的指针域一般应为空)。
// 试编写算法判断单链表是否存在环。

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 <stdio.h>
#include<stdlib.h>
//已知一个带表头结点的单链表,结点结构为: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&&count<k){
        p=p->next;
        count++;
    }
    if(count<k||p==NULL){ //p==NULL发生在p恰好到NULL,此时pre恰好在表头,此时count=k
        return 0; //访问越界
    }
    while(p){
        pre=pre->next;
        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

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
王道数据结构课后代码的C语言完整可以有很多种不同的代码示例,如下是一个实现链表的示例: ```c #include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node* next; } Node; Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->next = NULL; return newNode; } void insert(Node** head, int data) { if (*head == NULL) { *head = createNode(data); return; } Node* curr = *head; while (curr->next != NULL) { curr = curr->next; } curr->next = createNode(data); } void display(Node* head) { Node* curr = head; while (curr != NULL) { printf("%d ", curr->data); curr = curr->next; } printf("\n"); } void delete(Node** head, int data) { if (*head == NULL) { return; } Node* curr = *head; Node* prev = NULL; // 如果要删除的元素是第一个节点 if (curr->data == data) { *head = curr->next; free(curr); return; } // 否则遍历链表找到要删除的元素 while (curr != NULL && curr->data != data) { prev = curr; curr = curr->next; } // 如果找到了要删除的元素 if (curr != NULL) { prev->next = curr->next; free(curr); } } int main() { Node* head = NULL; insert(&head, 1); insert(&head, 2); insert(&head, 3); insert(&head, 4); display(head); delete(&head, 2); display(head); return 0; } ``` 以上代码实现了一个简单的链表数据结构,在main函数中对链表进行了插入和删除操作,并打印出链表中的元素。这只是一个简单的示例,王道数据结构课本中还有很多其他的数据结构和算法代码可以一一学习和实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值