学习C(十八)

链表的概念:

链表是一个动态的数据结构,他和数组的区别在于:链表不需要确定数据结构的大小,他是需要存放数据再申请空间,而数组是先申请足够大的空间,再存放数据
  但是链表中的所有模块的地址是不连续的(数组是连续的)。
往链表中存放新的节点的步骤:
  ① 先要确定有头节点,没有则创建。有了头节点后,才能操作整个链表
  ② 如果这张链表的数据存放有防重复机制的话,先输入防重复数据的值,确定不重复之后,再使用malloc创建新的节点newNode。
  ③ 完善malloc出来的模块中的数据域的数据
  ④ 将newNode链接到链表中(具体是哪一张链表取决于传入的头节点)
  如何链接到链表中:两种方式
    1: 头插法 将新的的节点添加到头节点的后面
    2:尾插法 将新的节点添加到尾节点的后面

数据结构:是一门计算机专业的学科,
其主要研究对象为:如何管理批量同类型元素
主要从两个方面深入研究:

  1. 元素间的逻辑关系:
    a. 同属一个集合 0 ~ 0
    b. 元素间是线性关系(线性表) 1 对 1
    c. 元素间是树形关系  1 对 n
    d. 元素间是图形关系  m 对 n
  2. 存储方式
    1. 顺序存储
      批量同类型元素在一块连续的内存空间顺序摆放
    2. 链式存储
      批量同类型元素不一块连续的内存空间中,
      但每个元素都保存着另一个元素在内存空间的首地址

线性表:

  1. 顺序存储的线性表 ---- 顺序表(数组)

  2. 链式存储的线性表 ----- 链表

链表中的元素 ---- 节点 — Node
  节点类型一定是结构体,该结构体中至少有一个成员用来保存其它节点的地址
这些用来保存其它节点地址的成员称为指针域(地址域)
其它成员统称为数据域,用来描述具体的事物

分类:

  1. 按指针域成员个数分为:
    a. 单向链表
    b. 双向链表

  2. 按首尾是否相接分为:
    a. 循环链表
    b. 非循环链表

  3. 按是否有头节点分为:
    a. 有头节点链表
    b. 无头节点链表

单向链表的使用案例

按照学生姓名查找学生,添加学生信息,修改学生的信息,删除学生,按成绩排序,加载,保存,

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//数据域
typedef struct Data{
	char name[20];
	int age;
	int score;
}data_t;
//单向链表域
typedef struct Stu{
	data_t data;
	struct Stu* next;
}stu_t;
//创建一个头节点
stu_t* init(){
	stu_t* head = calloc(1,sizeof(stu_t));
	head->next = 0;
	return head;
}
//按学生姓名查找
stu_t* findStu(stu_t* head){
	char name[20] = {0};
	printf("请输入要查找的学生姓名:");
	scanf("%s",&name);
    while(getchar()!=10);
	stu_t* p = head->next;//第二个节点
	while(p != NULL){
		if(strcmp(name,p->data.name)==0){//注意头节点没有比较到
			return p;//找到就返回这个节点的地址
		}
		p = p->next;
	}
	return NULL;//没找到就返回NULL
}
//修改分数
void updateStu(stu_t* head){
	int score = 0;
	stu_t* tar = findStu(head);//调用了函数帮忙查找(注意头没有找,因为没放数据)
	printf("请输入新的分数:");
	scanf("%d",&score);
	while(getchar()!=10);
	if(tar==NULL){return ;}
	tar->data.score = score;
}

