基础数据结构及算法练习1:链表

1. 力扣21: 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
在这里插入图片描述
解题:
方法一
用归并的方式给链表排序

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
	//如果一个空的,返回另一个数组
    if(NULL == l1) return l2;
    if(NULL == l2) return l1;
    struct ListNode* head = NULL;
    struct ListNode* tail = NULL;
    struct ListNode* p = l1;
    struct ListNode* q = l2;
    //如果两个数组都没空,则排序
    while(NULL != p && NULL !=q){
        if(p->val < q->val){
        	//考虑第一个数据插入的情况
            if(NULL == head){
                head = p;
            }else{
                tail->next = p;
            }
            tail = p;
            p = p->next;
        }else{
            if(NULL == head){
                head = q;
            }else{
                tail->next = q;
            }
            tail = q;
            q = q->next;
        }
    }
    //如果哪个数组没空,就把这个数组剩下的全放进来
    if(NULL != p) tail->next = p;
    if(NULL != q) tail->next = q;
    return head;
}

方法二
为了不考虑头指针为空的情况,我们直接加一个头节点

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if(NULL == l1) return l2;
    if(NULL == l2) return l1;
    struct ListNode dump = {0,NULL};
    struct ListNode* tail = &dump;
    struct ListNode* p = l1;
    struct ListNode* q = l2;
    while(NULL != p && NULL !=q){
        if(p->val < q->val){
            tail->next = p;
            tail = p;
            p = p->next;
        }else{
            tail->next = q;
            tail = q;
            q = q->next;
        }
    }
    if(NULL != p) tail->next = p;
    if(NULL != q) tail->next = q;
    return dump.next;    //返回的是一个指针
}

方法三
可以不用 p 和 q ,直接使用 l1 和 l2 ,删掉重复的判断,减少代码量

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    struct ListNode dump = {0,NULL};
    struct ListNode* tail = &dump;
    while(NULL != l1 && NULL != l2){
        struct ListNode* cur = l1->val < l2->val ? l1:l2;
        tail->next = cur;
        tail = cur;
        if(l1->val < l2->val){
            l1 = l1->next;
        }else{
            l2 = l2->next;
        }
    }
    if(NULL != l1) tail->next = l1;
    if(NULL != l2) tail->next = l2;
    return dump.next;
}

方法四
换个思路,用递归的方式,返回的都是地址

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
        if (NULL == l1) return l2;
        if (NULL == l2) return l1;
        if(l1->val < l2->val){
                l1->next = mergeTwoLists(l1->next,l2);
                return l1;
        }else{
                l2->next = mergeTwoLists(l1,l2->next);
                return l2;
        }
}

2. 力扣237: 删除链表中的节点

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为要被删除的节点
在这里插入图片描述

解题:
我们不知道要删除的前一个节点,而是当前节点,并且这个节点不是尾节点
我们可以把该结点后面结点的数据移过来,再删除后面的结点
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
void deleteNode(struct ListNode* node) {
        if(NULL == node || NULL == node->next) return;

        struct ListNode* next = node->next;     //定义一个指针next,指向当前结点的下一个结点
        node->val = next->val;               //把下一个结点的值赋给当前结点
        node->next = next->next;         //把当前结点的指针域指向下下结点的地址
        free(next);                   //释放下一个结点
}

3. 力扣24:两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换
在这里插入图片描述

解题:

递归写法:
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* swapPairs(struct ListNode* head){
    if(NULL == head) return NULL;
    if(NULL == head->next) return head;

    struct ListNode* p = head;
    struct ListNode* q = head->next;
    p->next = swapPairs(q->next);
    q->next = p;
    return q;
}

4. 力扣19:删除链表的倒数第N个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
在这里插入图片描述

解题:
方法一
用传统的方法,找到要删除对象的前一个数

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
        if(NULL == head || n<0) return head;
        int size = 0;
        struct ListNode* p =head;
        while(NULL != p){
                ++size;
                p = p->next;
        }

        //如果删除的是头结点
        if(n == size){
                p = head->next;
                free(head);
                return p;
        }

        int index = size - n;
        p = head;
        for(int i=0;i<index-1;++i){  //找到要删除结点的前一个结点
                p = p->next;
        }
        struct ListNode* del = p->next;
        p->next = del->next;
        free(del);

        return head;
}

