单链表操作_头结点方式

/*
单链表: 访问时,只能通过表头遍历进行访问,遍历结束的条件是最后一个节点的为NULL。单链表中可以分为数据域和指针域。数据域为用户存储数据的变量。指针域则指向下一个节点。 一般单链表操作可以分为头节结方式和头指针方式(struct node *root=NULL)方式。 由于单链表访问节点只有一条路径,因此再进行有序追加数据、删除数据和查找中间节点时,需要用到快慢指针。
*/
#include <stdio.h>
#include <stdlib.h>
#define NR(x)  sizeof(x)/sizeof(x[0])
typedef int DataType;
typedef struct node {
 DataType data;
    struct node *next;
}linkList;

/*头部插入法*/
void top_append(struct node *head,DataType data);
/*尾部插入法*/
void tail_append(struct node *head,DataType data);
/*删除节点*/
void del_node(struct node *head,int key);
/*打印单链表*/
void dispaly_list(struct node *head);

/*链表倒置*/
void invert_list(struct node *head);

/*查找中间节点*/
struct node *find_midList(struct node *head);


/*链表顺序插入*/
void insert_sortList(struct node *head,DataType data);

int main(void){
  linkList head={.next=NULL};
  DataType num[]={101,2,3,4,5,56,12,34,57,89,100,0};
  int i; 
  /*头部插入*/
  for(i=0;i<NR(num);i++){
    //  top_append(&head,num[i]);
  }  
  dispaly_list(&head); 
  printf("\n");  
  //*********//
  /*尾部插入*/
   for(i=0;i<NR(num);i++){
     // tail_append(&head,num[i]);
  }
  /*顺序插入*/
  for(i=0;i<NR(num);i++){
      insert_sortList(&head,num[i]);
    }
  dispaly_list(&head); 
  printf("\n");    
  /*逆置*/
  invert_list(&head);
  dispaly_list(&head);
  printf("\n");
  /*删除符合条件的节点 4*/
  printf("删除符合条件的节点 4\n");
  del_node(&head,101);
  dispaly_list(&head);
  printf("\n");
  printf("寻找链表中间节点:\n");
  if(find_midList(&head)!=NULL)
 printf("%d\n",(find_midList(&head))->data);
  else
   printf("this is linklist is empty\n");
return 0;
}
/*
  将data数据插入到head后面,即每次将新的数据往头部添加
*/
void top_append(struct node *head,DataType data){  //先插入的数据,最后打印
     struct node *new;
  new=malloc(sizeof(struct node));
     if(new==NULL)
     {
     printf("分配新空间失败\n");
  return ; 
  }       
     new->data=data;  //将数据赋值给新的节点
     new->next=head->next;   //将头节点指向的下一个节点的地址给新节点
  head->next=new;    //将新节点的地址给头结点   
}

void dispaly_list(struct node *head){
    struct node *tmp;
 for(tmp=head->next;tmp!=NULL;tmp=tmp->next)  //头结点的data不存在数据,因此tmp=head->next
           printf("%d ",tmp->data); 
}

/*
  将新数据添加到单链表的尾部
*/
void tail_append(struct node *head,DataType data){
     struct node *new,*tmp;  
     new=malloc(sizeof(struct node));
     if(new==NULL)
     {
     printf("新节点分配空间失败\n");
  return ; 
  } 
     new->data=data;
  for(tmp=head;tmp->next!=NULL;tmp=tmp->next);  //遍历单链表直到链表为空,即链表元素的next为NULL
      tmp->next=new;   //将新节点给链表的最后一个节点的next  
      new->next=NULL;    
}


/*
  采用快慢指针方式进行插入
  由于单链表指针只能从头部开始遍历,因此采用快慢指针的方式进行遍历,保留上一个节点的指针,进行插入操作
  思路分析(**link *cur):cur=*link cur为快指针,*link为慢的指针域 
   1、链表为空时,插入第一个数据, 只有head头节点.则*link为NULL,cur=NULL;则不进入while循环。直接将new->next=NULL,*link=new(head->next=new).
   2、链表不为空时,插入的数据都比原来链表中的要小,进入循环将cur->next的地址给link,则*link等于cur->next指向的下一个节点的地址直到cur为即前一次的cur->next指向的下一节点为NULL
   3、链表不为空,插入的数据比链表中的其中一个要小,则会在中途break掉.此时cur->data比新的data大。则需要切断cur节点跟前一个节点的链。然后将cur节点接到new->next中。*link为cur前一个节点的next
    
*/
void insert_sortList(struct node *head,DataType data){
     struct node *new,*cur,**link=&(head->next); //将头结点的next地址给二级指针**link, link解引用为head的next的地址,*link为head->next指向的节点(第一个节点)的地址 
     new=malloc(sizeof(struct node));
     if(new==NULL)
     {
      printf("新节点分配空间失败]n");
   return  ;
     }  
  new->data=data;  //将data赋值给新节点的数据域
#if  1
    struct node *slow=head,*fast;   //快慢指针
 for(fast=head->next;fast!=NULL;fast=fast->next)
 {     
    if(fast->data>=data)
                break;
    slow=fast;   
    }    
 new->next=fast;
 slow->next=new;

#else    
  while(cur=*link){   //link为装的节点的next地址 *link为解引用为next
      if((cur->data)>=data) //假设当前值小于当前数据域,则跳出循环
        break ;
      link=&(cur->next);  //将当前的cur->next的地址给link指针   即*link为cur->next指向的节点的地址   
  }
  new->next=cur;
  *link=new;
#endif  
}

/*
  思路:链表逆置
  将将原来的链表的表头处砍断,然后将砍断部分按头部插入法插入
*/
void invert_list(struct node *head){
     struct node *tmp,*tmp_head;
  tmp_head=malloc(sizeof(struct node));
  if(tmp_head==NULL)
  {
    printf("分配空间失败\n");
        return ;    
  } 
     //在头部砍断链表,表头的next指向的下一个节点给tmp_head临时表头
     tmp_head->next=head->next;
  head->next=NULL;
  for(tmp=tmp_head->next;tmp!=NULL;tmp=tmp->next)
        top_append(head,tmp->data);
  free(tmp_head);    
}


/*
  描述:删除数据域=key的节点
  思路:这里仍然采用快慢指针,快指针进行比较,慢指针保留后面一个节点
*/
void del_node(struct node *head,int key){
        struct node *fast,*slow;
  if(head->next==NULL){
   printf("This linklist is not entry\n");
      return ;
  }   
#if 0  
     for(fast=head->next;fast!=NULL;fast=fast->next){
     if(fast->data==key)
            break;
   slow=fast;    
  }
        slow->next=fast->next;
  free(fast);
  
#else
       struct node **link=&head->next,*cur;
    while(cur=*link){
       if(cur->data==key)
              break;
       link=&cur->next;  
    }
        *link=cur->next;
     free(cur);
#endif  
}

/*
  描述:查找中间节点
  思路:仍然是用快慢指针,快指针的速度是慢指针的两倍,当快指针走完链表时,慢指针刚好是链表的一半
*/
struct node *find_midList(struct node *head){
           struct node *slow=head,*fast=head; 
     if(NULL==head->next){
        printf("This linklist is not entry\n");
        return NULL;
     }
           while(fast->next){
         slow=slow->next;
      fast=fast->next;
         if(fast->next!=NULL)  //快指针每走完一个节点都要进行判断其指向的下一个节点是否为空,不为空,则进行下一步遍历
             fast=fast->next;
     }
     return slow;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值