数据结构学习日记--单向循环链表

一、单向循环链表

1.单向循环链表模型

基本与单项非循环链表一致,唯一区别是链表最后一个节点指向头节点,而不是NULL

2.模型设计

struct list_node{
    int data;
    struct list_node*next;
    
};

3.单向循环链表的增删设计

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>


struct list_node{
	char name[10];
	char sex;
	char tel[12];
	char friendship[20];
	struct list_node *next;
};

void insert_buf_to_list(struct list_node *head,char *buf)
{
	//1. 为新节点申请空间。
	struct list_node *new = malloc(sizeof(struct list_node));
	if(new == NULL)
		printf("malloc new error!\n");

	//2. 为数据域与指针域赋值。
	char seqs[] = ",";
	char *tmp = strtok(buf,seqs);  //tmp就是zhangsan
	strcpy(new->name,tmp);

	tmp = strtok(NULL,seqs);  //tmp就是M
	new->sex = *tmp;

	tmp = strtok(NULL,seqs);  //tmp就是10086
	strcpy(new->tel,tmp);
	
	tmp = strtok(NULL,seqs);  //tmo就是pengyou
	strcpy(new->friendship,tmp);
	
	new->next = NULL;

	//3. 寻找最后一个节点。
	struct list_node *p = NULL;
	for(p=head;p->next!=NULL;p=p->next);

	//4. 只需要让最后一个节点的指针域指向new。
	p->next = new;

	return;
}

void read_file(struct list_node *head,char *filename)  //filename = "zhangsan.txt"
{
	//1. 打开文件。
	FILE *fp = fopen(filename,"r");
	if(fp == NULL)
		printf("fopen error!\n");

	//2. 读取文件的内容。
	char buf[100] = {0};
	fread(buf,20,5,fp);  //buf: zhangsan,M,10086,pengyou

	//3. 关闭文件。
	fclose(fp);

	//4. 将buf的内容拆分之后,然后存放在链表中。
	insert_buf_to_list(head,buf);

	return;
}

struct list_node *init_list_head()
{
	//1. 为头节点申请空间。
	struct list_node *head = malloc(sizeof(struct list_node));
	if(head == NULL)
		printf("malloc head error!\n");

	//2. 为指针域赋值。
	head->next = NULL;

	return head;
}

void show_list_node(struct list_node *head)
{
	struct list_node *p;
	for(p=head->next;p!=NULL;p=p->next)
	{
		printf("%s,%c,%s,%s\n",p->name,p->sex,p->tel,p->friendship);
	}
}

void delete_list(struct list_node *head)
{
	struct list_node *p = NULL;
	struct list_node *q = NULL;
	for(q=p=head;p!=NULL;p=q)
	{
		q = p->next;
		free(p);
	}	
	return;
}

void insert_new_data_to_list_and_file(struct list_node *head,char *name,char sex,char *tel,char *friendship)
{
	//1. 为新节点申请空间。
	struct list_node *new = malloc(sizeof(struct list_node));
	if(new == NULL)
		printf("malloc new error!\n");

	//2. 为数据域域和指针域赋值。
	strcpy(new->name,name);
	new->sex = sex;
	strcpy(new->tel,tel);
	strcpy(new->friendship,friendship);
	new->next = NULL;

	//3. 寻找最后一个节点。
	struct list_node *p = NULL;
	for(p=head;p->next!=NULL;p=p->next);

	//4. 让最后一个节点的指针域指向new。
	p->next = new;

	//5. 拼接文件名字符串。
	char filename[50] = {0};
	sprintf(filename,"%s.txt",new->name);

	//6. 拼接文件的内容。
	char filebuf[50] = {0};
	sprintf(filebuf,"%s,%c,%s,%s",new->name,new->sex,new->tel,new->friendship);

	//7. 打开文件。
	FILE *fp = fopen(filename,"w");
	if(fp == NULL)
		printf("fopen filename error!\n");

	//8. 将准备好的数据写入到文件中。
	fwrite(filebuf,strlen(filebuf),1,fp);

	//9. 关闭文件。
	fclose(fp);

	return;
}

int main(int argc,char *argv[])
{
	//0. 初始化链表头。
	struct list_node *head = NULL;
	head = init_list_head();

	//1. 打开目录。
	DIR *dp = opendir("./usr_data/");
	if(dp == NULL)
		printf("opendir error!\n");

	//2. 切换到目录中。
	chdir("./usr_data/");   //在程序中切换到usr_data目录下。

	//3. 读取目录,将目录下的文件名读取出来。
	struct dirent *ep = NULL;
	while(1)
	{
		printf("#\n");
		ep = readdir(dp);   
		if(ep == NULL)   //已经读取完了整个目录
		{
			break;
		}

		if(ep->d_name[0] == '.')  //如果读取到.开头的文件,就继续读取下一个目录项。
		{
			continue;
		}

		read_file(head,ep->d_name);
	}

	//4. 遍历整条链表。
	printf("-------------第一题--------------\n");
	show_list_node(head);
	
	//5. 插入一个新人物到链表和文件中。
	printf("-------------第二题--------------\n");
	insert_new_data_to_list_and_file(head,"huangqi",'M',"56789","laodi");
	show_list_node(head);

	//6. 释放整条链表空间。
	delete_list(head);
	
	//7. 关闭目录。
	closedir(dp);

	return 0;
}

单向循环链表实现图片的切换,小程序的实现

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/input.h>

//设计节点
struct list_node
{
	char picname[20];
	struct list_node *next;
};

struct list_node *init_list_head()
{
	//1. 为头节点申请空间。
	struct list_node *head = malloc(sizeof(struct list_node));
	if (head == NULL)
		printf("malloc head error!\n");

