/*链式结构其实是结构体变量与结构体变量通过指针建立联系进而连接在一起。
而结构体分为:数据域(用来存储数据,而且这个数据可以是任何类型,甚至是结构体类型),指针域(用来做连接的)
链表就是内存不连续的,且数据存在不同类型的数组。只是它不能通过下标的方式访问,只能通过指针去访问
有头链表:表头不存放数据去操作
例:*/
```c
#include <stdio.h>
#include <stdlib.h> //标准头文件
struct Node
{
int data;
struct Node* next; //我通常用next指针表示下一个结构体变量的地址是多少
}
struct Node* createList()
/*createList要用指针,是因为它返回的是头的这个指针,且链表都是以指针的方式返回的,因为我们是从堆内存中申请一块内存的,我们要返回的是一个指针*/
{
struct Node* headNode = (struct Node*)malloc(sizeof(stuct Node));
/*有人会问为什么是头指针headNode分配这块内存。这是因为:【malloc其作用是在内存的动态存储区分配一个长度为sizeof()的连续空间,且此函数的返回值是分配区域的首地址,也可以说,此函数是一个指针类型的函数,返回的指针指向该分配域的开头位置。如果分配成功,则返回指向被分配内存的指针,否则返回空指针NULL。当内存不再使用时,应使用free()函数将此内存释放(malloc的含义来源于百度。在这里引用只为大家能更好理解单链表)】这里malloc分配了一块节点类型的内存,分配了这块内存之后返回这块内存的首地址存储到headNode里面*/
/*表头是一个结构体变量,我们要对其进行初始化,且表头不存放数据,所以数据data我们不做处理,指针要对其进行处理*/
headNode->next = NULL;
return headNode; /*这里返回headNode是为了主函数接收headNode这个值,否者写其他的话,headNode不被接收*/
}
//以上就是创建表头的过程,也叫创建链表的过程。
//创建结点,为插入做准备
struct Node*createNode(int data) /*节点也是个结构体变量,只是比表头多了个数据域,所以我们要传入一个数据域*/
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode ->next = NULL;
return newNode; /*其实节点和表头一样的,只是有头单链表表头不存放数据*/
}
/*第一种插入方式:表头法插入*/
void insertByHead(struct Node* headNode, int data)
/*告诉别人插入的是以headNode这个表头为头节点,插入的数据为data的链表*/
{
//插入之前首先创建插入的结点
struct Node* newNode = createNode(data); /*用指针调用这个结点*/
newNode ->next = headNode->next;
headNode->next = newNode; //这里已完成插入
}
/*因为我们要做的是一个有表头的链表,所以我们不可能把结点插到headNodew前面去的,只能插到headNode头结点的下一个*/
/*表尾插入,我们只需知道当这个下一个结点是空NULL的时候,即为表尾*/
/*从第一个结点插入,然后往后面找*/
void insertByTail(struct Node* headNode, int data)
/*要插入的结点,要插入的数据*/
{
struct Node* newNode = createNode(data);
/*创建插入的结点,调用一下createNode函数*/
struct Node* tailNode = headNode;
while (tailNode->next !=NULL)
{
tailNode = tailNode ->next;
}
tailNode ->next = newNode;
}
//指定位置插入
//struct Node* headNode 插入这个结点
//int data 插入这个数据
//int posData 指定位置
void insertByAppoin(struct headNode, int data , int posData)
{
struct Node* pMove = headNode;
struct Node*posNode = headNode->next;
//移动节点不为NULL,且当前节点元素不等于查找元素
while(posNode != NULL&&posNode ->data ! =posData)
{
posFrontNode = posNode;
posNode = posFrontNode->next;
}
//分析posNode的状态
if(posNode == NULL)
{
printf("未找到指定位置,无法插入!\n");
return;
}
else
{
struct Node* newNode = createNode(data);
posFrontNode ->next = newNode;
newNode -> next = posNode;
}
}
//表头删除,删除第二个结点
void deleteNodeByHead(struct Node* headNode)
{
struct Node*nextNode = headNode ->next;
if(nextNode == NULL)
{
printf("链表为NULL,无法删除!");
return ;
}
headNode ->next = nextNode ->next;
free(nextNode);
nextNode = NULL;
}
//表尾删除
void deleteNodeByTail(struct Node* headNode)
{
struct Node* tailNode= headNode ->next; //尾结点
struct Node* tailFrontNode = headNode; //尾结点上一个结点
if(tailNode ==NULL)
{
printf("链表为NULL,无法删除!")
return;
}
while(tailNode->next != NULL)
{
tailFrontNode = tailNode;
tailNode = tailFrontNode ->next;
}
tailFrontNode ->next = NULL;
free(tailNode);
tailNode = NULL;
}
//指定位置删除
void deleteByAppoin(struct Node* headNode, int posData)
{
struct Node*posFrontNode = headNode;
struct Node*posNode = headNode->next;
//移动结点不为NULL,并且当前结点中元素不等于查找的元素
while(posNode != NULL&&posNode ->data != posData)
{
posFrontNode = posNode;
posNode = posFrontNode - next;
}
//分析posNode状态
if(posNode == NULL)
{
printf("未找到指定位置,无法删除!\n");
}
else
{
posFrontNode ->next = posNode ->next;
free(posNode);
posNode =NULL;
}
}
**删除数据一定要判断是否为空**
//进行打印
void printList(struct Node* headNode)
{
//有头链表,从第二个开始打印
struct Node* pMove = headNode->next;
while(pMove)
{
printf("%d-->",pMove ->data);
pMove = pMove -> next;
}
printf("\n");
}
//需要用的时候,用主函数接收
int main()
{
struct Node*list = createList(); //链表创建
insertByHead(list, 1);
insertByHead(list, 2);
insertByHead(list, 3);
printList(list);
/*这里的结果是321,因为这里是表头法插入,按顺序先把 1 插到表头的下一个结点,然后再把 2 插进去,最后再把 3 插进去,也就是说,1 2 3按顺序地插进第二个结点,所以输出的结果是反的,为3 2 1*/
/* 在这里也可以写为:
for(int i = 1; i<=3 ; i++)
{
insertByHead(list, i);
}
printList(list); */
insertByTail(list, -1);
printList(list);
//输出结果为3->2->1-> -1
inserByAppoin(list , -100, -1);
printList(list);
deleteNodeByHead(list);
printList(list);
deleteNodeByTail(list);
printList(list);
deleteByAppoin(list, 1)
printLiist(list)
system("pause"); //防止闪屏
return 0;
}