学校的oj:“略为”复杂的链表操作

又是一次愉快的学校的oj作业题…
由于我实在是太懒了😭 一直到现在才更

话不多说上题目:

Problem A: 实验11_9_链表归并

已知有两个递增的正整数序列A和B,序列中元素个数未知,同一序列中不会有重复元素出现,有可能某个序列为空。现要求将序列B归并到序列A中,且归并后序列A的数据仍然按递增顺序排列。如果序列B中某些数据在序列A中也存在,则这些数据所在节点仍然留在序列B中,而不被归并到序列A中;否则这些数据所在节点将从序列B中删除,添加到序列A中。
要求:
建立两个单链表A、B用于存储两个正整数序列,然后按照题目的要求,将链表B中的元素归并到链表A中。在归并的过程中,不要释放B中的节点空间、然后建立新节点,而要改变指针的指向,使元素从B中删除并添加到A中。正整数序列按照递增顺序输入,用-1作为结束标志,注意-1不算这个正整数序列中的元素(不要统计-1)。在程序结束前要释放链表A、B中的所有节点。
Input

依次输入两个递增的正整数序列A和B,序列元素的个数未知,但以输入“-1”结束,每个正整数序列占一行。
Output

处理后的链表A中的元素,占一行;然后是处理后的链表B中的元素,占一行。每行的每个元素后有一个空格,注意最后一个元素后只有换行符,如果某个链表为空则,则输出“There is no item in X list.”
数据最多的测试用例节点数在100这个数量级,所有整数可以用int型存储。
请注意输入输出格式。
Sample Input Copy

Sample 1:
1 3 4 5 6 7 -1
2 3 6 8 9 10 11-1

Sample 2:
-1
-1
Sample Output Copy

Sample 1:
The new list A:1 2 3 4 5 6 7 8 9 10 11
The new list B:3 6

Sample 2:
There is no item in A list.
There is no item in B list.

我一开始看到这个题想着哈这不简单么 不就是个归并么 重新建立个表然后双管齐下看哪个大些不就行了么
然后眉头一皱 发现事情并不简单:直接对A操作!!不能建立一个新的表格!!!

我的思路是如果b的数据在a的两个相邻的数据之间,则插入进去
然后…
坑也许会迟到 但是绝对不会缺席 T-T
大概我踩进的坑有⬇️:
1、头插元素 因为原来的头节点没有元素 可以分类讨论来解决
但是我灵机一动 因为元素都是正整数,所以把头节点的元素初始化为0即可
2、尾插元素 同上 如果元素插在A的后面 “b的数据在a的两个相邻的数据”这个判准就不适用了 需要分类讨论
(后来发现可以模仿1的方法把尾巴数据定为2147483647就可了 只不过我的代码就没修改了)
3、一次插入多个元素 我一开始默认了两个元素之间只插入一个元素,然后光荣牺牲 后来改成while就可以了

上代码:/由于学校代码风格的要求加了一大堆注释…/

#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
    int data;
    struct node *next;
}NODE;
typedef NODE* NODEPTR;
void createList(NODEPTR *headPtrPtr);//建立链表,并把第一个头节点的数据初始化为0减少讨论
void mergeList(NODEPTR *headPtrPtrA, NODEPTR *headPtrPtrB);//合并链表
void printListA(NODEPTR *headPtrPtr);//打印A链表
void printListB(NODEPTR *headPtrPtr);//打印B链表
void freeList(NODEPTR *headPtrPtr);//释放链表
int main()
{
    NODE *headA, *headB;
    createList(&headA);//建立A链表
    createList(&headB);//建立B链表
    mergeList(&headA, &headB);//合并链表
    printListA(&headA);//打印A链表
    printListB(&headB);//打印B链表
    freeList(&headA);//释放A链表
    freeList(&headB);//释放B链表
    return 0;
}
void createList(NODEPTR *headPtrPtr)
{
    int num;
    NODEPTR currentPtr, previousPtr;
    (*headPtrPtr) = malloc(sizeof(NODEPTR));
    previousPtr = (*headPtrPtr);
    previousPtr -> next = NULL;
    previousPtr -> data = 0;
    scanf("%d", &num);
    while(num!=-1)
    {
        currentPtr = malloc(sizeof(NODEPTR));
        currentPtr -> data = num;
        currentPtr -> next = NULL;
        previousPtr -> next = currentPtr;
        previousPtr = currentPtr;
        scanf("%d", &num);
    }
}
void mergeList(NODEPTR *headPtrPtrA, NODEPTR *headPtrPtrB)
{
    NODEPTR pA, pB, preB;
    pA = *headPtrPtrA;
    preB = *headPtrPtrB;
    pB = preB -> next;
    while(pA!=NULL && pB!=NULL)
    {
        if(pA->next == NULL)//如果A在尾节点上
        {
            if(pA->data==pB->data)//如果数据相同则后移B指针
            {
                preB = pB;
                pB = preB -> next;
            }
            while(pB != NULL && pA->data<pB->data)//可以插到A的后面
            {
                preB -> next = pB -> next;
                pB -> next = pA -> next;
                pA -> next = pB;
                pB = preB -> next;
                pA = pA -> next;
            }
        }
        else
        {
            while(pB!=NULL && pA->data <= pB -> data && pB->data<pA->next->data)//如果B的数据在A的两个数据之间
            {
                if(pA->data==pB->data)//数据相同则后移B指针
                {
                    preB = preB -> next;
                    pB = preB -> next;
                }
                else
                {
                    preB -> next = pB -> next;
                    pB -> next = pA -> next;
                    pA -> next = pB;
                    pB = preB -> next;
                    pA = pA -> next;
                }
            }
        }
        pA = pA ->next;
    }
}
void printListA(NODEPTR *headPtrPtr)
{
    NODEPTR currentPtr;
    currentPtr = (*headPtrPtr) -> next;
    if(currentPtr==NULL) printf("There is no item in A list.\n");
    else
    {
        printf("The new list A:");
        while(currentPtr!=NULL)
        {
            printf("%d ", currentPtr->data);
            currentPtr = currentPtr -> next;
        }
        printf("\n");
    }
    
}
void printListB(NODEPTR *headPtrPtr)
{
    NODEPTR currentPtr;
    currentPtr = (*headPtrPtr) -> next;
    if(currentPtr==NULL) printf("There is no item in B list.\n");
    else
    {
        printf("The new list B:");
        while(currentPtr!=NULL)
        {
            printf("%d ", currentPtr->data);
            currentPtr = currentPtr -> next;
        }
        printf("\n");
    }
    
}
void freeList(NODEPTR *headPtrPtr)
{
    NODEPTR currentPtr, nextPtr;
    currentPtr = (*headPtrPtr);
    while(currentPtr!=NULL)
    {
        nextPtr = currentPtr -> next;
        free(currentPtr);
        currentPtr = nextPtr;
    }
    return ;
}

