小白学C语言数据结构之链表(二:例题贴)

前言

链表本身不难,但是题目不一定能做对...

这基本上是一个 例题贴

目前打算每一部分都写三章: 基础贴,例题贴和刷题贴

题目一:快慢指针

输入链表的头节点,奇数长度请返回中点,偶数长度请返回下中点

解法一:数组法!

很容易,先把链表中的数据倒入数组中去,然后遍历数组看数组的size

直接coding

int midReturn(struct Node* head) {
    struct Node* p = head;
    int n = 0;
    while (p != NULL) { // 计算链表长度
        p = p->next;
        n++;
    }
    int* arr = (int*)malloc(n * sizeof(int)); // 创建一个长度为n的数组
    p = head;
    int i = 0;
    while (p != NULL) { // 将链表元素存储到数组中
        arr[i++] = p->value;
        p = p->next;
    }
    int mid;
    if (n % 2 == 0) { // 如果链表长度为偶数,则返回下中间元素
        mid = arr[n / 2 - 1];
    }
    else { // 如果链表长度为奇数,则返回中间元素
        mid = arr[n / 2];
    }
    free(arr); // 释放数组的内存
    return mid;
}

这种方式很容易,但是问题在于:额外空间复杂度较高,所以就可以用到快慢指针的方式

解法二:快慢指针

int midReturn(struct Node* head){
    struct Node* slow = head;      // 慢指针一次走一步
    struct Node* fast = head;      //快指针一次走两步
    //一旦快指针到头了,就返回慢指针的位置
    while(fast != NULL && fast !=NULL){
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow->value;
}

代码easy且额外空间复杂度较小,仅为O(1)

题目二:判断是否回文

回文意思就是

1 2 3 2 1

a b c b a

谁系怀思怀系谁(假装有文化,实际上上网查的

判断一个结构是不是回文结构

解法一:栈方法

头节点开始遍历... 放进栈中去,再依次弹出

coding

// 实现一些栈的基本功能
struct stackNode{
    char data;
    struct stackNode* next;
};
struct Stack{
    struct stackNode* top;
}
void push(struct Stack* stack, char data){
    struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
    newnode-> data = data;
    newnode-> next = stack->top;
    stack-> top = newnode;
}
char pop(struct Stack* stack){
    if(stack->top == NULL){
        return NULL;
    }
    int data = stack->top->data;
    struct stackNode* temp = stack->top;
    stack->top = stack->top->next;
    free(temp);
    return data;
}

//实现主功能
bool huwen(char* str[]){
    int len = strlen(str[0]);
    struct Stack* stack = NULL;
    for(int i = 0; i < len; i++){
        push(&stack, str[0][i]);
    }
    for(int j = 0; j < len; j++){
        if(str[0][j] == pop(&stack)){
            continue;
        }
        else{
            printf("Error");
            return 0;
        }
    }
    return 1;
}

题目三:random指针

题目是这样的,链表的节点中现在除了next指针之外多了一个random指针,可能随机指向任意节点,也可能指向NULL。

给定一个这种带random指针类型的头节点,实现一个函数完成链表的复制,并返回赋值的新链表的head节点

解法一:哈希表

用Hashmap的方式,复制每一个节点放在hashmap中,然后再重构

#include"uthash.h"
struct ListNode{                     // 先定义listnode 其中比常规节点多了一个random指针
    int value; 
    struct ListNode* next;
    struct ListNode* random;
};
struct HashTableNode{        // 定义hashtable 其中key和value都是listnode类型
                                // 因为要靠节点找到节点
    struct ListNode* key;
    struct ListNode* value;
    UT_hash_handle hh;
};

struct ListNode* copyRandomList(struct ListNode* head){
    if(head ==NULL){        //判断空
        return NULL;
    }

    struct HashTableNode* hashmap = NULL; // 建一个空的hashmap
    struct ListNode* newHead  = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* curNode = head;    
    struct ListNode* newNode = newHead;
    
    while(curNode != NULL){            
        newNode->value = curNode->value;
        newNode->next = curNode->next;
        newNode->random = NULL;
        
        struct HashTableNode *hashNode = (struct HashTableNode *)malloc(sizeof(struct HashTableNode));
        hashNode->key = curNode;    // 这样找到curnode就能找到newnode了
        hashNode->value = newNode;
        
        HASH_ADD_PTR(hashmap, key, hashNode);    
        
        curNode = curNode->next;
        if(curNode != NULL){
            newNode->next = (struct ListNode*)malloc(sizeof(struct ListNode));
            newNode = newNode->next;
        }
    }
    newNode->next = NULL; // 对新链表的尾节点的next指针赋值为NULL

    curNode = head;
    newNode = newHead;
    while (curNode) {
        if (curNode->random) {
            struct HashTableNode *hashNode;
            HASH_FIND_PTR(hashmap, &(curNode->random), hashNode);
            newNode->random= hashNode->value;
    }
        curNode = curNode->next; // 将变量名改为curNode
        newNode = newNode->next;
}

// 释放哈希表中的节点
    struct HashTableNode *tmp, *hashNode;
    HASH_ITER(hh, hashmap, hashNode, tmp) {
        HASH_DEL(hashmap, hashNode);
        free(hashNode);
    }

// 释放链表节点和头节点
    curNode = newHead;
    while (curNode) {
        struct ListNode* tmp = curNode;
        curNode = curNode->next;
        free(tmp);
    }

    return newHead;
}

题目四:判断链表是否有环

给定两个可能有环也可以无环的单链表,头节点head1和head2 。判断两节点是否相交,若相交返回第一个交点,不相交返回NULL

HASHMAP!

把链表从头开始遍历,每次都存进hashmap中。

然后查询,如果有重复,就说明形成了环

又有一个问题:如果存在hashmap里,value值应该对应啥?

key已经对应节点了,value没用啊

那就直接少开辟点空间,用hashset

#include "uthash.h"

struct ListNode {
    int val;
    struct ListNode *next;
};
struct HashSet{
    struct ListNode* key;
    UT_hash_handle hh;
};

struct ListNode* returnNode(struct ListNode* head1, struct ListNode* head2){
    if(struct ListNode* head1 =NULL || struct ListNode* head2 = NULL){
        return NULL;
    }

    struct HashSet* hashset = NULL;// 先初始化一个hashset
    struct ListNode* p = head1;
    
    while(p->next != NULL){
        struct HashSet* hashNode = (struct HashSet*)malloc(sizeof(struct HashSet));
        hashNode -> key = p;
        HASH_ADD_PTR(hashset, key, hashNode);
        p = p->next;
    }

    p = head2;
    while(p != NULL){
        struct HashSet* hasNode;
        HASH_FIND_PTR(hashset, &(p), hashNode);
        if(hashNode != NULL){
            return hashNode->key;
        }
        p = p->next;
    }
    return NULL;
}
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值