C语言——链表(基础篇)
链表是一种非常重要的数据结构,在很多场景中都有广泛的应用,基本用法是动态存储,链表的大小可以动态增长或缩小,不像数组那样需要预先分配固定的内存空间。这使得它在数据量不确定的情况下非常有用。相当于内存不连续的变长数组。
一个简单的 C 语言链表实现,包括链表节点的定义、创建节点、插入节点(头部插入和尾部插入)、删除节点和遍历链表的操作
本文为链表基础篇,链表基础入门,使用偏向c语言的代码,比c++代码冗长。
节点构建:
链表的基本单元是节点(node),每个节点包含一个值和指向下一个节点的指针。
struct ListNode {
int data;
struct ListNode* next;
};
这是一个数据类型为结构体指针的函数,使用new开辟新节点并进行初始化,返回新建节点的指针
struct ListNode* createNode(int data) {
struct ListNode* newNode=new ListNode();
if(newNode==NULL){exit(-1);}//如果内存分配失败退出并返回-1
newNode->data=data;
newNode->next=NULL;
return newNode;
}
链表的构建:
在头部(前面)添加节点:
void insertAtHead(struct ListNode** head, int data) {
struct ListNode* newNode=createNode(data);
newNode->next=*head;//与原头部先连接
*head=newNode;//更新头部
}
在链表操作里,我们经常要对链表的头指针进行修改,比如在头部插入新节点、删除头节点时,头指针指向会改变。普通指针 struct ListNode* head 是按值传递,函数里修改它的值不会影响原头指针。而使用指向指针的指针 struct ListNode** head 按地址传递头指针,这样函数内部对它所指向的指针进行修改,外部的头指针也会跟着改变。
说人话就是*head指向的是链表头部,**head指向储存头部的地方,改变**head就是改变头部
在尾部(后面)添加节点:
新建节点,特判头部不存在,寻找尾部,延长尾部(在尾部添加节点)。
void insertAtTail(struct ListNode** head, int data) {
struct ListNode* newNode=createNode(data);
if(*head==NULL) {
*head=newNode;
return;//特判头部不存在
}
struct ListNode* temp=*head;//建立一个临时指针用于遍历
while(temp->next!=NULL) {
temp=temp->next;
}//找到尾部
temp->next=newNode;//延长
}
删除包含特定数据(data)的节点:
检查是否为空链表,头部特判(检查头部是否为目标data),寻找data,如果存在data则删除节点
while循环,如果temp的下一个是data节点(或NULL)停止循环,也就是说要删的是temp->next。
在连接节点的过程中,如果data是尾部节点,temp->next->是不存在的即为NULL
void deleteNode(struct ListNode** head,int data) {
if(*head==NULL) {return;}//头部不存在,空链表特判
if((*head)->data==data) {//头部特判
struct ListNode* temp=*head;//用于删除原头节点
*head=(*head)->next;
delete temp;
return;
}
struct ListNode* temp=*head;//temp初始是头,直接判定下一个,也就是next
while(temp->next!=NULL&&temp->next->data!=data) {
temp=temp->next;
}
if(temp->next!=NULL) {
struct ListNode* temp2=temp->next;
temp->next=temp2->next;//temp->next=temp1->next->next;
delete temp2;
}
}
遍历链表:
void traverselist(struct ListNode* head) {
struct ListNode* temp=head;
while(temp!=NULL) {
cout<<temp->data<<" ";
temp=temp->next;
}
}
摧毁链表:
因为我们节点是new出来的,动态分配在堆上,操作系统的回收内存过程是粗略的,可能存在内存泄漏,所有我建议用完链表后手动摧毁。
void destroyList(struct ListNode** head) {
struct ListNode* temp = *head;
struct ListNode* temp2;
while (temp != NULL) {
temp2 = temp->next;
free(temp);
temp = temp2;
}
*head = NULL;
}
总代码:
#include<iostream>
using namespace std;
struct ListNode {
int data;
struct ListNode* next;
};
struct ListNode* createNode(int data) {
struct ListNode* newNode=new ListNode();
if(newNode==NULL){exit(-1);}//如果内存分配失败退出并返回-1
newNode->data=data;
newNode->next=NULL;
return newNode;
}
void insertAtHead(struct ListNode** head, int data) {
struct ListNode* newNode=createNode(data);
newNode->next=*head;//与原头部先连接
*head=newNode;//更新头部
}
void insertAtTail(struct ListNode** head, int data) {
struct ListNode* newNode=createNode(data);
if(*head==NULL) {
*head=newNode;
return;//特判头部不存在
}
struct ListNode* temp=*head;//建立一个临时指针用于遍历
while(temp->next!=NULL) {
temp=temp->next;
}//找到尾部
temp->next=newNode;//延长
}
void deleteNode(struct ListNode** head,int data) {
if(*head==NULL) {return;}//头部不存在,空链表特判
if((*head)->data==data) {//头部特判
struct ListNode* temp=*head;//用于删除原头节点
*head=(*head)->next;
delete temp;
return;
}
struct ListNode* temp=*head;//temp初始是头,直接判定下一个,也就是next
while(temp->next!=NULL&&temp->next->data!=data) {
temp=temp->next;
}
if(temp->next!=NULL) {
struct ListNode* temp2=temp->next;
temp->next=temp2->next;//temp->next=temp1->next->next;
delete temp2;
}
}
void traverselist(struct ListNode* head) {
struct ListNode* temp=head;
while(temp!=NULL) {
cout<<temp->data<<" ";
temp=temp->next;
}
}
void destroyList(struct ListNode** head) {
struct ListNode* temp = *head;
struct ListNode* temp2;
while (temp != NULL) {
temp2 = temp->next;
free(temp);
temp = temp2;
}
*head = NULL;
}
int main() {
struct ListNode* head = NULL;
insertAtHead(&head, 2);insertAtHead(&head, 5);insertAtHead(&head, 6);// 插入节点
insertAtTail(&head, 0);insertAtTail(&head, 1);insertAtTail(&head, 3);
insertAtTail(&head, 1);insertAtTail(&head, 4);
printf("Original list: ");
traverselist(head);
deleteNode(&head, 1);deleteNode(&head, 3);deleteNode(&head, 1);deleteNode(&head, 4);// 删除节点
printf("After deleting 1314: ");
traverselist(head);
destroyList(&head);
return 0;
}

浙公网安备 33010602011771号