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; }

浙公网安备 33010602011771号