C语言实现单链表的一些操作详细说明(带头指针)

关于头节点与头指针的一些说明

头指针:链表中第一个结点的存储位置就叫做头指针

在实现链表操作时,有两种方法去实现:一种是带头结点的,一种是不带头结点的,即只有头指针的情况。

针对于第一种:

带有头结点的情况
这种情况下,头指针是指向头结点的。接着头结点才指向我们的首结点,即真正我们要插入的第一个结点。

头结点的数据域一般是不存任何数据的,但是也可以存储链表的长度之类的。

有了头结点后,对在第一个元素结点插入结点和删除结点,其操作与对其它结点的操作统一了。

针对于第二种情况只有头结点的情况

对于这种情况,我们的头指针就直接指向了我们要插入的元素的,因此我们可以发现一个问题,即我们插入或删除的时候,需要区分一下要插入或者删除的是否是第一个元素,假如是第一个元素,我们需要改变头指针的值,假如不是第一个元素,我们要改变的值则是前一个元素所指向的next

从这里我们可以看出,头结点的实现相对于头指针的实现会更加简单一些,因为插入和删除的操作统一了,不需要区分是否是第一个元素。

我们这里实现的是更为复杂一点的带头指针的情况

带头指针的链表的实现

首先是结构体的定义:

struct Node{
 int data;         //一个数据域,一个指针域,next指向下一个结点
 struct Node* next; 
};

然后还可以做一个简化

typedef struct Node* LList; //将其重命名为LList
//之后创建一个新的结构体可以简化为
LList R;

链表的初始化

void init(struct Node **phead){  //链表的初始化 
 *phead = NULL; 
}

链表的遍历

int getLength(struct Node *head){//遍历链表求链表长度 
 int len = 0;
 while(head){
  len++;
  head = head->next;
 }
 return len;
}

打印链表

void printList(struct Node *head){//遍历链表,将链表打印出来 
 while(head){
  printf("%d ",head->data);
  head = head->next;
 }
}

创建一个指针,为后面插入和删除提供方便,少写点代码

struct Node* createNode(int x){ //创建一个指针 
 struct Node *t;
 t = (struct Node*)malloc(sizeof(struct Node)); //强制类型转换
 t->next=NULL;              //好习惯,不要让指针处于未赋值状态
 t->data = x;
 return t; 
}

插入一个结点,k表示插入的位置,x为插入的值
这里有几个注意的点:
1.需要判断是否为第一个结点,如果是,需要改变头指针
2.在插入时,有两种方法判断k的合法性
(1)判断k的大小,k<1或者k>getlength ,但是这样不是很好,因为getlength会遍历一遍链表,有n的时间消耗
(2)直接找k-1,看看其是否存在,存在即可插入,不存在即插入不了,相比上面,时间消耗会减少一些,更加优秀一点

int insert(struct Node**phead,int k,int x){ //插入结点 
 //(1)判断k的大小,k<1或者k>getlength ,但是这样不是很好,因为getlength会遍历一遍链表,有n的时间消耗
 //(2)直接找k-1,看看其是否存在,存在即可插入,不存在即插入不了
 if(k<1) return 0;     
 else if(k==1){          //需要改变头指针的情况
  struct Node *t;
  t = createNode(x);     
  t->next = *phead;      
  *phead = t; 
  return 1;             //返回1表示成功,返回0表示失败
 }
 else{		        //不需要改变头指针的情况,正常情况
  struct Node *p;
  int count = 1;
  p = *phead;
  while(p && count < k-1 ){   //找到要插入的位置
   p = p->next;
   count++;
  } 
  if(p){		       //p不为空即找到,开始插入
   struct Node *t;
   t = createNode(x);
   t->next = p->next;         //栓新绳,解旧绳
   p->next = t;               
   return 1;
  }
  else{
   return 0;
  }
 }
}

删除一个结点,k表示要删除的位置,*px为被删除元素存放的位置
基本思路与插入相同,同样需要判断是否要改变头指针

int removeNode(struct Node**phead,int k,int *px){
 if(k<1) return 0;
 else if (k==1){             //需要改变头指针的情况
  if(*phead){
   *px = (*phead)->data;
   *phead = (*phead)->next;
   return 1;
  }
  else return 0;
 }
 else{			    //正常的情况
  int count = 1;
  struct Node*p;
  p = *phead;
  while(p&&count<k-1){
   p = p->next;
   count ++;
  }
  if(p==NULL||p->next==NULL) return 0; 
  struct Node*t;
  t = p->next;
  p->next = t->next;
  *px = t->data;          //用完记得将t释放掉
  free(t);
  return 1;
 } 
}

完整代码

#include<stdio.h>
#include<stdlib.h>
using namespace std;
//带有头指针的链表 
struct Node{
 int data;
 struct Node* next; 
};
//typedef struct Node* LList; //简化操作为LList R;
void init(struct Node **phead){  //链表的初始化 
 *phead = NULL; 
}
int getLength(struct Node *head){//遍历链表求链表长度 
 int len = 0;
 while(head){
  len++;
  head = head->next;
 }
  return len;
}
void printList(struct Node *head){//遍历链表,将链表打印出来 
 while(head){
  printf("%d ",head->data);
  head = head->next;
 }
}
struct Node* createNode(int x){ //创建一个指针 
 struct Node *t;
 t = (struct Node*)malloc(sizeof(struct Node));
 t->next=NULL;              //好习惯,不要让指针处于未赋值状态
 t->data = x;
 return t; 
}
int insert(struct Node**phead,int k,int x){ //插入结点 
 //(1)判断k的大小,k<1或者k>getlength ,但是这样不是很好,因为getlength会遍历一遍链表,有n的时间消耗
 //(2)直接找k-1,看看其是否存在,存在即可插入,不存在即插入不了
 if(k<1) return 0;
 else if(k==1){
  struct Node *t;
  t = createNode(x);     
  t->next = *phead;      
  *phead = t;
  
  return 1;
 }
 else{
  struct Node *p;
  int count = 1;
  p = *phead;
  while(p && count < k-1 ){
   p = p->next;
   count++;
  } 
  if(p){
   struct Node *t;
   t = createNode(x);
   t->next = p->next;
   p->next = t; 
   return 1;
  }
  else{
   return 0;
  }
 }
 
}
int removeNode(struct Node**phead,int k,int *px){
 if(k<1) return 0;
 else if (k==1){
  if(*phead){
   *px = (*phead)->data;
   *phead = (*phead)->next;
   return 1;
  }
  else return 0;
 }
 else{
  int count = 1;
  struct Node*p;
  p = *phead;
  while(p&&count<k-1){
   p = p->next;
   count ++;
  }
  if(p==NULL||p->next==NULL) return 0;
  struct Node*t;
  t = p->next;
  p->next = t->next;
  *px = t->data;
  free(t);
  return 1;
  
 } 
}
int main()
{
 struct Node * head;
 init(&head);
 int k = getLength(head);
 int x=0;
 insert(&head,1,11);
 insert(&head,1,22);
 insert(&head,2,44);
 removeNode(&head,1,&x); 
 printf("%d\n",x);
 printList(head);
 return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值