什么是链表
链表就是一个结构体变量
struct people
{
char name[20];
int age;
int num;
char addr[20];
};
struct Node
{
//int data; //数据域
struct MM data; //指针域
struct Node* next;
};
链表的一个结点包括数据域和指针域
用第一个节点表示整个链表
头节点:没有存数据 有头链表,常用
首节点:存数据 无头链表
静态内存申请
手动申请,手动释放
#include <stdio.h>
struct MM
{
char name[20];
int age;
int num;
};
struct Node
{
//struct MM data;
int data; //数据域
struct Node* next; //指针域
};
int main()
{
struct Node node1 = { 1,NULL };
struct Node node2 = { 2,NULL };
struct Node node3 = { 3,NULL };
node1.next = &node2;
node2.next = &node3;
struct Node* pMove = &node1;
while(pMove!=NULL)
{
printf("%d\t", pMove->data);
pMove = pMove->next;
}
//1.链表是什么?
//2.链表怎么表示
//3.链表如何打印
return 0;
}
动态内存申请
#include <stdio.h>
#include <stdlib.h>
struct Node //节点结构体
{
int data;
struct Node* next;
};
1.没有在封装
用第一个节点表示整个链表
有头链表: 1.创建表头--->创建结构体变量
用指针表示结构体变量?
1.1用变量地址初始化,
1.2动态内存申请
//1.创建表头,即创建结构体变量
struct Node* createHead()
{
//1.动态内存申请
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//(*headNode).next = NULL;
headNode->next = NULL;//变量要初始化
return headNode; //返回变量
}
2.创建节点—>把用户数据加工成节点为插入准备
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL; //作为链表结束标志
return newNode;
}
//3.表头插入
//自己写时候,参数要能够解释出意思
//以headNode 为表头链表
//插入的数据是data
void insertByHead(struct Node* headNode,int data)
{
struct Node* newNode = createNode(data); //调用自己写的函数
//下面两句先后顺序不能交换
//先连后断
newNode->next = headNode->next;
headNode->next = newNode;
/*
headNode->next = newNode;
newNode->next = headNode->next; //newNode->next = newNode
*/
}
//4.表尾插入
void insertByTail(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);
struct Node* pTail = headNode;
while (pTail->next != NULL)
{
pTail = pTail->next;
}
pTail->next = newNode;
}
//5.指定位置插入
//data:插入的数据
//posData: 指定位置
void insertByAppoin(struct Node* headNode, int data, int posData)
{
//做这种查找类插入,先不要着急创建节点?考虑没找到情况
struct Node* frontNode = headNode; //左
struct Node* posNode = headNode->next; //右
//注意: && 短路处理
//posNode != NULL作为找到表尾的退出条件
//当posNode等于NULL ,NULL->data 的非法访问
//frontNode->next!=NULL&&posNode->data != posData
while (posNode != NULL && posNode->data != posData )//难点
{
//frontNode = frontNode->next;
//posNode = posNode->next;
frontNode = posNode;
posNode = frontNode->next; //posNode=posNode->next;
//frontNode 是posNode左边
//最后一节点:frontNode posNode就是NULL
}
//退出循环,分析讨论是否找到
if(posNode==NULL)
{
printf("%d\t", frontNode->data);
printf("未找到,无法插入信息!\n");
}
else
{
struct Node* newNode = createNode(data);
frontNode->next = newNode;
newNode->next = posNode;
}
}
删除操作:
打狗要看主人: 把一个节点下一个删除,要考虑删除节点上一节点next
不能删除NULL的东西
//6.表头删除
void deleteByHead(struct Node* headNode)
{
struct Node* nextNode = headNode->next;
if (nextNode != NULL) //防御性编程
{
headNode->next = nextNode->next;
free(nextNode);
nextNode = NULL;
}
}
//7.表尾删除
void deleteByTail(struct Node* headNode)
{
struct Node* frontNode = NULL;
struct Node* tailNode = headNode; //NULL;
//struct Node* tailNode = headNode->naxt; 会引发中断
while (tailNode->next != NULL) //NULL->next!=NULL
{
frontNode = tailNode;
tailNode = frontNode->next;
}
if (frontNode == NULL)
{
printf("表为NULL,删除失败\n");
}
else
{
frontNode->next = NULL;
free(tailNode);
tailNode = NULL;
}
}
//8.指定位置删除
void deleteByAppoin(struct Node* headNode, int posData)
{
struct Node* frontNode = headNode;
struct Node* posNode = headNode->next;
while (posNode != NULL && posNode->data != posData)
{
frontNode = posNode;
posNode = frontNode->next;
}
if (posNode == NULL)
{
printf("未找到,无法删除!\n");
}
else
{
frontNode->next = posNode->next;
free(posNode);
posNode = NULL;
}
}
//9.遍历--->打印
void printList(struct Node* headNode)
{
//为什么指向第二个节点? 因为第一个节点没有存数据
struct Node* pMove = headNode->next;
while (pMove != NULL)
{
printf("%d\t", pMove->data);
pMove = pMove->next;
}
printf("\n");
}
int main()
{
struct Node* list = createHead();
for (int i = 0; i < 3; i++)
{
insertByHead(list, i);
}
printList(list);
insertByTail(list, 100);
printList(list);
insertByAppoin(list, 99, 100);
printList(list);
insertByAppoin(list, 102, 112122);
insertByAppoin(list, 102, 2);
printList(list);
deleteByHead(list);
printList(list);
deleteByTail(list);
printList(list);
deleteByAppoin(list, 1);
printList(list);
return 0;
}
链表在项目当中的使用
链表:充当数据的容器
特点:灵活的存储数据
int date 改为 struct name date