您的位置:首页 > 文旅 > 美景 > 企业网站自助建站上海_软件工程学什么课程_少儿编程培训机构排名前十_盐城seo培训

企业网站自助建站上海_软件工程学什么课程_少儿编程培训机构排名前十_盐城seo培训

2024/12/24 4:01:09 来源:https://blog.csdn.net/m0_46190471/article/details/144556116  浏览:    关键词:企业网站自助建站上海_软件工程学什么课程_少儿编程培训机构排名前十_盐城seo培训
企业网站自助建站上海_软件工程学什么课程_少儿编程培训机构排名前十_盐城seo培训

本文目录

  • 前置
  • 反转单向链表
    • 描述
    • 示例1
    • 示例2
    • Solution
    • 代码解释
      • 步骤 1:初始化
      • 步骤 2:处理 `2`
      • 步骤 3:处理 `3`
      • 步骤 4:处理 `4`
      • 步骤 5:处理 `5`
      • 图示
  • 链表内指定区间反转
    • 描述
    • 示例1
    • 示例2
    • Solution

前置

定义一个结构体,如下:

typedef struct node {int data;    //节点中的数据struct node *next;     //struct node 类型的指针
} Node;    //typedef 定义的别名为 Node

使用 malloc() 来为结构体申请内存,如下:

Node *head = (Node*)malloc(sizeof(Node));
head->data = 1;//为数据赋值
head->next = NULL;

我们多次使用 malloc() 函数来申请 Node 结构体大小的内存,并将所有的 Node 节点通过 next 指针连起来。这样就可以得到一个链表,由于所有的节点都指向下一个节点,所以它是单向的,这样链表被称为单向链表。head 保存了第一个节点的内存地址,通过 head 我们就可以遍历所有的 Node 节点。最后一个节点的 next 指针赋值为 NULL 作为链表的结束标志。所有节点的内存地址在内存中不一定就是连续的,它是通过指针赋值地址的方式将所有的节点连在一起的。

删除节点时,要 free(节点内存地址) 释放对应节点的内存地址,释放前要确保节点指针的断开与连接,以免造成节点丢失的问题。


完整单向链表示例:

#include <stdio.h>
#include <stdlib.h>// 定义链表节点
struct Node {int data;           // 节点存储的数据struct Node* next;  // 指向下一个节点的指针
};// 创建新节点
struct Node* createNode(int data) {struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));newNode->data = data;newNode->next = NULL;return newNode;
}// 在头节点前面插入新节点
void insertAtHead(struct Node** head, int data) {       //struct Node **head 二级指针,指向指针的指针,如果传入 head 一级指针,我们只能修改 head 指向的内容,而无法修改指针本身,传入二级指针可以修改 head 指针本身/*指针的本质是一个变量,变量里面保存的是一个内存地址。一级指针 head 保存的是链表第一个 Node 节点的内存地址。二级指针是 head 这个变量的内存地址,*head 赋值新创建的节点的内存地址。*/struct Node* newNode = createNode(data);newNode->next = *head;*head = newNode;
}//在链表末尾添加节点
void insertAtTail(struct Node** head, int data) {struct Node* newNode = createNode(data);if (*head == NULL) {*head = newNode;} else {struct Node* temp = *head;while (temp->next != NULL) {temp = temp->next;}temp->next = newNode;}
}//删除头节点
void deleteAtHead(struct Node** head) {if (*head == NULL) {printf("List is empty.\n");return;}struct Node* temp = *head;*head = (*head)->next;free(temp);
}//删除指定节点
void deleteNode(struct Node** head, int data) {if (*head == NULL) {printf("List is empty.\n");return;}struct Node* temp = *head;// 如果要删除的是头节点if (temp->data == data) {*head = temp->next;free(temp);return;}// 查找要删除的节点while (temp->next != NULL && temp->next->data != data) {temp = temp->next;}// 如果找到要删除的节点if (temp->next != NULL) {struct Node* toDelete = temp->next;temp->next = temp->next->next;free(toDelete);} else {printf("Node with data %d not found.\n", data);}
}//打印所有节点
void printList(struct Node* head) {if (head == NULL) {printf("List is empty.\n");return;}struct Node* temp = head;while (temp != NULL) {printf("%d -> ", temp->data);temp = temp->next;}printf("NULL\n");
}//销毁链表
void destroyList(struct Node* head) {while (head != NULL) {struct Node* temp = head;head = head->next;free(temp);}
}int main() {struct Node* head = NULL;  // 初始化空链表// 插入节点insertAtHead(&head, 10);insertAtHead(&head, 20);insertAtTail(&head, 30);insertAtTail(&head, 40);// 打印链表printf("Linked list: ");printList(head);// 删除节点deleteNode(&head, 20);  // 删除值为 20 的节点printf("After deleting 20: ");printList(head);deleteAtHead(&head);  // 删除头节点printf("After deleting head: ");printList(head);// 销毁链表destroyList(head);return 0;
}



反转单向链表

  • 原题链接 反转链表 https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=295&tqId=23286&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
  • 难度【简单】

描述

给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

数据范围: 0 ≤ n ≤ 1000 0≤n≤1000 0n1000

要求:空间复杂度 O(1) ,时间复杂度 O(n)。

如当输入链表{1,2,3}时,

经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。

以上转换过程如下图所示:

在这里插入图片描述

示例1

输入:

{1,2,3}

返回值:

{3,2,1}

示例2

输入:

{}

返回值:

{}

说明:

