# 数据结构之单链表
5 min read
Table of Contents
链表是线性表里常见的数据结构,不需要连续存储到内存中。每一个结点都包括了存储数据的结点 data 以及指向下一个结点的指针 next。
在单链表有两个特殊的结点,分别是头结点和尾结点。头结点用来记录链表的基地址,用来遍历整条链表。而尾结点是指向空地址 NULL,代表链表上最后一个结点。
插入,删除与遍历
单链表的一个优点就是无需确定内存大小,方便插入与删除。因为在链表的插入与删除操作中,我们不需要搬移结点,只需要改变相邻的结点的指针。时间复杂度是 O(1)。
链表必须从头开始依次遍历查询,如果需要随机访问第 k 个元素,则无法根据首地址和下标,通过寻址公式计算出对应的内存地址,而是需要根据指针一个个结点依次遍历,直到找到对应的结点。时间复杂度是 O(n)。
C 中的表示
在 C 中我们可以用结构体表示结点,以下是一个带整数的链表结点的示例
// 一个链表结点struct Node { int data; struct Node *next;}// 简单的列表遍历void printList(struct Node* head) { while (head != NULL) { printf(" %d ", head->data); head = head->next; }}// 创建新结点node createNode() { struct Node* temp = (struct Node*)malloc(sizeof(struct Node)); temp->next = NULL; return temp;}// 添加结点--在前面添加结点void push(struct Node **head, int data) { struct Node* temp = (struct Node*)malloc(sizeof(struct Node)); temp->data = data; temp->next = (*head); (*head) = temp;}
// 添加结点--在指定元素后面添加添加结点void insertAfter(struct Node* prev, int data) { if (prev == NULL) { printf("the previous node connot be NULL"); return; } struct Node* temp = (struct Node*)malloc(sizeof(struct Node)); temp->data = data; temp->next = prev->next; prev->next = temp;}
// 添加结点--在末尾添加结点void append(struct Node **head, int data) { struct Node* temp = (struct Node*)malloc(sizeof(struct Node)); struct Node *last = *head; temp->data = data; temp->next = NULL; if(*head==NULL) { *head = temp; return; } while (last->next != NULL) { last = last->next; } last->next = temp; return;}// 删除结点--根据指定的值void deleteNode(struct Node **head, int key) { struct Node* temp = *head, *prev; if (temp != NULL && temp->data == key) { *head = temp->next; free(temp); return; } while(temp != NULL && temp->data != key) { prev = temp; temp = temp->next; } if (temp == NULL) return; prev->next = temp->next; free(temp);}
// 删除结点--根据指定的位置void deleteNode(struct Node **head, int position) { if (**head == NULL) return; struct Node* temp = *head; if (position == 0) { *head = temp -> next; free(temp); return; } for(int i=0; temp!=NULL && i<position-1; i++) { temp = temp->next; } if(temp == NULL || temp->next == NULL) { return; } struct Node *next = temp->next->next; free(temp->next); temp->next = next;}// 删除链表void deleteList(struct Node** head) { struct Node* current = *head; struct Node* next; while(current != NULL) { next = current->next; free(current); current = next; } *head = NULL;}// 返回单链表的长度void listLength() { int length = 0; struct Node* current = head; while(current != NULL) { length++; current = current->next; } return length;}// 查找链表是否有值key,有的话返回true,否则返回falsebool search(struct Node* head, int key) { struct Node* current = head; while(current != NULL) { if (current->data == key) return true; current = current->next; } return false;}// 获取指定位置的值,否则返回错误int getNode(struct Node* head, int index) { struct Node* current = head; int count = 0; while(current != NULL) { if (count == index) return (current->data); count++; current = current->next; } assert(0);}