Problem B: 实验11_15_拆分链表

已知有一个乱序的字符序列L,序列中的字符可能是英文字母、数字字符或其它字符,字符的个数未知,每个字符之间用空格分开。字符序列用“-1”作为输入结束标志,这里你要把-1当做一个字符串对待,并且不算作字符序列中的元素。如下即为一个合法的字符序列:“a c 3 b a d 6 , & j m 8 7 2 V -1”。你的任务是将这个字符序列拆分为三个独立的序列A、B和C,其中序列A存放序列L中的字母,序列B存放序列L中的数字,序列C存放序列L中的其他字符,然后,将序列A、B和C分别按照ASCII码的大小关系进行升序排序。最终序列L将变为空序列。
要求:
建立四个单链表,分别存储序列L、A、B、C中的元素。字符序列的输入用“-1”作为结束标志。建立链表L时,建议使用scanf(“%s”,s);来读取字符序列中的字符,即把单独的字符看做一个字符串读取。当L建立后,你要按照问题描述中所述,将L拆分为A、B、C三个链表,然后对每个链表都进行排序,这部分的操作都应该是对指针进行修改,而不是删除节点与建立新节点。在程序结束前要释放链表A、B、C中的所有节点。
Input

一个乱序的字符序列,序列元素的个数未知,以输入“-1”结束,输入“-1”前可能没有其它元素,每个字符序列占一行。
Output

链表A中的元素,占一行;然后是链表B中的元素,占一行。最后是链表C中的元素,占一行。每行的每个元素后有一个空格,注意最后一个元素后只有换行符,如果某个链表为空则,则输出“There is no item in X list.”
数据最多的测试用例节点数在100这个数量级。
请注意输入输出格式。
Sample Input Copy

Sample 1:
a c 3 b a d 6 , & j m 8 7 2 V -1

Sample 2:
z m v 1 a K 2 m p 9 a 0 a d -1
Sample Output Copy

Sample 1:
The list A is: V a a b c d j m
The list B is: 2 3 6 7 8
The list C is: & ,

Sample 2:
The list A is: K a a a d m m p v z
The list B is: 0 1 2 9
There is no item in C list.

第二题除了麻烦真的没有别的要注意的点了… 可能的坑都帮你挑明了
本来还担心数字有多位数的来着 后来发现都是“字符” 就放心大胆的写了

但是代码由于不给用全局变量写了好多二重指针…
看着别烦😂(但我自己都烦)