方法二
再前面增加一个空结点,可以不考虑删除头结点的情况

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
        if(NULL == head || n<0) return head;
        int size = 0;
        struct ListNode dump = {0,head};
        struct ListNode* p = head;
        while(NULL != p){
                ++size;
                p = p->next;
        }

        int index = size - n;
        p = &dump;
        for(int i=0;i<index;++i){  //找到要删除结点的前一个结点
                p = p->next;
        }
        struct ListNode* del = p->next;
        p->next = del->next;
        free(del);

        return dump.next;
}

方法三
另一种思维:
定义p和q都在链表头,p先跑n,再p和q一起跑,p到最后时,q所在位置就是要删除位置的前一个位置
在这里插入图片描述

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    if(NULL == head || n<0) return head;
    
    struct ListNode dump = {0,head};
    struct ListNode* p = &dump;
    for(int i=0;i<n;++i){
        p = p->next;
    }
    struct ListNode* q = &dump;
    while(NULL != p->next){
        p = p->next;
        q = q->next;
    }

    struct ListNode* del = q->next;
    q->next = del->next;
    free(del);
    return dump.next;
}

方法四
使用递归的方式,在归的时候删除
需要新建一个函数用于递归

int NthFromEnd(struct ListNode* head,int n){    //返回是倒数第几个数
    if(NULL == head) return 0;
    if(NULL == head->next) return 1;
    int nextNth = NthFromEnd(head->next,n);
    if(nextNth == n){
        struct ListNode* del = head->next;     //head是要找的前一个结点
        head->next = del->next;
        free(del);
    }
    return nextNth+1;
}

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    if(NULL == head || n<0) return head;

    struct ListNode dump = {0,head};
    NthFromEnd(&dump,n);
    return dump.next;
}

方法五
用栈的方法来删除会更简单,第n个出栈的删除就可以完成

typedef struct ListNode* Element;
typedef struct Node{
        Element e;
        struct Node* next;
}Node;

typedef struct Stack{
        Node* header;
        size_t size;
}Stack;

//创建
Stack* Create(){
        Stack* s = malloc(sizeof(Stack));
        s->header = NULL;
        s->size = 0;
        return s;
}

//销毁
void Destory(Stack** s){
        if(NULL == s) return;
        if(NULL == *s) return;

        Node* p = (*s)->header;
        while(NULL!=p){
                Node* del = p;
                p = p->next;
                free(del);
        }
        free(*s);
        *s = NULL;
}

//栈长度
size_t GetSize(Stack* s){
        return s->size;
}

//入栈
bool Push(Stack* s,Element e){
        if(NULL == s) return false;
        Node* p = malloc(sizeof(Node));
        p->e = e;
        p->next = s->header;
        s->header = p;
        s->size++;
        return true;
}

//出栈
bool Pop(Stack* s){
        if(NULL == s) return false;
        if(NULL == s->header) return false;
        s->size--;
        Node* del = s->header;
        s->header = del->next;
        free(del);
        return true;
}

//头指针
Element* Top(Stack* s){
        if(NULL == s) return NULL;
        if(NULL == s->header) return NULL;
        return &(s->header->e);
}

int NthFromEnd(struct ListNode* head,int n){    //返回是倒数第几个数
    if(NULL == head) return 0;
    if(NULL == head->next) return 1;
    int nextNth = NthFromEnd(head->next,n);
    if(nextNth == n){
        struct ListNode* del = head->next;     //head是要找的前一个结点
        head->next = del->next;
        free(del);
    }
    return nextNth+1;
}

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    if(NULL == head || n<0) return head;

    struct ListNode dump = {0,head};
    // NthFromEnd(&dump,n);
    Stack* s = Create();

    struct ListNode* p = &dump;
    while(NULL != p){
        Push(s,p);
        p = p->next;
    }
    for(int i=0;i<n;++i){
        Pop(s);
    }
    p = *Top(s);
    struct ListNode* del = p->next;
    p->next = del->next;
    free(del);

    Destory(&s);
    return dump.next;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值