1、什么是链表?
链表就是结构体变量与结构体变量连接在一起形成的一串表
如下图创建一个简单的静态链表:
一个简单的链表是由头结点,若干个结点和尾结点构成,其中需要注意的是:中间的结点必须要有数据域和指针域,尾结点必须指向空。代码如下:
#include <stdio.h>
struct Node{
int data; //数据域
struct Node* next; //指针域
};
int main()
{
/*静态链表*/
struct Node Node1={1,NULL}; //创建的结构体变量
struct Node Node1={2,NULL};
struct Node Node1={3,NULL};
Node1.next = &Node2; //表1的指针要指向下一个表的首地址
Node2.next = &Node3;
return 0;
}
2、如何动态创建一个链表:
动态内存链表无非就是动态内存申请和模块化设计:
2.1. 创建链表(创建一个表头表示整个链表)
/*创建链表*/
struct Node* createList()
{
//动态内存申请使得headnode从结构体指针变成结构体变量
struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));
//变量使用前必须被初始化
headNode->data = 1;
headNode->next = NULL;
return headNode;
}
2.2. 创建结点(形成新的结点)
/*创建结点*/
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof (struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
2.3. 插入结点(分别有头部插入,尾部插入,指定位置插入,本例使用头部插入)
/*(表头法插入)插入结点,参数:插入那个链表,插入结点的数据是多少*/
void insertNodeByHead(struct Node* headNode,int data)
{
//创建插入的结点
struct Node* newNode=createNode(data); //子函数
newNode->next = headNode->next; //新结点的下一个就是头结点的下一个
headNode->next = newNode; //头结点的下一个就是新结点
}
2.4. 删除结点(指定位置删除)
/*链表删除*/
void deleteNodeByappoint(struct Node* headNode,int posData)
{
struct Node* posNode=headNode->next; //定义指定结点为头结点的下一结点
struct Node* posNodeFront=headNode; //定义指定结点的前一个结点为头结点
/*判断当指定结点为空的时候无法删除*/
if(posNode==NULL)
printf("无法删除链表为空");
else
{
/*判断当指定结点的数据不等于指定的数据则开始循环直到指定结点数据与指定数据相等*/
while(posNode->data != posData)
{
posNodeFront = posNode; //指定结点的前一结点为指定结点
posNode =posNode->next; //指定结点为指定节点的下一结点
/*当指定结点为空则无法打印*/
if(posNode==NULL)
{
printf("未找到指定位置,无法打印\n");
break;
}
}
posNodeFront->next = posNode->next;
free(posNode); //删除指定结点
}
}
2.5. 打印遍历链表(用来测试)
/*打印链表*/
void printfList(struct Node* headNode)
{
struct Node* pMove=headNode->next; //定义一个移动的指针
while(pMove)
{
printf("%d\t",pMove->data);
pMove = pMove->next;
pMove = pMove->next;
}
printf("\n");
}
代码如下:
#include <stdio.h>
#include <stdlib.h>
struct Node{
int data; //数据域
struct Node* next; //指针域
};
/*创建链表*/
struct Node* createList()
{
//动态内存申请使得headnode从结构体指针变成结构体变量
struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));
//变量使用前必须被初始化
headNode->data = 1;
headNode->next = NULL;
return headNode;
}
/*创建结点*/
struct Node* createNode(int data)
{
struct Node* newNode = (struct Node*)malloc(sizeof (struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
/*打印链表*/
void printfList(struct Node* headNode)
{
struct Node* pMove=headNode->next; //定义一个移动的指针
while(pMove)
{
printf("%d\t",pMove->data);
pMove = pMove->next;
pMove = pMove->next;
}
printf("\n");
}
/*(表头法插入)插入结点,参数:插入那个链表,插入结点的数据是多少*/
void insertNodeByHead(struct Node* headNode,int data)
{
//创建插入的结点
struct Node* newNode=createNode(data); //子函数
newNode->next = headNode->next; //新结点的下一个就是头结点的下一个
headNode->next = newNode; //头结点的下一个就是新结点
}
/*链表删除*/
void deleteNodeByappoint(struct Node* headNode,int posData)
{
struct Node* posNode=headNode->next; //定义指定结点为头结点的下一结点
struct Node* posNodeFront=headNode; //定义指定结点的前一个结点为头结点
/*判断当指定结点为空的时候无法删除*/
if(posNode==NULL)
printf("无法删除链表为空");
else
{
/*判断当指定结点的数据不等于指定的数据则开始循环直到指定结点数据与指定数据相等*/
while(posNode->data != posData)
{
posNodeFront = posNode; //指定结点的前一结点为指定结点
posNode =posNode->next; //指定结点为指定节点的下一结点
/*当指定结点为空则无法打印*/
if(posNode==NULL)
{
printf("未找到指定位置,无法打印\n");
break;
}
}
posNodeFront->next = posNode->next;
free(posNode); //删除指定结点
}
}
int main()
{
struct Node* list = createList();
insertNodeByHead(list,1);
insertNodeByHead(list,2);
insertNodeByHead(list,3);
printfList(list);
deleteNodeByappoint(list,2);
printfList(list);
system("pause");
return 0;
}
3、学习链表有什么作用?
- 链表可以解决数组无法存储多种数据类型的问题
- 链表可以解决数组元素个数无法改变的限制
- 数组移动元素的过程中要对元素进行大范围的移动,很耗时间,效率也不高
用链表写一个关于学生成绩的排名,我们只需要把对应的变量添加进去就可以了:
#include <stdio.h>
#include <stdlib.h>
struct student
{
char name[20];
int num;
int math;
};
struct Node{
struct student data; //数据域
struct Node* next; //指针域
};
/*创建链表*/
struct Node* createList()
{
//动态内存申请使得headnode从结构体指针变成结构体变量
struct Node* headNode=(struct Node*)malloc(sizeof(struct Node));
//变量使用前必须被初始化
//headNode->data = 1;
headNode->next = NULL;
return headNode;
}
/*创建结点*/
struct Node* createNode(struct student data)
{
struct Node* newNode = (struct Node*)malloc(sizeof (struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
/*打印链表*/
void printfList(struct Node* headNode)
{
struct Node* pMove=headNode->next; //定义一个移动的指针
printf("name\tnum\tmath\n");
while(pMove)
{
printf("%s\t%d\t%d\n",pMove->data.name,pMove->data.num,pMove->data.math);
pMove = pMove->next;
}
printf("\n");
}
/*插入结点*/
void insertNodeByHead(struct Node* headNode, struct student data)
{
struct Node* newNode=createNode(data);
newNode->next = headNode->next;
headNode->next = newNode;
}
/*链表删除*/
void deleteNodeByappointnum(struct Node* headNode,int num)
{
struct Node* posNode=headNode->next;
struct Node* posNodeFront=headNode;
if(posNode==NULL)
(posNode==NULL)
printf("无法删除链表为空");
else
{
while(posNode->data.num != num)
{
posNodeFront = posNode;
posNode =posNode->next;
if(posNode==NULL)
{
printf("未找到指定位置,无法打印\n");
break;
}
}
posNodeFront->next = posNode->next;
free(posNode);
}
}
int main()
{
struct Node* list = createList();
struct student info;
while(1)
{
printf("请输入学生的姓名 学号 数学成绩:");
setbuf(stdin,NULL);
scanf("%s%d%d",info.name,&info.num,&info.math);
insertNodeByHead(list,info);
printf("continue(Y/N)?\n");
setbuf(stdin,NULL);
int choice = getchar;
scanf("%d",&choice);
if( choice == 'N' || choice == 'n' )
break;
}
printfList(list);
system("pause");
return 0;
}