#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
    char symbol;
    struct node *next;
}NODE;
typedef NODE* NODEPTR;
void createListHead(NODEPTR *headPtrPtr);//创建链表头
void createList(NODEPTR *headPtrPtr);//建立总链表
void printList(NODEPTR *headPtrPtr, char ListName);//打印链表
void splitList(NODEPTR *head);//把链表拆分
void engraft(int num, NODEPTR *Ptr, NODEPTR *nextPtr);//把总元素接到第num个链表的后面
void findmin(NODEPTR *findPtrPtr, NODEPTR *locationPtrPtr, NODEPTR *preLocationPtrPtr, char minSymbol);//找到最小的元素
void select_sort(NODEPTR *headPtrPtr);//运用选择排序来给链表排序;
void freeList(NODEPTR *headPtrPtr);
int main()
{
    int i;
    NODEPTR head[4];
    for(i=0;i<4;i++) createListHead(&head[i]);//创建链表头
    createList(&head[0]);//建立总链表
    splitList(head);//把链表拆分
    for(i=1;i<=3;i++) //对某个链表
    {
        select_sort(&head[i]);//先排序
        printList(&head[i], 'A'-1+i);//然后打印
        freeList(&head[i]);//最后free掉
    }
    return 0;
}
void createListHead(NODEPTR *headPtrPtr)
{
    (*headPtrPtr) = (NODEPTR)malloc(sizeof(NODEPTR));
    (*headPtrPtr) -> next = NULL;
    return ;
}
void createList(NODEPTR *headPtrPtr)
{
    char s[5];
    NODEPTR currentPtr, previousPtr;
    previousPtr = (*headPtrPtr);
    scanf("%s", s);
    while(s[0]!='-' || s[1]!='1')
    {
        currentPtr = malloc(sizeof(NODEPTR));
        currentPtr -> symbol = s[0];
        currentPtr -> next = NULL;
        previousPtr -> next = currentPtr;
        previousPtr = currentPtr;
        scanf("%s", s);
    }
    return ;
}
void engraft(int num, NODEPTR *Ptr, NODEPTR *nextPtr)
{
    Ptr[0] -> next = (*nextPtr) -> next;
    Ptr[num]->next = (*nextPtr);
    (*nextPtr) -> next = NULL;
    Ptr[num] = Ptr[num]->next;
    (*nextPtr) = Ptr[0]->next;
}
void splitList(NODEPTR *head)
{
    int i;
    char temp;
    NODEPTR Ptr[4], nextPtr;
    for(i=0;i<=3;i++) Ptr[i] = head[i];
    nextPtr = head[0] -> next;
    while(nextPtr!=NULL)
    {
        temp = nextPtr -> symbol;
        if((temp>='a'&&temp<='z')||(temp>='A'&&temp<='Z')) engraft(1, Ptr, &nextPtr);//把元素接到A链表的后面
        else if(temp>='0' && temp<='9') engraft(2, Ptr, &nextPtr);//把元素接到B链表的后面
        else engraft(3, Ptr, &nextPtr);//把元素接到C链表的后面
    }

}
void findmin(NODEPTR *findPtrPtr, NODEPTR *locationPtrPtr, NODEPTR *preLocationPtrPtr, char minSymbol)
{
    while((*findPtrPtr)->next != NULL)
    {
        if((*findPtrPtr)->next->symbol < minSymbol)
        {
            minSymbol = (*findPtrPtr)->next->symbol;
            (*locationPtrPtr) = (*findPtrPtr) -> next;
            (*preLocationPtrPtr) = (*findPtrPtr);
        }
        (*findPtrPtr) = (*findPtrPtr) -> next;
    }    
}
void select_sort(NODEPTR *headPtrPtr)
{
    char minSymbol;
    NODEPTR preCurrentPtr, currentPtr, locationPtr, preLocationPtr, findPtr, temp;
    preCurrentPtr = (*headPtrPtr);
    currentPtr = preCurrentPtr -> next;
    while(currentPtr!=NULL && currentPtr->next != NULL)
    {
        minSymbol = currentPtr -> symbol;
        findPtr = currentPtr;
        preLocationPtr = preCurrentPtr;
        locationPtr = currentPtr;
        findmin(&findPtr, &locationPtr, &preLocationPtr, minSymbol);
        if(locationPtr!=currentPtr)//如果当前节点不是最小的
        {
            if(preLocationPtr==currentPtr)//如果最小的和当前的节点是相邻的
            {
                currentPtr->next = locationPtr->next;
                preCurrentPtr -> next = locationPtr;
                locationPtr->next = currentPtr;
            }
            else//如果最小的和当前的节点不是相邻的
            {
                temp = locationPtr -> next;
                preCurrentPtr->next = locationPtr;
                locationPtr -> next = currentPtr -> next;
                preLocationPtr -> next = currentPtr;
                currentPtr -> next = temp;
            }
        }
        preCurrentPtr = preCurrentPtr -> next;
        currentPtr = preCurrentPtr -> next;
    }
    return ;
}
void printList(NODEPTR *headPtrPtr, char ListName)
{
    NODEPTR currentPtr;
    currentPtr = (*headPtrPtr) -> next;
    if(currentPtr==NULL) printf("There is no item in %c list.\n", ListName);
    else
    {
        printf("The list %c is: ", ListName);
        while(currentPtr!=NULL)
        {
            printf("%c ", currentPtr -> symbol);
            currentPtr = currentPtr -> next;
        }
        printf("\n");
    }
    return ;
}
void freeList(NODEPTR *headPtrPtr)
{
    NODEPTR currentPtr, nextPtr;
    currentPtr = (*headPtrPtr);
    while(currentPtr!=NULL)
    {
        nextPtr = currentPtr -> next;
        free(currentPtr);
        currentPtr = nextPtr;
    }
}

结束咯~这次就两道题~轻轻松松~(误)

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值