数据结构代码集训day7(适合考研、自学、期末和专升本)

习题来自B站up:白话拆解数据结构


单链表结构体看这里icon-default.png?t=N7T8https://blog.csdn.net/m0_61522765/article/details/141536639?spm=1001.2014.3001.5501

今日题目如下:

(1)将单链表就地逆置(补昨天的)

(2)删除带头结点的单链表L中的最小值。

(3)删除带头结点的单链表L中所有值为x的结点,并释放其内存空间。


题1

        法一:可以采用昨天的头插法,首先将头结点摘下来,然后将后面的结点一个个头插到头结点后面。

Linklist list_reverstbyhead(Linklist &L){

    Lnode *p,*r;

    p=L->next;

    L->next=NULL;        // 摘下头结点

    while(p){

        r=p->next;

        p->next=L->next;

        L->next=p;

        p=r;

    }

    return L;

}

实践一下:成功!

 

        法二:三指针法,这个有点不好想,但其实也还好,可以自己动手画一下。首先需要这样的三个指针:

        然后我们改变2的指针域,让2指向1,再把1的指针域置空(因为1结点是表尾结点):

        记得将L的指针域也置空,因为L的指针域最后要指向新的表头结点;然后我们把p,q,r向后面移动,继续这样操作就行了!

// 法二:三指针法

Linklist three_zhizhen(Linklist &L){

    Lnode *p,*q,*r=NULL;

    p = L->next;

    q = p->next;

    L->next = NULL; //摘下头节点

    p->next = NULL;

    while(q!=NULL){

        r=q->next;

        q->next = p;

        p=q;

        q=r;

    }

    L->next= p;

    return L;

}

        注意r指针的赋值要在while循环里,他要后赋值,指向q的next,如果让r指针和后面俩指针一起移动,就会出现当q指向最后一个结点时,r已经指向空了,此时判断条件是q不指向空,所以还要往下走一轮,r再往下走就会报错!

实践一下:成功!

完整代码如下:(在vscode环境下已跑通)

#include <iostream>
#include <cstdio>
#include <ctime>
using namespace std;

// 单链表结构体定义
typedef struct Lnode{
    int data;
    Lnode *next;
}Lnode,*Linklist;

Linklist list_insertbytail(Linklist &L){
    if (L == NULL || L->next == NULL) return L;
    Lnode *s;
    int x;
    L = (Lnode*)malloc(sizeof(Lnode));
    L->next = NULL;
    Lnode *r = L;
    cin >> x;
    while(x!=9999){
        s = (Lnode*)malloc(sizeof(Lnode));
        s->data=x;
        s->next=NULL;

        r->next = s;
        r=r->next;
        cin >> x;
    }
    return L;
}


// 链表就地逆置

//法一:头插法
Linklist list_reverstbyhead(Linklist &L){
    Lnode *p,*r;
    p=L->next;
    L->next=NULL;
    while(p){
        r=p->next;
        p->next=L->next;
        L->next=p;
        p=r;
    }
    return L;
}

// 法二:三指针法
Linklist three_zhizhen(Linklist &L){
    Lnode *p,*q,*r=NULL;
    p = L->next;
    q = p->next;
    L->next = NULL; //摘下头节点
    p->next = NULL;
    while(q!=NULL){
        r=q->next;
        q->next = p;
        p=q;
        q=r;
    }
    L->next= p;
    return L;
}

