2021年11月29日到2021年12月5日学习笔记

               单链表

        本周主要想学习一下链表的基础知识,首先见识到的就是单链表,而实现的第一种方法就是头插法,关于头插法的一些理解,已经写到了注释里面

#include<stdio.h>
#include<stdlib.h>
void getInput(struct Book* book);
void addBook(struct Book** library);
void printLibrary(struct Book* library);
void releaseLibrary(struct Book** library);
struct Book {
		char title[128];
		char author[40];//前两行为信息域
		struct Book* next;//指针域,指向下一个信息域,直到指向NULL,显然,我们需要一个
		//头指针,指向第一个指针域,同样,我们的头插法便是对这个头指针进行操作,
		//改变我们头指针指向的值,最终在链表中插入一个新元素
};
void getInput(struct Book* book) {
	printf("请输入书名:");
	scanf_s("%s", book->title, 128);
	printf("请输入作者:");
	scanf_s("%s", book->author, 40);
}
void addBook(struct Book **library) {
	//插入一个新值的时候,我们需要改变头指针的值,所以这里传入的是一个二级指针
	struct Book* book, * temp;
	book = (struct Book*) malloc (sizeof(struct Book));
	if (book == NULL) {
		printf("内存分配失败了!\n");
		exit(1);
	}
	getInput(book);
	if (*library != NULL) {
		temp = *library;//temp存储的就是头指针指向的这个信息域的地址
		*library = book;//把book即新增加的这个节点的信息域赋给library也就是我们的头指针
		book->next = temp;//这个时候把指针域指向原来的第一个节点,完成增加元素的目的
		//所以,这种增加元素的方式是将新增的元素排列到最顶端的,故称为头插法,
		//当然,还有尾插法的啦
	}
	else {
		*library = book;
		book->next = NULL;
	}
}
void printLibrary(struct Book* library) {
	struct Book* book;
	int count = 1;
	book = library;
	while (book != NULL) {
		printf("Book%d:\n", count);
		printf("书名:%s", book->title);
		printf("作者:%s", book->author);
		book = book->next;
		count++;
	}
}
void releaseLibrary(struct Book** library) {
 struct Book *temp;
	while (library != NULL) {
 temp = *library;
	*library = (*library)->next;
		free(temp);
	}
}
int main(void) {
	struct Book* library = NULL;//头指针
	int ch;
	while (1) {
		printf("请问是否需要录入书籍信息(Y/N):");
		do {
			ch = getchar();
		} while (ch != 'Y' && ch != 'N');
		if (ch == 'Y') {
			addBook(&library);
		}
		else {
			break;
		}
	}
		printf("请问是否需要打印图书信息(Y/N):");
	do {
		ch = getchar();
	} while (ch != 'Y' && ch != 'N');
	if (ch == 'Y') {
		printLibrary(library);
	}
	releaseLibrary(&library);
	return 0;
	}

当然咯,还有尾插法的呀!头插法与尾插法只有一点点思路上的不同,只需要将addLibrary函数做一点改动即可,代码如下:

void addBook(struct Book** library) {
	struct Book* book, * temp;
	book = (struct Book*)malloc(sizeof(struct Book));
	if (book == NULL) {
		printf("内存分配失败了!\n");
		exit(1);
	}
	getInput(book);
	if (*library != NULL) {
		temp = *library;
		//定位单链表的尾部位置
		while (temp->next != NULL) {
			temp = temp->next;
		}//退出循环时,有temp->next==NULL;
		//插入数据;;;
		temp->next = book;//将新值插入进去
		book->next = NULL;//下一个值改为NULL;
	}
	else {
		*library = book;
		book->next = NULL;
	}
}

        这个时候就出现了一个问题,我们在使用尾插法的时候,每次都要将整个链表遍历一遍,效率不高,我们可以直接使用一个指针指向链表的尾部,提高效率,这里只展示与尾插法不同的addBook部分。

void addBook(struct Book** library) {
	struct Book* book;
	static struct Book* end;//静态存储变量
	book = (struct Book*)malloc(sizeof(struct Book));
	if (book == NULL) {
		printf("内存分配失败!\n");
		return;
	}
	else {
		getInput(book);
		if (*library == NULL) {
			*library = book;
			book->next = NULL;
		}
		else {
			end->next = book;
			book->next = NULL;
			}
		end = book;
		}
	}

        还进行了一个小练习,对一个链表实现增删查改,我写了一个比较具体的程序来反映这几个功能,代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Book {
	char title[120];
	char author[40];
	struct Book* next;
};//创建了一个链表
void addBook(struct Book** head);//增加
void deleteBook(struct Book** head);//删除
void searchBook(struct Book *head);//寻找
void changeBook(struct Book *head);//改动
void addInput(struct Book* book);
void printBook(struct Book* head);

