赞
踩
有一种加密方法为:其使用一个字符串(可以含重复字母,字符个数不超过50)作为密钥。例如:若密钥字符串为Fea25Ther,则需 要先将大写字母转换成小写字母,并去掉密钥单词中的非字母及重复字母得到单词串feathr,然后将其反序,最后将字母表中的其 它字母以反序追加到后面:
r | h | t | a | e | f | z | y | x | w | v | u | s | q | p | o | n | m | l | k | j | i | g | d | c | b |
---|
加密字母的对应关系如下:
a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
r | h | t | a | e | f | z | y | x | w | v | u | s | q | p | o | n | m | l | k | j | i | g | d | c | b |
编写程序根据输入的密钥,生成相应的密码对应表串。
从标准输入读入密钥字符串(字符个数不超过50,其中可包含空白符或其它非字母字符),末尾有换行符(不属于密钥字符串)。
先向控制台输出原字母表,然后在下一行输出生成的对应密码表。
Fea25Ther
abcdefghijklmnopqrstuvwxyz
rhtaefzyxwvusqponmlkjigdcb
输入的密钥字符串为Fea25Ther,先将大写字母转换成小写字母,并去掉密钥单词中的非字母及重复字母得到单词串feathr,然后将 其反序,最后将字母表中的其它字母以反序追加到后面,便得到密码表。
该题要求生成密码对应表,提交程序名为:key.c。
本题几乎是第二次作业第三题的原题,甚至比原题还要简单——没有涉及文件的输入输出操作。此处相比原题只有了两处变动:
由于基本是原题,此处不再给出具体分析过程,所有思路都蕴含在注释中。
#include <stdio.h>
#include <string.h>
# include <ctype.h>
char secret_key [27]; // 加密对应表
int main()
{
char org_word[55] = {0}; // 最开始读取的秘钥
gets(org_word);
int already_used[26] = {0}; // 记录哪些积木已经被用过了(字母1-26编号)
int count = 0;
for(int i = 0; org_word[i]; i++){
if (isalpha(org_word[i])){ // 判断当前位置是否是字母
org_word[i] = tolower(org_word[i]); // 是字母,转化成小写形式
if(!already_used[org_word[i] - 'a']){ // 没被用过
already_used[org_word[i] - 'a'] = 1;
secret_key[count++] = org_word[i];
}
}
}
//接下来要对secret_key逆序,可以有很多种方法,考试时可以就用最笨的方法——开一个tmp数组存储其逆序后的结果,然后copy回去
char tmp[100]= {0};
for (int i=0; i < count; i++){
tmp[count-1-i] = secret_key[i];
}
// 现在tmp已经是secret_key逆序后的数组了
strcpy(secret_key, tmp);
for(int i = 25; i >= 0; i--){
if(!already_used[i]){
secret_key [count++] = 'a' + i;
}
}
// 输出
for(int i = 0; i < 26; i++){
printf("%c", 'a' + i);
}
printf("\n");
for (int i = 0; i < 26; i++)printf("%c", secret_key[i]);
return 0;
}
链表结构存在一个严重不足,就是需要顺序查找才能找到所需要的元素,查找性能低,下面为一个改进链表查找效率的方法。 链表构造规则如下:
编写程序,对输入的一组整数,依次在上述规则构建的链表中查找每个整数。 假如依次输入了15个整数,分别为:-200 120 85 97 2900 85 696 -120 85 120 85 120 85 97 120,前五个数据输入后,构建的链表如 下所示:
结点中前面的数据表示输入的整数,后面的数据是该整数的出现次数。输入第六个数据后,构建的链表如下所示:
所有整数输入完毕后,构建的链表如下所示:
先从控制台读取整数的个数n(n>0),然后在下一行输入n个整数,各整数间以一个空格分隔,输入的整数不会超过int的表示范围。
先输出创建链表时总的整数比较次数,然后依次分行输出链表中前五个整数及其出现次数(整数和出现次数间以一个空格分隔);若链表中 结点的个数少于五个,则按照实际结点个数输出。
15
-200 120 85 97 2900 85 696 -120 85 120 85 120 85 97 120
41
120 4
97 2
85 5
-200 1
2900 1
输入了15个整数;按照上述链表创建规则,输入第一个整数后,没有比较整数,这时总的比较次数为0;输入第五个整数后,整数比较次数为 14;输入第六个整数后,整数比较次数为17;所有整数输入完毕后,总的比较次数为41,这时整数120位于链表头,出现了4次。
该题要求按照改进的链表查找整数,提交程序名为link.c。
本题难度不大,按照要求模拟即可,其实在考场上我们更可能去关心的是用链表去写还是数组去实现。显然本题想考链表,但用数组去写代码肯定更简单,ds很少卡时间,唯一担心的就是会不会有某几个测试点数据量特别大,导致数组开不够大(事实上我有同学就用数组过了),所以还是建议直接用链表去实现。
本题要频繁地在头结点位置插入结点,我个人喜欢带一个哑结点以简化插入结点时的逻辑,所以我们先定义结点类型,然后声明两个指针指向链表头,尾:
# include <stdio.h>
# include <stdlib.h>
typedef struct node {
int num;
int time;
struct node* next;
} node;
node* head = NULL; // 指向链表头(哑结点)
node* tail = NULL; // 指向表尾
在主函数中初始化:
int main()
{
int n;
scanf("%d", &n);
head = (node*) malloc(sizeof(node));
head->next = NULL;
tail = head;
return 0;
}
然后进行数据的读入,每读进来一个数,我们要判断链表中是否已经有结点的数据域(num)等于该数,这需要我们把链表遍历一遍,同时设置一个flag记录是否出现过。对于没有出现过的数,只需把其插入链表尾即可;对于出现过的数,我们找到其位置p然后应该进行如下的操作:
我们来实现这个逻辑:
int tmp; // 暂存读入的数据
for (int i = 0; i < n; i++) {
scanf("%d", &tmp);
if (i==0) { // 读入的第一个数,不用进行任何判断,直接接到head后就行
tail -> next = (node*) malloc(sizeof(node));
tail = tail -> next;
tail -> num = tmp;
tail -> time = 1;
tail -> next = NULL;
} else {
node *p = head -> next; // p从头到尾跑一遍,看看链表中是否出现过该数
int flag = 0; // 标志,记录是否出现过
while (p) {
if (p -> num == tmp) { // p所指的结点的num域与tmp相等
// 在链表中删除p结点,注意这个删除的意思不是要把p free掉
if (p -> next == NULL) { // 要是p结点是尾结点
tail = find_pre(tail); // 改变tail
}
p -> time ++;
find_pre(p) -> next = p -> next; // 让p的前一个结点指向后一个结点(删除p)
// 把p接到head后
p -> next = head -> next;
head -> next = p;
flag = 1; // 标志设为1
break;
}
p = p -> next; // 当前结点的num域不与tmp相等,继续找下一个结点
}
if (!flag) { // 没找到,把p接到表尾即可
tail -> next = (node*) malloc(sizeof(node));
tail = tail -> next;
tail -> num = tmp;
tail -> time = 1;
tail -> next = NULL;
}
}
}
其中的find_pre函数实现的功能是找到当前结点的上一个结点,对链表进行删除和插入时经常用到,其实现如下:
node* find_pre(node*p){
node *q = head;
while(q){
if (q->next==p)return q;
q=q->next;
}
}
这样我们就已经按照题目要求构建出了链表,接下来依照题意还要做两件事:
而后我们在最后先输出compare_num,再判断一下all_num是否大于5,输出对应的数据即可。
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int num;
int time;
struct node *next;
} node;
node *head = NULL; // 指向链表头(哑结点)
node *tail = NULL; // 指向表尾
node *find_pre(node *p)
{
node *q = head;
while (q)
{
if (q->next == p)
return q;
q = q->next;
}
}
int main()
{
int n;
scanf("%d", &n);
head = (node *)malloc(sizeof(node));
head->next = NULL;
tail = head;
int tmp; // 暂存读入的数据
int all_num = 1; // 记录总的结点个数
int compare_time = 0; // 记录比较的次数
for (int i = 0; i < n; i++)
{
scanf("%d", &tmp);
if (i == 0)
{ // 读入的第一个数,不用进行任何判断,直接接到head后就行
tail->next = (node *)malloc(sizeof(node));
tail = tail->next;
tail->num = tmp;
tail->time = 1;
tail->next = NULL;
}
else
{
node *p = head->next; // p从头到尾跑一遍,看看链表中是否出现过该数
int flag = 0; // 标志,记录是否出现过
while (p)
{
compare_time++;
if (p->num == tmp)
{ // p所指的结点的num域与tmp相等
// 在链表中删除p结点,注意这个删除的意思不是要把p free掉
if (p->next == NULL)
{ // 要是p结点是尾结点
tail = find_pre(tail); // 改变tail
}
p->time++;
find_pre(p)->next = p->next; // 让p的前一个结点指向后一个结点(删除p)
// 把p接到head后
p->next = head->next;
head->next = p;
flag = 1; // 标志设为1
break;
}
p = p->next; // 当前结点的num域不与tmp相等,继续找下一个结点
}
if (!flag)
{ // 没找到,把p接到表尾即可
all_num++;
tail->next = (node *)malloc(sizeof(node));
tail = tail->next;
tail->num = tmp;
tail->time = 1;
tail->next = NULL;
}
}
}
// 输出
printf("%d\n", compare_time);
if (all_num < 5)
{
node *temp = head->next;
while (temp)
{
printf("%d %d\n", temp->num, temp->time);
temp = temp->next;
}
}
else
{
node *temp = head->next;
for (int i = 0; i < 5; i++)
{
printf("%d %d\n", temp->num, temp->time);
temp = temp->next;
}
}
return 0;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。