链表
1,建立静态链表
#include <stdio.h>
struct Student
{
int num;
float score;
struct Student *next;//在结构体变量中定义一个本类型指针next,指针指向的是一个结构体变量
};
int main()
{
struct Student a, b, c, *p;
a.num = 10101; a.score = 89.5; a.next = &b;
b.num = 10103; b.score = 90; b.next = &c;
c.num = 10107; c.score = 85; c.next = NULL;//每个结构体变量中的next指针都指向下一个结构体变量,直到最后一个,指向NULL
struct Student *head = &a;//定义一个头指针
p = head;//p最开始为头指针,然后一个一个的指下去
do
{
printf("%ld\t%.1lf\n", p->num, p->score);//输出指针此时所指的结构体变量中的某个成员(仅通过指针的变化来输出其它)
p = p->next;//一个一个的指下去,为输出下一个结点做准备
}while(p != NULL);
return 0;
}
在声明结点的数据结构时,通常结合typedef以简化代码,,也使代码更清晰。
struct 结构名
{
数据类型1 变量1;
数据类型2 变量2;
struct 结构名 *next;
};
typedef struct 结构名 node;//简化结构体变量名(结点)
typedef node* link;//简化结构体指针名
struct Student
{
int num;
float score;
struct Student *next;
};
typedef struct Student node;
typedef node* link;
int main()
{
node a, b, c;
a.num = 10101; a.score = 89.5; a.next = &b;
b.num = 10103; b.score = 90; b.next = &c;
c.num = 10107; c.score = 85; c.next=NULL;
link head, p;
head = &a;
p = head;
2,建立动态链表
#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(struct Student)//规定每次开辟的空间大小(即结点大小)(sizeof是求字节数运算符)
struct Student
{
long num;
float score;
struct Student *next;
};
typedef struct Student node;//结点
typedef node* link;//结点的指针
int n = 0;//n为结点个数
/*思路:让p_new指向新开辟的结点,p_end指向链表中的最后一个结点,
再将p_new所指的结点连接在p_end所指的结点后面,用 p_end->next = p_new实现 */
link create(void)//定义指针类型函数(返回头指针)create 建立链表
{
link p_new, p_end, head = NULL;//先使head为NULL,这是链表为"空”时的情况(即链表中无结点),当建立第一个结点,就使head指向该结点
p_new = p_end = (link)malloc(LEN);//用malloc函数开辟第一个结点,并使p_new和p_end指向他(强制类型转换)
/*编译系统可以进行隐式的类型转换 因此可以:
p_new = p_end = malloc(LEN); */
scanf("%ld,%f", &p_new->num, &p_new->score);//输入数据给p_new所指的第一个结点
while (p_new->num != 0)//规定输入学号为0表示建立链表的过程完成
{
//若输入的学号不为0,则输入的是结点数据
n ++;//若输入的学号不为0,则结点数+1 ,n为结点个数
if (n == 1)
head = p_new;//将head指向第一个结点
else
p_end->next = p_new;//若该结点不是第一个结点,就将该结点连接到上一个结点的表尾(next和p1均为指针变量)
p_end = p_new;//将p_new所指向的结点交给p_end来指向,即p_end为链表的最后一个结点
p_new = (link)malloc(LEN);//p1去指向另一个新开辟的结点
scanf("%ld,%f", &p_new->num, &p_new->score);//再向这个新开辟的结点中输入数据
}
p_end->next = NULL;//建立链表结束后,使上一个结点中的next指针指向空NULL
free(p_new); //释放掉没有用到的空间
return (head);//链表已建立完成,知道表头head就可以调动一整串链表,因此仅返回第一个结点的起始地址就好
}
void print(link head)//定义一个指针类型的函数print 输出链表
{
link p;
p = head;//p从head处开始,即指向第一个结点
if (head != NULL)//保证链表不为空
{
do
{
printf("\nnum:%ld\nscore:%.1f\n", p->num, p->score);//输出p此时所指的结点中的信息
p = p->next;//p再指向下一个结点,再输出
}while (p != NULL);//直到链表的尾结点中的next指针指向NULL
}
}
int main()
{
link pt;
pt = create();//指针指向所创建的链表的表头
print(pt);
return 0;
}
3,链表的相关操作
1,插入结点
//功能:输入某个学号(结点),则会在该结点后插入一个结点,再在该结点中存入学号、成绩,输出时所有成绩会按结点连接顺序输出
struct Student* insert(long k, struct Student *head)//返回头指针
{
struct Student *p, *temp;
if (head != NULL)
{
if (k == 0)//在第一个结点之前插入结点
{
p = (struct Student*)malloc(LEN);//先开辟再连接
printf("请输入您想要插入的数据:\n");
scanf("%ld,%f", &p->num, &p->score);
p->next = head;
head = p;//头指针发生改变
}
else
{
p = head;
while (p->num != k)
p = p->next;//移到下一个结点
temp = p->next;//将原本要指向的下一个结点记为temp
p->next = (struct Student*)malloc(LEN);//在中间建立新的空间,存入结点数据
p = p->next;//移到新开辟的结点
printf("请输入您想要插入的数据:\n");
scanf("%ld,%f", &p->num, &p->score);//让结点里的指针指向这个新创建的空间(即新的结点)
p->next = temp; //这个新结点再指向temp
}
}
return head;//返回头指针
}
2,删除结点
//删除节点函数
//功能:输入一个学号(节点),则链表中会删去结点,即输出成绩时不会输出该同学的成绩
struct Student* del(long k, struct Student *head)
{
struct Student *p = head, *temp;
if (head->num == k)//若删除的是第一个结点
{
head = head->next;//则要改变head
free(p);//释放掉被删除的结点的空间
return(head);//返回head,即新表头的地址,主函数中输出时,从新表头开始输出
//同时也终止函数的运行
}
if (head != NULL)
{
while ((p->next)->num != k)
p = p->next;
temp = p->next;
p->next = (p->next)->next;//遇到需要删除的结点时,前一个结点里的指针指的是下下个结点的地址,即跳过需要删除的结点
free(temp);//释放掉被删除的结点的空间
}
return(head);
}