#include<stdio.h>
#include<stdlib.h>//动态分配空间头文件
/***创建链表的结构体:
链表中第一个结点数据data存的是链表目前的结点个数
next是个结构体指针 指向下一个结点的地址
第一个结点是头结点 不是读入进去的数据
***/
typedef struct Node{
int data;
struct Node* next;
}Node;//通过typedef的方式将访问链表的方式进行重定义 可以参考: https://blog.csdn.net/sjp151/article/details/119668876
/***初始化链表:
1、 要给链表开辟一块新的内存空间/创建新结点
2、 将链表结点清空(个数为0、头节点的下一个结点为空)
abbr. 初始化(initialization)
***/
Node* initList(){//这里返回的应该是头结点的地址(指针)
//因为只要得到头结点的地址,就可以知道其他的结点
Node* L=(Node*)malloc(sizeof(Node));
L->data=0;
L->next=NULL;
return L;
}
/***头插法:
1、需要传递头结点和插入的数据
2、创建一个新结点
3、将数据赋给新结点data
4、将头结点的next赋给新结点的next:new->next=L->next
解释:头结点在第一次执行头插法时为空,则新结点的下一个结点地址为空(还没有插入第二个新结点)
5、将新结点的地址赋给头结点的地址(不是next):L->next=new
解释:在插入第一个新的结点时 头结点的下一个结点地址next就是新结点的地址(这里不是next,next是新结点的下一个结点)
在第2次插入新结点的时候, 新的结点的next是头结点的next(也就是插入的第一个结点地址)
头结点的next就变成新结点的地址,如下方演示:
未插入第二个结点前:L->data=1 L->next=new1 new1->next=NULL
插入第二个结点后: L->data=2 L->next=new2 new2->next=new1 new1->next=NULL
...
6、头结点的data++(代表此时链表的结点增加一个)
***/
void headInsert(Node* L,int data){//L本身存储的就是地址
Node* node=(Node*)malloc(sizeof(Node));
node->data=data;
node->next=L->next;
L->next=node;
L->data++;
}
/***尾插法:
1、同样需要 头结点地址和数据
2、创建一个结点等于头结点 new=L 用于遍历链表
3、遍历链表,得到当前链表最后一个结点的地址
4、开辟一块内存空间给新插入的结点,将data赋值,next置为空,链表原来的最后一个结点的next=新结点的地址
5、头结点的data++
***/
void tailInsert(Node* L,int data){
Node* node=L;//为了防止遍历过程中头结点改变 要用新的结点来遍历链表
for(int i=0;i<L->data;i++){
node=node->next;
}
Node* n=(Node*)malloc(sizeof(Node));
n->data=data;
n->next=NULL;
node->next=n;
L->data++;
}
/***
假设原来的链表为 2 111,1 112,2 113 (111是头结点,剩下的是自带的结点)
node=111
node=112
node=113
这样就可以得到链表的最后结点
***/
/***删除结点:
1、找到要删除的结点,将上一个结点的next赋值为下一个结点的地址
上一个结点->next=删除结点->next
2、释放要删除的结点 结点个数--
3、找到目标结点删除 返回真 没找到返回假
***/
int deletedata(Node* L,int data){
//delete在devc++是关键字
//这里类似于 双指针的用法?
Node* preNode=L;//以头结点为开始
Node* node=L->next;//第一个数据结点的地址
while(node){
if(node->data==data){
preNode->next=node->next;
free(node);
L->data--;
return 1;
}
preNode=node;
node=node->next;
}
return 0; //0为假 非0为真
}
/***打印链表:
遍历链表
***/
void printList(Node* L){
Node* node=L->next;//指向第一个数据结点 而不是头结点
while(node){
printf("%d ",node->data);
node=node->next;
}
}
int main(){
//建立链表并且初始化它
Node* L=initList();
headInsert(L,1);//头插法,传递 创建好的链表 和 值
headInsert(L,2);
headInsert(L,3);
headInsert(L,4);
headInsert(L,5);
tailInsert(L,6);//尾插法
tailInsert(L,7);
tailInsert(L,8);
tailInsert(L,9);
tailInsert(L,10);
printList(L);//打印链表
if(deletedata(L,10)){
printf("删除成功\n");
}
else{
printf("删除失败\n");
}
printList(L);//再打印一遍链表
return 0;
}
数据结构(C语言版) 代码详解01-单链表
最新推荐文章于 2024-06-12 18:28:23 发布