单链表的头插法和尾插法时间复杂度
时间: 2024-05-06 07:13:01 浏览: 306
单链表是一种常见的数据结构,它由一列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。
头插法和尾插法是两种常见的向单链表中插入节点的方法。
1. 头插法:
头插法是将新节点插入到链表的头部,即将新节点作为链表的第一个节点。具体步骤如下:
- 创建一个新节点,并将要插入的数据赋值给新节点的数据域。
- 将新节点的指针域指向原链表的头节点。
- 将新节点设为链表的头节点。
头插法的时间复杂度为O(1),因为无论链表的长度如何,都只需要进行固定数量的操作。
2. 尾插法:
尾插法是将新节点插入到链表的尾部,即将新节点作为链表的最后一个节点。具体步骤如下:
- 创建一个新节点,并将要插入的数据赋值给新节点的数据域。
- 若链表为空,则将新节点设为链表的头节点。
- 若链表不为空,则找到链表的最后一个节点,将最后一个节点的指针域指向新节点。
尾插法的时间复杂度为O(n),其中n为链表的长度。因为需要遍历整个链表找到最后一个节点。
相关问题
C语言中一个单链表的调用,能同时写头插法和尾插法吗
在C语言中,单链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。头插法和尾插法是链表插入节点的两种不同方式。
头插法是指每次将新节点插入到链表的头部,即每次新节点都将成为链表的第一个节点。这种方法的特点是插入操作的时间复杂度为O(1),因为不需要遍历链表就能完成插入。
尾插法则是在链表的尾部添加新节点,即在链表的最后一个节点之后。这种方法的特点是需要先遍历到链表的尾部才能插入新节点,因此时间复杂度为O(n),其中n是链表的长度。
通常情况下,一个单链表结构一次只能高效地支持头插法或者尾插法中的一种。如果要同时支持两种插入方式,需要在链表的结构中同时维护头指针和尾指针。这样在头插法时可以直接修改头指针指向新节点,在尾插法时则可以在尾指针指向的节点上添加新节点,然后更新尾指针。
以下是单链表结构和头尾插法的简化示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点结构体
typedef struct Node {
int data;
struct Node* next;
} Node;
// 初始化链表,创建头节点
Node* initList() {
Node* head = (Node*)malloc(sizeof(Node));
if (head != NULL) {
head->next = NULL;
}
return head;
}
// 头插法插入节点
void insertAtHead(Node* head, int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode != NULL) {
newNode->data = data;
newNode->next = head->next;
head->next = newNode;
}
}
// 尾插法插入节点
void insertAtTail(Node* head, int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (newNode != NULL) {
newNode->data = data;
newNode->next = NULL;
Node* current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
}
int main() {
Node* list = initList();
insertAtHead(list, 10); // 头插法
insertAtTail(list, 20); // 尾插法
// ... 链表操作
return 0;
}
```
编写一个程序Split_你的名字拼音全拼.c,已给定值x为基准将单链表分割为两部分, 所有小于x的结点排在大于或等于x的结点之前,并进行时间复杂度的分析。 提示:利用单链表头插法和尾插法建表实现。
首先,我将以"王五"为例,编写一个名为`Split_Wangwu.c`的程序,该程序会接收用户输入的一个整数`x`作为基准,然后将链表中的节点按照大小关系分为两部分:小于`x`的节点放在大于等于`x`的节点前面。
```c
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node* next;
} Node;
Node* createNode(int val) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->value = val;
newNode->next = NULL;
return newNode;
}
// 插入节点到链表的头部
void insertAtHead(Node** head, int val) {
Node* newNode = createNode(val);
newNode->next = *head;
*head = newNode;
}
// 插入节点到链表的尾部
void insertAtTail(Node** head, int val) {
Node* newNode = createNode(val);
if (*head == NULL) {
*head = newNode;
} else {
Node* temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
}
// 分割链表并返回两个新的链表头部
Node** splitList(Node* head, int x) {
Node* smaller_head = NULL;
Node* larger_head = NULL;
Node* current = head;
while (current != NULL) {
if (current->value < x) {
insertAtHead(&smaller_head, current->value);
} else {
insertAtTail(&larger_head, current->value);
}
current = current->next;
}
return (Node**)malloc(sizeof(Node*) * 2); // 分配空间保存两个链表头部
}
int main() {
int x, input;
printf("请输入一个整数x: ");
scanf("%d", &x);
Node* list = NULL; // 示例链表,可以自定义生成
// ...(这里添加链表初始化和填充数据)
Node** result = splitList(list, x);
printf("分割后的链表如下:\n");
Node* smaller_list = result[0];
while (smaller_list != NULL) {
printf("%d ", smaller_list->value);
smaller_list = smaller_list->next;
}
printf("\n");
Node* larger_list = result[1];
while (larger_list != NULL) {
printf("%d ", larger_list->value);
larger_list = larger_list->next;
}
printf("\n");
free(result); // 释放内存
return 0;
}
```
时间复杂度分析:
- 创建节点的时间复杂度为O(1),因为固定大小的结构体。
- 在`splitList`函数中,遍历整个链表一次,所以时间复杂度为O(n),其中n为链表长度。插入操作(头插法和尾插法)都是常数时间操作,不会影响总时间复杂度。
总的来说,这个程序的时间复杂度是线性的。
阅读全文