//用冒泡排序来排序学生成绩
void sortStu(stu_t* head){
	stu_t* p = head->next;//第二个节点
	stu_t* q = p;//第二个节点
	data_t temp = {0};//数据域,作为临时交换数据
	if(q == NULL){return;}
	while(p->next != NULL){//i<len-1
		q = head->next;//初始化
		while(q->next != NULL){//j<len-1
			if(q->data.score < q->next->data.score){
				temp = q->data;
				q->data = q->next->data;
				q->next->data = temp;
			}
			q=q->next;
		}
		p=p->next;
	}
}
//删除学生
void removeStu(stu_t* head){
	char name[20] = {0};
	printf("请输入要删除的学生姓名:");
	scanf("%s",&name);
    while(getchar()!=10);
	stu_t* p = head;
	stu_t* temp = 0;//用来指向要删除的学生
	while(p->next != NULL){
		if(strcmp(p->next->data.name,name)==0){
			temp = p->next;
			p->next = p->next->next;
			free(temp);//释放节点就是删除的操作
		}
		p=p->next;
		if(p==NULL){break;}
	}
}
//释放整个链表
void freeStu(stu_t* head){
	stu_t* p = head->next;
	stu_t* temp = 0;
	while(p!= NULL){
		temp = p;
		p = p->next;
 		free(temp);
	}
	free(head);
}
//添加学生信息
void insertStu(stu_t* head){
	stu_t* newNode = malloc(sizeof(stu_t));
	memset(newNode,0,sizeof(stu_t));
	char name[20] = {0};
	printf("请输入姓名:");
	scanf("%s",name);
    while(getchar()!=10);
	int age = 20;
	static int score = 85;
	score++;
	strcpy(newNode->data.name,name);
	newNode->data.age = age;
	newNode->data.score = score;
	//头插法,插在头节点的下一个节点
/*	newNode->next = head->next;
	head->next = newNode;*/
    //尾插法,插在尾节点的下一个位置
	stu_t* p = head;
	while(p->next != NULL){
		p = p->next;
	};
	p->next = newNode;
	newNode->next = NULL;
}
//打印学生信息
void printStu(stu_t* head){
	stu_t* p = head->next;
	while(p!=NULL){
		printf("******\n");
		printf("姓名:%s\n",p->data.name);
		printf("成绩:%d\n",p->data.score);
		p=p->next;
	}
	printf("******\n");
}

//保存到文件中
void saveStu(stu_t* head){
	FILE* fp = fopen("./stuDB.txt","w");
	stu_t* p = head->next;
	while(p != NULL){
		fwrite(&(p->data),sizeof(data_t),1,fp);
		//fprintf(fp,"%s %d %d\n",p->data.name,p->data.age,p->data.score);
		p = p->next;
	}
	fclose(fp);
}

//加载的意思是加载到原有链表的后面
void loadStu(stu_t* head){
	int retval = 0;
	data_t data = {0};
	stu_t* p = head;
	while(p->next!=NULL){
		p = p->next;
	}
	FILE* fp = fopen("./stuDB.txt","r");//加载以只读的方式打开
	if(fp == 0){return;}
	while(1){	
		retval = fread(&data,sizeof(data_t),1,fp);
		if(retval == 0){break;}
		stu_t* newNode = malloc(sizeof(stu_t));
		memset(newNode,0,sizeof(stu_t));
		newNode->data = data;
		p->next = newNode;
		newNode->next = NULL;
		p = p->next;
	}
	fclose(fp);
}

//单向链表至始至终头结点都没有存放数据
int main(){
	stu_t* head = init();//创建头节点
	insertStu(head);//添加学生信息
	insertStu(head);//添加学生信息
	insertStu(head);//添加学生信息
	printStu(head);//打印学生信息
	removeStu(head);//删除学生
	sortStu(head);//排序学生成绩
	loadStu(head);//加载
	printStu(head);//打印学生信息
	saveStu(head);//保存
	freeStu(head);//释放链表
	return 0;
}

单向链表的逆序排序

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct Data{
	char name[20];
	int age;
	int score;
}data_t;

typedef struct Stu{
	data_t data;
	struct Stu* next;
}stu_t;

void insertStu(stu_t* head){
	stu_t* newNode = malloc(sizeof(stu_t));
	memset(newNode,0,sizeof(stu_t));
	char name[20] = {0};
	printf("请输入姓名:");
	scanf("%s",name);
    while(getchar()!=10);
	int age = 20;
	static int score = 85;
	score++;
	strcpy(newNode->data.name,name);
	newNode->data.age = age;
	newNode->data.score = score;
	//头插法
/*	newNode->next = head->next;
	head->next = newNode;*/
	stu_t* p = head;
	while(p->next != NULL){
		p = p->next;
	};
	p->next = newNode;
	newNode->next = NULL;
}

void printStu(stu_t* head){
	stu_t* p = head->next;
	while(p!=NULL){
		printf("******\n");
		printf("姓名:%s\n",p->data.name);
		printf("成绩:%d\n",p->data.score);
		p=p->next;
	}
	printf("******\n");
}
/*
	封装函数实现功能:将链表逆序
*/
void exchange(stu_t* head){
	stu_t* p = head;
	stu_t* q = head;
	stu_t* k = NULL;
	while(1){
		p = head;
		while(p->next!=NULL){
			k = p;
			p = p->next;
		}
		p->next = q->next;
		q->next = p;
		k->next = NULL;
		q = q->next;
		if(k == q->next){break;}
	}
}

int main(){
	stu_t* head = malloc(sizeof(stu_t));
	memset(head,0,sizeof(stu_t));

	insertStu(head);
	insertStu(head);
	insertStu(head);
	insertStu(head);
	insertStu(head);
	exchange(head);
	printStu(head);

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值