文章目录
一、静态链表
1.认识链表
类型 | 区别 |
---|---|
有头链表 | 没有存数据、表头节点无数据域 |
无头链表 | 存数据、表头节点有数据域 |
2.链表怎么表示
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;
3.链表如何打印
一般通过移动指针操作
struct Node* pMove = &node1;
while (pMove != NULL)
{
printf("%d\t", pMove->data);
pMove = pMove->next;
}
二、动态链表
意思:自动链接 用户只需要输入就可
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.创建节点
//2创建节点—>把用户数据加工节点
//为插入准备 指针作为链表结束标志
2.创建节点 把用户数据加工成节点 未插入做准备
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL; //作为链表结束标志
return newNode;
}
3.表头插入
要插入的节点,表头节点(链表)
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.表尾插入
要插入的节点,表尾节点
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.指定位置插入
/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;
}
}
6.表头删除
打狗要看主人: 把一个节点下一个删除,要考虑删除节点上一节点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.表尾删除
7.表尾删除
void deleteByTail(struct Node* headNode)
{
struct Node* frontNode = NULL;
struct Node* tailNode = headNode; //NULL;
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.指定位置删除
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.遍历.打印
9.遍历--->打印
void printList(struct Node* headNode)
{
//为什么指向第二个节点? 因为第一个节点没有存数据
struct Node* pMove = headNode->next;
while (pMove != NULL)
{
printf("%d\t", pMove->data);
pMove = pMove->next;
}
printf("\n");
}
10.测试
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;
}
三、链表在项目中的使用
链表: 充当数据的容器
可以灵活存取数据
管理系统
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct MM
{
char name[20];
int age;
int num;
char addr[20];
};
struct Node
{
//int data;
struct MM data;
struct Node* next;
};
struct Node* list = NULL;
struct Node* createHead()
{
//1.动态内存申请
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//(*headNode).next = NULL;
headNode->next = NULL;
return headNode;
}
struct Node* createNode(struct MM data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL; //作为链表结束标志
return newNode;
}
void insertByHead(struct Node* headNode, struct MM data)
{
struct Node* newNode = createNode(data); //调用自己写的函数
//下面两句先后顺序不能交换
//先连后断
newNode->next = headNode->next;
headNode->next = newNode;
}
//8.指定位置删除
void deleteByName(struct Node* headNode, char *mmName)
{
struct Node* frontNode = headNode;
struct Node* posNode = headNode->next;
while (posNode != NULL && strcmp(posNode->data.name , mmName))
{
frontNode = posNode;
posNode = frontNode->next;
}
if (posNode == NULL)
{
printf("未找到,无法删除!\n");
}
else
{
frontNode->next = posNode->next;
free(posNode);
posNode = NULL;
}
}
struct Node* searchByName(struct Node* headNode, char* mmName)
{
struct Node* pMove = headNode->next;
while (pMove != NULL && strcmp(pMove->data.name, mmName))
{
pMove = pMove->next;
}
return pMove;
}
//9.遍历--->打印
void printList(struct Node* headNode)
{
//为什么指向第二个节点? 因为第一个节点没有存数据
struct Node* pMove = headNode->next;
//表头
printf("姓名\t年龄\t编号\t地址\n");
while (pMove != NULL)
{
//printf("%d\t", pMove->data);
printf("%s\t%d\t%d\t%s\n", pMove->data.name, pMove->data.age, pMove->data.num, pMove->data.addr);
pMove = pMove->next;
}
printf("\n");
}
void makeMenu()
{
printf("------------MM 管理系统 ---------\n");
printf("\t\t0.退出系统\n");
printf("\t\t1.录入系统\n");
printf("\t\t2.浏览信息\n");
printf("\t\t3.删除信息\n");
printf("\t\t4.修改信息\n");
printf("\t\t5.查找信息\n");
printf("-----------------------------------\n");
}
void keyDown()
{
int userKey = 0;
struct MM tempData;
struct Node* result = NULL;
scanf("%d", &userKey);
switch (userKey)
{
case 0:
printf("正常退出!\n");
system("pause");
exit(0);
break;
case 1:
printf("name,age,num,addr:");
scanf("%s%d%d%s", tempData.name, &tempData.age, &tempData.num, tempData.addr);
insertByHead(list, tempData);
break;
case 2:
printList(list);
break;
case 3:
printf("input Name:");
scanf("%s", tempData.name);
deleteByName(list, tempData.name);
break;
case 4:
printf("input Name:");
scanf("%s", tempData.name);
result = searchByName(list, tempData.name);
if (result == NULL)
{
printf("未找到\n");
}
else
{
printf("input new name,age,num,addr:");
scanf("%s%d%d%s", result->data.name, &result->data.age, &result->data.num, result->data.addr);
}
break;
case 5:
printf("input Name:");
scanf("%s", tempData.name);
result = searchByName(list, tempData.name);
if (result == NULL)
{
printf("未找到\n");
}
else
{
printf("姓名\t年龄\t编号\t地址\n");
printf("%s\t%d\t%d\t%s\n", result->data.name, result->data.age, result->data.num, result->data.addr);
}
break;
default:
printf("请重新输入!\n");
break;
}
}
int main()
{
list = createHead();
while (1)
{
makeMenu();
keyDown();
system("pause");
system("cls");
}
return 0;
}