void addInput(struct Book* book) {
	printf("请输入书名:");
	scanf_s("%s", book->title, 120);
	printf("请输入作者:");
	scanf_s("%s", book->author, 40);
}

void addBook(struct Book** head) {
	struct Book* book;
	book = (struct Book*)malloc(sizeof(struct Book));
	if (book == NULL) {
		printf("可用空间不足!\n");
		return;
	}
	else {
		printf("请输入你要新增的书:\n");
		addInput(book);
		if ((*head) != NULL) {
			struct Book* temp;
			temp = *head;
			*head = book;
			book->next = temp;
		}
		else {
			*head = book;
			book->next = NULL;
		}
	}
}

void printBook(struct Book* head) {
	int cnt = 1;
	
	while (head != NULL) {
		printf("Book%d:", cnt++);
		printf("书名:%s\n ", head->title);
		printf("作者:%s\n ", head->author);
		head = head->next;
	}
	printf("\n");
}

void searchBook(struct Book* head) {
	printf("请输入您要查找的书的书名或作者:");
	char search[120];
	scanf_s("%s", search, 120);
	while (head != NULL) {
		if ((strcmp(search,head->author)) == 0 ||(strcmp(search,head->title)) == 0) {
			printf("您要找的图书找到了!\n");
			printf("书名:%s\n", head->title);
			printf("作者:%s\n", head->author);
		}
		head = head->next;
	}
}

void deleteBook(struct Book** head) {
	printf("请输入你要删除的书的名字:");
	char title[120];
	struct Book* pf = *head;
	struct Book* pb = *head;
	scanf_s("%s", title, 120);
	while (strcmp(title, pb->title) != 0) {
		pf = pb;
		pb = pb->next;
	}
	if (pb != NULL) {
		if (pb == *head) {
			*head = (*head)->next;
		}
		else {
			pf->next = pb->next;
		}
	}
}

void changeBook(struct Book* head) {
	printf("请输入你要改动第几本书:");
	int number;
	scanf_s("%d", &number);
	for (int i = 0; i < number - 1; i++) {
		head = head->next;
	}
	printf("请输入改动后的书名:");
	scanf_s("%s", head->title, 120);
	printf("请输入改动后的作者:");
	scanf_s("%s", head->author, 40);
}

int main(void) {
	struct Book* head = NULL;
	while (1) {
		printf("请选择你要进行的操作:\n");
		printf("**********************\n");
		printf("**********************\n");
		printf("**1.add     2.delete**\n");
		printf("**3.search  4.change**\n");
		printf("**      5.exit      **\n");
		printf("**********************\n");
		printf("**********************\n");
		int a;
		scanf_s("%d", &a);
		switch (a) {
		case 1:addBook(&head);
			printBook(head); break;
		case 2:deleteBook(&head); 
			printBook(head); break;
		case 3:searchBook(head); break;
		case 4:changeBook(head);
			printBook(head); break;
		case 5:return 0;
		default:printf("请按所给提示输入!\n"); break;
		}
	}	
}

本周还针对字符串做了一些练习,挑选了一个我认为是其中最有难度的题拿出来:

        Q1:给定程序的功能主要是将未在字符串S中出现,而在字符串T中出现的字符,形成一个新的字符串放在U中,U按照原字符串中的字符顺序排列,但去掉重复字符

eg:S="12345",T="24667",U=“67”,我的代码如下:

#include<stdio.h>
int main(void) {
 char str1[50];
 char str2[50];
 //目的是将str2内的str1中没有的元素赋给str3,并且不能重复
 char str3[50];
 int cnt = 0, cnt1 = 0, temp1 = 0;
 for (int i = 0; i < 50; i++) {
  scanf_s("%c", &str1[i]);
  if (str1[i] == '\n') {
   break;
  }
  ++cnt;//str1中元素的个数
 }
 for (int i = 0; i < 50; i++) {
  scanf_s("%c", &str2[i]);
  if (str2[i] == '\n') {
   break;//str2中元素的个数
  }
  ++cnt1;
 }
 for (int i = 0; i < cnt1; i++) {
  int temp = 1;
  for (int j = 0; j < cnt; j++) {
   if (str2[i] == str1[j]) {
    temp = 0;
   }
  }
  if (temp == 1) {
   int temp3 = 1;
   for (int j = 0; j < temp1; j++) {
    if (str3[j] == str2[i]) {
     temp3 = 0;
     break;
    }
   }
   if (temp3 == 1) {
    str3[temp1] = str2[i];
    ++temp1;
   }
    }
   }

  for (int i = 0; i < temp1; i++) {
   printf("%c", str3[i]);
  }
 }

        这些就是本周大致的学习内容!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值