空链表则输出空                 

Solution

对于单向链表的反转,关键点在在于正确处理节点的断开与连接。

而节点的断开与连接,关键点在于正确处理节点 next 指针的赋值。

在处理链表反转时,要注意不要丢失节点的指针。

代码很短很简单,但是在逻辑上要格外注意指针的赋值,以免丢失节点。

/*** struct ListNode {*	int val;*	struct ListNode *next;* };*/
/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param head ListNode类 * @return ListNode类*/
struct ListNode* ReverseList(struct ListNode* head ) {struct ListNode *pre = NULL, *cur = head, *nxt = NULL;while (cur) {nxt = cur->next;cur->next = pre;pre = cur;cur = nxt;}return pre;
}

时间复杂度 O(n),一次 while 循环整个链表。

空间复杂度 O(1)。

代码解释

步骤 1:初始化

pre = NULL, cur = head (1), nxt = NULL

链表结构:

NULL <- 1 -> 2 -> 3 -> 4 -> 5 -> NULL
  • nxt = cur->nextnxt = 2
  • cur->next = pre,将 1->next 指向 NULL
  • pre = curpre 移动到 1
  • cur = nxtcur 移动到 2

步骤 2:处理 2

pre = 1, cur = 2, nxt = NULL

链表结构:

NULL <- 1 <- 2 -> 3 -> 4 -> 5 -> NULL
  • nxt = cur->nextnxt = 3
  • cur->next = pre,将 2->next 指向 1
  • pre = curpre 移动到 2
  • cur = nxtcur 移动到 3

步骤 3:处理 3

pre = 2, cur = 3, nxt = NULL

链表结构:

NULL <- 1 <- 2 <- 3 -> 4 -> 5 -> NULL
  • nxt = cur->nextnxt = 4
  • cur->next = pre,将 3->next 指向 2
  • pre = curpre 移动到 3
  • cur = nxtcur 移动到 4

步骤 4:处理 4

pre = 3, cur = 4, nxt = NULL

链表结构:

NULL <- 1 <- 2 <- 3 <- 4 -> 5 -> NULL
  • nxt = cur->nextnxt = 5
  • cur->next = pre,将 4->next 指向 3
  • pre = curpre 移动到 4
  • cur = nxtcur 移动到 5

步骤 5:处理 5

pre = 4, cur = 5, nxt = NULL

链表结构:

NULL <- 1 <- 2 <- 3 <- 4 <- 5 -> NULL
  • nxt = cur->nextnxt = NULL(最后一个节点)。
  • cur->next = pre,将 5->next 指向 4
  • pre = curpre 移动到 5
  • cur = nxtcur 变为 NULL,退出循环。

图示

步骤precurnxt当前链表状态
初始NULL1NULL1 -> 2 -> 3 -> 4 -> 5 -> NULL
步骤 1122NULL <- 1 -> 2 -> 3 -> 4 -> 5 -> NULL
步骤 2233NULL <- 1 <- 2 -> 3 -> 4 -> 5 -> NULL
步骤 3344NULL <- 1 <- 2 <- 3 -> 4 -> 5 -> NULL
步骤 4455NULL <- 1 <- 2 <- 3 <- 4 -> 5 -> NULL
步骤 55NULLNULL5 -> 4 -> 3 -> 2 -> 1 -> NULL




链表内指定区间反转

  • 原题链接:链表内指定区间反转:https://www.nowcoder.com/practice/b58434e200a648c589ca2063f1faf58c?tpId=295&tqId=654&ru=/exam/oj&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
  • 难度【中等】

描述

将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n),空间复杂度 O(1)。
例如:
给出的链表为 1→2→3→4→5→NULL, m=2,n=4,
返回 1→4→3→2→5→NULL.

数据范围: 链表长度 0<size≤1000,0<m≤n≤size,链表中每个节点的值满足 ∣val∣≤1000

要求:时间复杂度 O(n)) ,空间复杂度 O(n)

进阶:时间复杂度 O(n),空间复杂度 O(1)

示例1

输入:

{1,2,3,4,5},2,4

返回值:

{1,4,3,2,5}

示例2

输入:

{5},1,1

返回值:

{5}

Solution

在 head 节点前面加上一个辅助节点,可以方便反转操作。代码有注释:

/*** struct ListNode {*	int val;*	struct ListNode *next;* };*/
/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param head ListNode类 * @param m int整型 * @param n int整型 * @return ListNode类*/
struct ListNode* reverseBetween(struct ListNode* head, int m, int n ) {if(!head || m == n) return head;   //head为空或 m=n 则直接返回 headstruct ListNode *start = (struct ListNode*)malloc(sizeof(struct ListNode));start->next = head;   //在head前面添加一个节点 startstruct ListNode *revPre = start;   for (int i = 0; i < m - 1; i++)   //找到第m个节点的前一个节点 revPrerevPre = revPre->next;struct ListNode *rev = revPre->next;   //rev 第m个节点struct ListNode *tmp = NULL;   // 临时指针for (int i = m; i < n; i++) {tmp = rev->next;   // 保存第m+1个节点的地址rev->next = tmp->next;      //第m个节点指向第m+2个节点tmp->next = revPre->next;      //第m+1个节点指向需要反转的第一个节点mrevPre->next = tmp;      //第m节点指向第m+1节点}tmp = start->next;    // tmp 保存反转后的 headfree(start);    //释放辅助的节点 start 的内存空间return tmp;    //返回 head
}

提交代码:过辣!!!

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com