单链表的基本操作以及头插法和尾插法建立单链表
本文主要关于单链表的基本操作,创建单链表,插入节点,删除节点,查找结点,清空节点,销毁节点,以及使用头插法和尾插法建立单链表,阅读大概5分钟,希望能帮到你。
单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成包括元素(数据元素的映象)和指针(指示后继元素存储位置)。元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。以“结点的序列”表示线性表称作线性链表(单链表),单链表是链式存取的结构。
单链表的操作主要包括以下几种:
- 创建单链表:创建一个新的链表,包括初始化头指针等操作。
- 插入节点:在链表的头部、尾部或者指定位置插入新的节点。
- 删除节点:删除链表中的指定节点,包括头节点和尾节点等。
- 查找节点:在链表中查找指定的节点,并返回该节点的值。
- 遍历链表:按照一定的顺序遍历整个链表,输出每个节点的值。
- 清空链表:将链表中的所有节点删除,释放内存空间。
- 销毁链表:彻底删除链表,包括释放内存空间等操作。
这些操作是单链表的基本操作,通过这些操作可以实现单链表的各种应用,比如插入排序、查找最大值等。同时需要注意,在实际应用中需要判断指针是否为空,以避免访问非法内存地址导致程序崩溃等问题。
基本操作示例代码
//单链表的基本操作
#include<stdio.h>
#include<stdlib.h>
//节点结构体
typedef struct Node{
int data;
struct Node*next;
}Node;
//单链表结构体
typedef struct LinkedList{
Node*head;
int length;
}LinkedList;
//初始化结构体
void initLinkedList(LinkedList*list){
list->head=NULL;
list->length=0;
}
//在链表末尾插入节点
void insertNode(LinkedList*list ,int data){
Node*newNode=(Node*)malloc(sizeof(Node));
newNode->data=data;
newNode->next=NULL;
if(list->head==NULL){
list->head=newNode;
}
else{
Node*temp=list->head;
while (temp->next!=NULL){
temp=temp->next;
}
temp->next=newNode;
}
list->length++;
}
//销毁链表
void destroyLinkedList(LinkedList*list){
Node*current=list->head;
Node*next;
while (current!=NULL){
next=current->next;
free(current);
current=next;
}
list->head=NULL;
list->length=0;
}
//清空列表
void clearLinkedList(LinkedList*list){
destroyLinkedList(list);
initLinkedList(list);
}
//求链表的表长
int getLength(LinkedList*list){
return list->length;
}
//判断链表是否为空
int isEmpty(LinkedList*list){
return list->head==NULL?1:0;
}
int main(){
LinkedList list;
initLinkedList(&list);
insertNode(&list,5);
insertNode(&list,10);
insertNode(&list,15);
insertNode(&list,25);
printf("表的长度:%d\n",getLength(&list));
printf("链表是否为空?%s\n",isEmpty(&list)?"是":"否");
clearLinkedList(&list);
printf("清空后链表的长度:%d\n",getLength(&list));
printf("清空后链表是否为空?%s\n",isEmpty(&list)?"是":"否");
return 0;
}
**头插法和尾插法是单链表中的两种插入方法。**
头插法是指每次将新节点插入到链表的头部,即第一个节点的之前的位置。这种方法的特点是插入操作的时间复杂度为O(1),即无论链表的大小如何,插入操作的时间复杂度都是常数时间。但是,头插法会导致链表中元素的数据顺序与插入顺序相反。
尾插法是指每次将新节点插入到链表的尾部,即最后一个节点的之后的位置。这种方法的特点是插入操作的时间复杂度为O(n),即插入操作需要遍历整个链表才能找到尾部节点。但是,尾插法可以保持链表中元素的数据顺序与插入顺序一致。
在实际应用中,可以根据具体需求选择不同的插入方法。如果需要频繁插入和删除操作,头插法可能会更合适;如果需要保持数据顺序与插入顺序一致,尾插法可能会更合适。
示例代码如下:
//单链表的操作(尾插法和头插法建立单链表)
#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));
if(newNode==NULL){
printf("内存分配失败");
exit(1);
}
newNode->data=data;
newNode->next=NULL;
return newNode;
}
//头插法建立单链表
struct Node*insertAtBeginning(struct Node*head,int data){
struct Node*newNode=createNode(data);
newNode->next=head;
return newNode;
}
//尾插法建立单链表
struct Node*insertAtEnd(struct Node*head,int data){
struct Node*newNode=createNode(data);
if(head==NULL){
return newNode;
}
struct Node*temp=head;
while(temp->next!=NULL){
temp=temp->next;
}
temp->next=newNode;
return head;
}
//取单链表中第i个元素
int getAtIndex(struct Node*head,int index){
int count=0;
struct Node*current=head;
while(current!=NULL){
if(count==index){
return current->data;
}
count++;
current=current->next;
}
printf("索引超出范围\n");
return -1; // 表示未找到
}
//按值查找节点位置序号
int findPosition(struct Node*head,int value){
int pos=0;
struct Node*current=head;
while(current!=NULL){
if(current->data==value){
return pos;
}
pos++;
current=current->next;
}
printf("未找到该值\n");
return -1; // 表示未找到
}
//在第i个结点前插入新节点
struct Node*insertBeforeIndex(struct Node*head,int index,int data){
if(index==0){
return insertAtBeginning(head,data);
}
int count=0;
struct Node*current=head;
while(current!=NULL&&count<index-1){
current=current->next;
count++;
}
if(current==NULL){
printf("索引超出范围\n");
return head;
}
struct Node*newNode=createNode(data);
newNode->next=current->next;
current->next=newNode;
return head;
}
//删除第i个节点
struct Node*daleteAtIndex(struct Node*head,int index){
if(head==NULL){
printf("链表为空\n");
return NULL;
}
if(index==0){
struct Node*temp=head;
head=head->next;
free(temp);
return head;
}
int count=0;
struct Node*current=head;
struct Node*prev=NULL;
while(current!=NULL&&count<index){
prev=current;
current=current->next;
count++;
}
if(current==NULL){
printf("索引超出范围\n");
return head;
}
prev->next=current->next;
free(current);
return head;
}
//打印单链表
void printLinkedList(struct Node*head){
struct Node*temp=head;
while (temp!=NULL){
printf("%d->",temp->data);
temp=temp->next;
}
printf("NULL\n");
}
int main(){
struct Node*head=NULL;
//使用头插法建立单链表
head=insertAtBeginning(head,5);
head=insertAtBeginning(head,15);
head=insertAtBeginning(head,25);
head=insertAtBeginning(head,65);
printf("头插法建立单链表以后:");
printLinkedList(head);
//使用尾插法建立单链表
head=insertAtEnd(head,8);
head=insertAtEnd(head,58);
head=insertAtEnd(head,68);
head=insertAtEnd(head,78);
printf("尾插法建立单链表以后:");
printLinkedList(head);
//获取第i个元素
int elementAtIndex=getAtIndex(head,2);
printf("索引2处的元素:%d\n",elementAtIndex);
//查找元素的位置序号
int position=findPosition(head,58);
printf("值为58的位置:%d\n",position);
//在第i个结点前插入新节点
head=insertBeforeIndex(head,3,30);
printf("在索引3处前插入节点后:");
printLinkedList(head);
//删除第i个节点
head=daleteAtIndex(head,2);
printf("删除索引2处的节点后:");
printLinkedList(head);
return 0;
}
运行效果
感谢阅读