	//2. 为头节点赋值。
	head->next = NULL;

	return head;
}

void insert_picname_to_list(struct list_node *head, char *picname)
{
	//1. 为新节点申请空间。
	struct list_node *new = malloc(sizeof(struct list_node));
	if (new == NULL)
		printf("malloc new error!\n");

	//2. 为新节点的数据域与指针域赋值。
	strcpy(new->picname, picname);
	new->next = NULL;

	//3. 寻找最后一个节点。
	struct list_node *p = NULL;
	for (p = head; p->next != NULL; p = p->next)
		;

	//4. 让最后一个节点的指针域指向new。
	p->next = new;

	return;
}

void show_list_node(struct list_node *head)
{
	struct list_node *p = NULL;
	for (p = head->next; p != NULL; p = p->next)
	{
		printf("picname:%s\n", p->picname);
	}
	return;
}

void mmap_show_bmp(const char *picname)
{
	char bmp_buf[800 * 480 * 3] = {0}; //图片每一个像素点都是由3个字节组成,所以一共有800*480*3个字节。
	char lcd_buf[800 * 480 * 4] = {0}; //lcd每一个像素点都是由4个字节组成,所以一共有800*480*4个字节。
	char show_buf[800 * 480 * 4] = {0};
	int x, y;
	int i, j, k;

	//1. 访问图片文件。
	FILE *fp = fopen(picname, "r"); //当前的光标在最开头
	if (fp == NULL)
		printf("fopen error!\n");

	//2. 访问lcd液晶设备
	int lcd = open("/dev/fb0", O_RDWR);
	if (lcd < 0)
		printf("open lcd error!\n");

	//3. 跳过54个头数据。
	fseek(fp, 54, SEEK_SET);

	//4. 将图片的数据读取到一个缓冲区中。
	int n = fread(bmp_buf, 800 * 480 * 3, 1, fp);
	if (n != 1)
		printf("fread error!\n");

	//5. 24位转32位
	for (i = 0, j = 0; i < 800 * 480 * 4; i += 4, j += 3)
	{
		lcd_buf[i] = bmp_buf[j];
		lcd_buf[i + 1] = bmp_buf[j + 1];
		lcd_buf[i + 2] = bmp_buf[j + 2];
		lcd_buf[i + 3] = 0;
	}

	//6. 上下颠倒
	for (y = 0; y < 480; y++)
	{
		for (x = 0; x < 800 * 4; x++)
		{
			show_buf[800 * 4 * (479 - y) + x] = lcd_buf[800 * 4 * y + x];
		}
	}

	//7. 内存映射
	char *p = mmap(NULL, 800 * 480 * 4, PROT_WRITE | PROT_READ, MAP_SHARED, lcd, 0);
	if (p == (void *)-1)
		printf("mmap error!\n");

	//8. 不断将show_buf的内容拷贝到内存空间。
	for (k = 0; k < 800 * 480 * 4; k++)
	{
		memcpy(p + k, &show_buf[k], 1);
	}

	//9. 撤销映射
	munmap(p, 800 * 480 * 4);

	//10.关闭文件。
	close(lcd);
	fclose(fp);

	return;
}

int map_turn(struct list_node *head)
{
	struct list_node *p = head->next; //让p指向头节点的下一个节点。
	struct list_node *q = NULL;
	struct list_node *last;
	for (last = head; last->next != NULL; last = last->next)
		;

	mmap_show_bmp(p->picname);

	//6. 打开触摸屏
	int fd = open("/dev/input/event0", O_RDWR);
	if (fd < 0)
		printf("open event0 error!\n");

	//7. 读取触摸屏的数据。
	struct input_event buf;
	int touch_x, touch_y;
	while (1)
	{

		read(fd, &buf, sizeof(buf));
		if (buf.type == EV_ABS && buf.code == ABS_X)
			touch_x = buf.value;
		if (buf.type == EV_ABS && buf.code == ABS_Y)
			touch_y = buf.value;

		if (buf.type == EV_KEY && buf.code == BTN_TOUCH && buf.value == 0)
		{

			if (touch_x < 500)
			{
				if (p == head->next)
				{
					p = last;
				}
				else
				{
					for (q = head->next; q != p; q = q->next)
						{
							if(q->next==p){
								p=q;
							}
						}
				}
			}
			if (touch_x >= 500)
			{
				if (p->next == NULL) //如果是,说明当前正在显示最后一张
				{
					p = head->next; //就把第一张赋值给p。
				}
				else
				{				 //如果当前不是最后一张
					p = p->next; //直接下一张就可以。
				}
				
			}
			mmap_show_bmp(p->picname);
			//
		}
	}
	return 0;
}
int main(int argc, char *argv[])
{
	//1. 初始化链表头。
	struct list_node *head = NULL;
	head = init_list_head();

	//2. 打开目录。
	DIR *dp = opendir("/IOT/bmp_data");
	if (dp == NULL)
		printf("opendir error!\n");

	//3. 切换到目录中。
	chdir("/IOT/bmp_data");

	//4. 读取目录下的文件名
	struct dirent *ep = NULL;
	while (1)
	{
		ep = readdir(dp);
		if (ep == NULL) //说明目录已经读取完毕
		{
			break;
		}

		if (ep->d_name[0] == '.')
		{
			continue; // 如果读取到.开头的文件,我不要。
		}

		insert_picname_to_list(head, ep->d_name);
	}

	//5. 到目前为止: 链表已经有这些图片的名字。
	map_turn(head);
	//8. 关闭目录
	closedir(dp);

	return 0;
}

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值