int main(){
    Linklist L;
    // list_insertbyhead(L);
    list_insertbytail(L);
    Lnode *p = L->next;
    printf("origin list:");
    while (p != NULL) {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");
    
    printf("reverse list:");
    list_reverstbyhead(L);
    // three_zhizhen(L); 
    Lnode *q = L->next;
    while (q != NULL) {
        printf("%d-> ",q->data);
        q = q->next;
    }
    printf("NULL");
    return 0;
}


题2:

         删除最小值,首先就要找到最小值,其实这个找最小值的过程和顺序表差不多,也是需要一个temp变量来记录,然后遍历比较,更新temp中的值

Lnode *p,*q;

    p=L;

    q=L->next;

    int temp=q->data;

    while(q!=NULL){

        if(q->data<temp)

        {

            temp = q->data;

            p=p->next;

            q=q->next;

        }

            p=p->next;

            q=q->next;

    }

        只是找到了还不够,我们还要删除这个最小值结点,所以我们还需要两个指针变量,一个记录最小值结点的位置,一个记录最小值前驱的位置,因为删除操作需要知道结点的前驱。注意,这两个指针只在要更新temp值的时候更新指向,其他时候指向不变

 

Linklist delete_min(Linklist &L){

    if (L == NULL || L->next == NULL) return L;

    Lnode *p,*q,*min_pre=NULL,*minp=NULL;

    p=L;

    q=L->next;

    int temp=q->data;

    while(q!=NULL){

        if(q->data<temp)

        {

            min_pre = p;        // 前驱

            minp=q;        // 最小值结点

            temp = q->data;

            p=p->next;

            q=q->next;

        }

            p=p->next;

            q=q->next;

    }

    // 删除最小值节点

    if (minp == L->next) {  // 如果最小值节点是第一个节点

        L->next = minp->next;

    } else {

        min_pre->next = minp->next;

    }

    return L;

}

实践:成功删掉了最小值2.

 

完整代码如下:

#include <iostream>
#include <cstdio>
#include <ctime>
using namespace std;

// 单链表结构体定义
typedef struct Lnode{
    int data;
    Lnode *next;
}Lnode,*Linklist;

Linklist list_insertbytail(Linklist &L){
    Lnode *s;
    int x;
    L = (Lnode*)malloc(sizeof(Lnode));
    L->next = NULL;
    Lnode *r = L;
    cin >> x;
    while(x!=9999){
        s = (Lnode*)malloc(sizeof(Lnode));
        s->data=x;
        s->next=NULL;

        r->next = s;
        r=r->next;
        cin >> x;
    }
    return L;
}

// 删除带头节点的单链表L中最小值(最小值唯一)
Linklist delete_min(Linklist &L){
    if (L == NULL || L->next == NULL) return L; 
    Lnode *p,*q,*min_pre=NULL,*minp=NULL;
    p=L;
    q=L->next;
    int temp=q->data;
    while(q!=NULL){
        if(q->data<temp)
        {
            min_pre = p;
            minp=q;
            temp = q->data;
            p=p->next;
            q=q->next;
        }
            p=p->next;
            q=q->next;
    }
    // 删除最小值节点
    if (minp == L->next) {  // 如果最小值节点是第一个节点
        L->next = minp->next;
    } else {
        min_pre->next = minp->next;
    }
    return L;
}


int main(){
    Linklist L;
    // list_insertbyhead(L);
    list_insertbytail(L);
    Lnode *p = L->next;
    printf("origin list:");
    while (p != NULL) {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");
    delete_min(L);
    printf("new list:");

    Lnode *q = L->next;
    while (q != NULL) {
        printf("%d-> ",q->data);
        q = q->next;
    }
    printf("NULL");
    return 0;
}


题 3:

        法一:需要两个指针,一个指向值为x结点的前驱,一个指向x结点;当遍历到结点data为x的时候,指向删除操作,不为x的时候,两个指针就向后移

Linklist del_allx(Linklist &L,int x){

    if (L == NULL) return L;

    Lnode *p,*q;

    p=L;

    q=L->next;

    while (q != NULL) {

        if (q->data == x) {

            // 删除节点 q

            p->next = q->next;

            free(q);

            q = p->next;    // 更新 q 为删除后的下一个节点

        } else {

            // 如果当前节点不需要删除,继续遍历

            p = q;

            q = q->next;

        }

    }

    return L;

}

实践:x=3

        

        法二:尾插的思想,将data不为x的结点重新尾插到L后面,可以当成新表来看待!

Linklist del_allx2(Linklist &L, int x) {

    if (L == NULL) return L;  // 如果链表为空,直接返回

    Lnode *p = L;          

    Lnode *q = L->next;      

    while (q != NULL) {

        if (q->data != x) {

            p->next = q;      // 当前节点不需要删除

            p = p->next;      // 更新 p

        } else {

            Lnode *temp = q;  // 保存要删除的节点

            q = q->next;      // 更新 q

            free(temp);      

            continue;         // 跳过

        }

        q = q->next;

    }

   

    // 处理最后一个节点的 next,确保链表的末尾指向 NULL

    p->next = NULL;

    return L;

}

        这里的continue不能省略,如果省略会造成q一次走两步,会出错! 

实践:x=4

完整代码如下:

#include <iostream>
#include <cstdio>
#include <ctime>
using namespace std;

// 单链表结构体定义
typedef struct Lnode{
    int data;
    Lnode *next;
}Lnode,*Linklist;

Linklist list_insertbytail(Linklist &L){
    Lnode *s;
    int x;
    L = (Lnode*)malloc(sizeof(Lnode));
    L->next = NULL;
    Lnode *r = L;
    cin >> x;
    while(x!=9999){
        s = (Lnode*)malloc(sizeof(Lnode));
        s->data=x;
        s->next=NULL;

        r->next = s;
        r=r->next;
        cin >> x;
    }
    return L;
}


//带头节点链表L中,删除所有值为x的节点并释放其内存空间(x不唯一)
Linklist del_allx(Linklist &L,int x){
    if (L == NULL) return L; 
    Lnode *p,*q;
    p=L;
    q=L->next;

    while (q != NULL) {
        if (q->data == x) {
            // 删除节点 q
            p->next = q->next;
            free(q);
            q = p->next;    // 更新 q 为删除后的下一个节点
        } else {
            // 如果当前节点不需要删除,继续遍历
            p = q;
            q = q->next;
        }
    }
    return L;
}

//法二:将头节点断开,将不为x的元素重新接上去
Linklist del_allx2(Linklist &L, int x) {
    if (L == NULL) return L;  // 如果链表为空,直接返回

    Lnode *p = L;          
    Lnode *q = L->next;       
    while (q != NULL) {
        if (q->data != x) {
            p->next = q;      // 当前节点不需要删除
            p = p->next;      // 更新 p 
        } else {
            Lnode *temp = q;  // 保存要删除的节点
            q = q->next;      // 更新 q 
            free(temp);       
            continue;         // 跳过
        }
        q = q->next;
    }
    
    // 处理最后一个节点的 next,确保链表的末尾指向 NULL
    p->next = NULL;

    return L;
}

int main(){
    Linklist L;
    // list_insertbyhead(L);
    list_insertbytail(L);
    Lnode *p = L->next;
    printf("origin list:");
    while (p != NULL) {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");

    del_allx2(L,4);
    printf("new list:");

    Lnode *q = L->next;
    while (q != NULL) {
        printf("%d-> ",q->data);
        q = q->next;
    }
    printf("NULL");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值