链表实现的逻辑
链表,本质是结构体,包含了节点值和后节点指针两个数据(双向链表会有两个节点指针)
struct LIST{
int data;
struct LIST* next;
};
//创建了struct LIST结构体
基本操作的代码实现
插入
struct LIST* listInsert(struct LIST *head,int data,int n){//在索引为i的节点插入新节点(初始索引为0)
struct LIST *temp1=(struct LIST*)malloc(sizeof(struct LIST));//创建新节点
temp1->data=data;
temp1->next=NULL;
if(n==0){//头插入
temp1->next=head;
head=temp1;
return head;
}
struct LIST *temp2=head;//遍历到目标节点的前节点
for(int i=0;i<n-1;i++){
temp2=temp2->next;
}
temp1->next=temp2->next;//新节点指向目标节点
temp2->next=temp1;//前节点指向新节点
return head;//更新头节点
}
优化:
int listLength(struct ListNode* head){
int len=0;
struct ListNode *temp=head->next;
while(temp){
++len;
temp=temp->next;
}
return len;
}
int addAtIndex(struct ListNode* head, int index, int val){
int len=listLength(head);//得到链表长度
if(index>len || index<0){//判断是否超范围
return 0;
}
else{//范围合理
struct ListNode *prev=head;
struct ListNode *newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
newnode->val=val;
for(int i=0;i<index;i++){
prev=prev->next;
}
newnode->next=prev->next;
prev->next=newnode;
return 1;
}
return 0;
}
//head->next为头节点
//成功插入返回1,否则返回0
删除
struct LIST* listDelete(struct LIST *head,int target){//删除节点值为target的节点
if(target==head->data){//只有一个节点
head=NULL;
return head;
}
struct LIST *temp1=head;
while((temp1->next)->data!=target){
temp1=temp1->next;//遍历到目标节点的前节点
}
struct LIST *temp2=temp1->next;//temp2为目标节点
temp1->next=temp2->next;
temp2->next=NULL;
return head;
}
打印
void printList(struct LIST *head){//打印链表
struct LIST *temp=head;
printf("list is:");
while(temp!=NULL){//遍历所有节点并打印
printf("%d ",temp->data);
temp=temp->next;
}
printf("\n");
}
释放空间
void listFree(struct LIST *head){//释放空间
if(head){
//递归free空间
struct LIST *temp=head->next;
free(head);
listFree(temp);
}
}
求长度
int listLength_fir(struct LIST *head){//得到链表长度
if(head) return listLength(head->next)+1;
else return 0;
}
int listLength_sec(struct ListNode* head){
int len=0;
struct ListNode *temp=head->next;
while(temp){
++len;
temp=temp->next;
}
return len;
}
寻找节点
struct LIST* listFind(struct LIST *head,int target){//找到data为target的节点
struct LIST *temp=head;
while(temp->data!=target){
temp=temp->next;//未找到,不断后移节点
}
return temp;
}
反转链表
struct LIST* listReverse(struct LIST *head){//反转链表
if(!head->next){//一个节点
return head;
}
else if(!(head->next)->next){//两个节点
(head->next)->next=head;
head->next=NULL;
return head;
}
struct LIST* temp1=head;//前节点
struct LIST* temp2=head->next;//中间节点
struct LIST* temp3=temp2->next;//后节点
while(temp3!=NULL){//中节点为最后有效节点
temp2->next=temp1;//中节点指向前节点
temp1=temp2;//前节点后移
temp2=temp3;//中节点后移
temp3=temp3->next;//后节点但后移
}
temp2->next=temp1;//最后有效节点处理
head->next=NULL;//头节点指向NULL
head=temp2;//头节点变换为尾节点
return head;//返回新的头节点
}
易错点
每次操作完,必须更新头节点,因为头节点指向内容虽然改变,但是头节点本身地址并没有改变,
除非使用
struct LIST **head_ref;
//创建头节点指针的指针
这样就不需要显式地更新头节点