1. 单链表的基本形式
2. 链表节点的结构体
需要注意 typedef 可以将结构体重命名。此外,单链表由数据域和指针域组成。
// 节点结构体
typedef struct ListNode{
int value;
struct ListNode* next;
}ListNode;
3. 创建单链表节点
申请空间后,需要对空间进行判断,确保空间申请成功。
// 创建节点
ListNode* CreateNode(int value){
// 申请空间
ListNode * node = malloc(sizeof(ListNode));
// 申请空间失败
if(!node) exit(1);
node->value = value;
node->next = NULL;
return node;
}
4. 销毁单链表节点
销毁节点时,需要注意的是节点指针也要置为NULL,所以在函数传参时,需要将节点指针的指针传入函数,这样才能修改节点指针的值。
// 销毁节点,需要注意的是,节点的指针也要在函数中置为NULL,所以要传入节点指针的指针
void DestroyNode(ListNode** node_ptr){
// 节点的操作
(*node_ptr)->next = NULL;
free(*node_ptr);
// 节点指针置NULL
*node_ptr = NULL;
}
5. 创建单链表
注意,代码默认头结点的数据域无效,所以头结点的下一节点才开始存储传入的参数。
// 创建单链表
ListNode *CreateList(int array[], int length){
if(length <= 0) return 0;
// 创建头结点
ListNode *head = CreateNode(0);
ListNode *cur = head;
for (int i = 0; i < length; ++i) {
cur->next = CreateNode(array[i]);
cur = cur->next;
}
return head;
}
6. 销毁单链表
由于销毁单独节点时,需要将节点指针置为NULL,故此处也传入二维指针。特别注意的是,头结点指针也要置为NULL,不能忘记。
// 销毁单链表, 由于节点指针需要置为NULL,传入二维指针
void DestroyList(ListNode **head){
// 如果节点指针不存在或者节点指针的指针不存在,直接退出
if(!head || !(*head)) return;
ListNode *cur = *head;
// 移动之后,把上一个节点清除
while(cur){
// 一旦节点销毁,节点的指针也会被置为NULL,所以需要创建一个临时的节点指针
ListNode *temp = cur;
cur = cur->next;
DestroyNode(&temp);
}
// 特别注意,使用的*head要置为NULL,不能让其成为野指针
*head = NULL;
}
7. 打印单链表
// 打印单链表
void PrintList(ListNode *head){
// 头结点不存在
if (!head) return;
// 头结点存在
ListNode *cur = head;
while(cur->next){
printf("%d,", cur->next->value);
cur = cur->next;
}
}
8. 插入单链表节点
需要注意的是,如果插入位置前面没有节点,默认用值为 -1 的节点进行补齐。此外补齐节点的代码 cur->next = CreateNode(-1),可以好好看看。
void InsertList(ListNode *head, int index, int num){
if(!head || index < 0) return;
// 新节点一直都在
ListNode *new_node = CreateNode(num);
ListNode *cur = head;
// 如果不是插入新节点
while(index > 0){
// index不为0,需要补齐-1节点
if(!cur->next){
cur->next = CreateNode(-1); // 妙处在于这句话,新建节点,并且相连了
}
cur = cur->next;
index--;
}
// 插入新节点
new_node->next = cur->next;
cur->next = new_node;
}
9. 删除单链表节点
删除单链表中所有元素值为 value 的节点,不是删除第一个值为 value 的节点。
// 删除单链表节点,根据传入的value值删除对应节点
void DeleteNode(ListNode **head, int value){
// 如果头结点的指针或者头结点不存在,没法删除
if(!head || !(*head)) return;
ListNode *cur = *head;
// 一直遍历
while(cur->next){
// 找到待删除的节点
if(cur->next->value != value){
cur = cur->next;
}else{
// 删除这一节点
ListNode *to_be_delete = cur->next;
cur->next = to_be_delete->next;
DestroyNode(&to_be_delete);
}
}
}
10. 验证
int main(){
int array[5] = {1,2,3,4,5};
ListNode *head = CreateList(array, 5);
PrintList(head);
printf("\n插入之后:");
InsertList(head, 7, -22);
PrintList(head);
printf("\n删除之后:");
DeleteNode(&head, -5);
PrintList(head);
DestroyList(&head);
printf("\n销毁之后:");
PrintList(head);
return 0;
}