结构体
struct ListNode {
int element; //数据域
struct ListNode *next; //指针域
};
结构体的定义中,因为链表是链式存储结构,需要一个每一个结点处都需要存放一个指针来指向下一个结点的位置,而下一个结点的类型依然是这个结构体类型,所以指针的定义就是struct ListNode *next;。数据域中的元素为了举例,以int整形为例,当然也可以设置其它的数据类型。
单链表的初始化
void InitListNode(struct ListNode *head){
head->next=NULL;
}
我使用的是带有头结点的单链表,头结点的作用可以简化链表操作,也可以统一空链表和非空链表的操作。链表初始化是对链表的头结点head,数据域中的内容一般不需要操作,只需要把指针域置空,当需要连接下一个结点时,将指针域指向待连接的结点即可。
插入操作
int InsertListNode(struct ListNode *head,int element,int index){
if(index<1) return 0; //判断插入位置是否合法
struct ListNode *p=head;
while (index>1){ //循环至需要插入的位置的前驱结点
p=p->next;
index--;
}
struct ListNode *node =malloc(sizeof(struct ListNode)); //分配空间
if (node==NULL) return 0; //判断空间是否分配成功
node->element=element;
node->next=p->next; //将插入位置的指针域指向插入前该位置的结点
p->next=node; //将插入位置的前驱结点的指针域指向被插入结点
return 1;
}
插入函数的三个参数分别是,需要操作的单链表,插入的数据,插入的位置。插入操作中,和顺序表不同的是,不需要将插入位置后面的元素向后移动,只需要将前一个结点指向插入结点,将插入结点指向后一个结点。需要注意的是,在改变指针时,需要注意顺序,如果先操作p->next=node; ,那么会导致后一个结点的位置丢失,node->next无法找到正确的后一个结点。
删除操作
int DeleteListNode(struct ListNode *head,int index){
if (index<1) return 0; //判断删除位置是否合法
struct ListNode *p=head;
while (index>1){ //循环将指针指向待删除结点的前驱结点
p=p->next;
index--;
if(p==NULL) return 0;
}
if (p->next==0) return 0; //如果是最后的尾结点,下一个被删位置是空,则返回错误信息
struct ListNode *q=p->next;
p->next=p->next->next;
free(q); //释放被删除结点的空间资源
return 1;
}
删除操作和插入操作相似,先要找到被插入或者删除结点的前驱结点,之后再进行插入或者删除操作。删除操作中改变指针时,是直接将前驱节点跳过待删除结点直接指向后继节点,这样单链表中就不会连接待删除结点了。而在改变指针前,也先需要再定义一个指针标量标记待删除结点,否则也是会失去待删除结点的位置,最后用free()函数完成资源的释放。
获取指定位置的数据
int GetListNode(struct ListNode *head,int index){
if (index<1) return 0;
struct ListNode *p=head;
while (index>1){
p=p->next;
if(head==NULL) return 0;
index--;
}
return p->next->element;
}
与顺序表不同的是,单链表中获取元素没有数组下标供我们使用,所以我们还是通过循环,将指针指向指定位置,通过前驱节点获取或者直接获取指定位置的数据都是可以的。这里的index是单链表的位序,从1开始,不包括头节点,头结点的位序是0。
查找链表中数据的位置
int FindListNode(struct ListNode *head, int target){
struct ListNode *p=head;
int i=0;
while (p->next){
p=p->next;
i++;
if (target==p->element){
return i;
}
}
return 0;
}
通过循环遍历整个单链表的每一个结点,将结点中的数据和待查找的数据比较,如果一致,则返回该结点的位序。注意,头节点不算在内,函数中的参数代表位序。
单链表长度
int ListNodeSize(struct ListNode *head){
int i=0;
struct ListNode *p=head;
while(p->next){
p=p->next;
i++;
}
return i;
}
通过循环遍历单链表,每获取得到一个结点,将计数器编号自增一次,最后计数器的数据就是链表的长度。注意,头结点不算在内。
打印输出单链表
void PrintListNode(struct ListNode *head){
struct ListNode *p=head;
while (p->next){
p=p->next;
printf("%d ",p->element);
}
printf("\n");
}
和顺序表相同,为了看到链表中数据的真实情况,我们需要将单链表打印输出。通过遍历,打印每一个结点。
完整代码
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int element;
struct ListNode *next;
};
void InitListNode(struct ListNode *head){
head->next=NULL;
}
int InsertListNode(struct ListNode *head,int element,int index){
if(index<1) return 0;
struct ListNode *p=head;
while (index>1){
p=p->next;
index--;
}
struct ListNode *node =malloc(sizeof(struct ListNode));
if (node==NULL) return 0;
node->element=element;
node->next=p->next;
p->next=node;
return 1;
}
int DeleteListNode(struct ListNode *head,int index){
if (index<1) return 0;
struct ListNode *p=head;
while (index>1){
p=p->next;
index--;
if(p==NULL) return 0;
}
if (p->next==0) return 0;
struct ListNode *q=p->next;
p->next=p->next->next;
free(q);
return 1;
}
int GetListNode(struct ListNode *head,int index){
if (index<1) return 0;
struct ListNode *p=head;
while (index>1){
p=p->next;
if(head==NULL) return 0;
index--;
}
return p->next->element;
}
int FindListNode(struct ListNode *head, int target){
struct ListNode *p=head;
int i=0;
while (p->next){
p=p->next;
i++;
if (target==p->element){
return i;
}
}
return 0;
}
void PrintListNode(struct ListNode *head){
struct ListNode *p=head;
while (p->next){
p=p->next;
printf("%d ",p->element);
}
printf("\n");
}
int ListNodeSize(struct ListNode *head){
int i=0;
struct ListNode *p=head;
while(p->next){
p=p->next;
i++;
}
return i;
}
int main (){
...
return 0;
}
2623

被折叠的 条评论
为什么被折叠?



