浙江大学MOOC数据结构-陈越、何钦铭 编程练习题(第十一讲)
编程说明
编程环境:平台运行
编程语言:C or C++
第一题代码
#include <stdio.h>
#include <stdlib.h>
//#include <windows.h>
#include <math.h>
#include <string.h>
#define MAXTABLESIZE 200000 //表最大
#define KEYLENGTH 11 //关键词字符串的最大长度
#define MAXD 5 //取号码后五位
typedef char ElementType[KEYLENGTH + 1];//关键词类型用字符串
typedef int Index;//位置下标
//链表节点
typedef struct LNode *List;
struct LNode {
ElementType Data;
List Next;
int Cnt;//电话号码出现次数
};
typedef List Position;
//哈希表
typedef struct TblNode *HashTable;
struct TblNode {
int TableSize;//哈希表最大长度
List Heads;//指向链表头节点的数组
};
HashTable CreateTable(int N);
bool Insert(HashTable H, ElementType Key);
Position Find(HashTable H, ElementType Key);
int Hash(int Key, int Size);
void ScanAndOutput(HashTable H);
void DestroyTable(HashTable H);
int main(void)
{
int N;
ElementType Key;
HashTable H;
scanf("%d", &N);
H = CreateTable(2 * N);
for (int i = 0; i < N; i++)
{
scanf("%s", Key);
Insert(H, Key);
scanf("%s", Key);
Insert(H, Key);
}
ScanAndOutput(H);
DestroyTable(H);
// system("pause");
return 0;
}
//寻找大于N的最小素数决定建立空间的大小
int NextPrime(int N)
{
int p;
int i;
p = (N % 2)?(N + 2):(N + 1);//奇数加2,偶数加1。寻找大于N的最小奇数
for (i = p; p <= MAXTABLESIZE; i += 2)
{
int j;
for (j = (int)sqrt(i); j > 2; j--)
{
if (!(i % j))
break;//说明不是素数
}
if (j == 2)
break;//说明是素数
}
return i;
}
//哈希表的建立以及内部所有变量初始化
HashTable CreateTable(int TableSize)
{
HashTable H;
H = (HashTable)malloc(sizeof(struct TblNode));
H->TableSize = NextPrime(TableSize);
H->Heads = (List)malloc(H->TableSize * sizeof(struct LNode));
for (int i = 0; i < H->TableSize; i++)
{
H->Heads[i].Data[0] = '\0';
H->Heads[i].Cnt = 0;
H->Heads[i].Next = NULL;
}
return H;
}
//将读入的数据插入到哈希表
bool Insert(HashTable H, ElementType Key)
{
Position P, NewCell;
int Pos;
P = Find(H, Key);
if (!P) /* 关键词未找到,可以插入 */
{
NewCell = (Position)malloc(sizeof(struct LNode));
strcpy(NewCell->Data, Key);
NewCell->Cnt = 1;
/* 将NewCell插入为H->Heads[Pos]链表的第1个结点 */
Pos = Hash(atoi(Key + KEYLENGTH - MAXD), H->TableSize);//P为NULL则需要重新计算余数
NewCell->Next = H->Heads[Pos].Next;
H->Heads[Pos].Next = NewCell;
return true;
}
else /* 关键词已存在 */
{
P->Cnt++;
return false;
}
}
Position Find(HashTable H, ElementType Key)
{
Index Pos;
Position P;
/* 初始散列位置 */
Pos = Hash(atoi(Key + KEYLENGTH - MAXD), H->TableSize);
P = H->Heads[Pos].Next; /* 从该链表的第1个结点开始 */
while (P && strcmp(P->Data, Key))/* 当未到表尾,并且Key未找到时 */
P = P->Next;
return P; /* 此时P或者指向找到的结点,或者为NULL */
}
int Hash(int Key, int Size)
{
/* 除留余数法法散列函数 */
return Key%Size;
}
void ScanAndOutput(HashTable H)
{
ElementType MinPhone;
int Pcnt = 0;
int Maxcnt = 0;
List P;
MinPhone[0] = '\0';
for (int i = 0; i < H->TableSize; i++)/* 扫描链表 */
{
P = H->Heads[i].Next;
while (P)//节点不空的时候
{
if (P->Cnt > Maxcnt)/* 更新最大通话次数 */
{
Pcnt = 1;//最大数量的人数
strcpy(MinPhone, P->Data);//最大数量对应号码
Maxcnt = P->Cnt;
}
else if (P->Cnt == Maxcnt)
{
Pcnt++;/* 狂人计数 */
if (strcmp(P->Data, MinPhone) < 0)
{
strcpy(MinPhone, P->Data);/* 更新狂人的最小手机号码 */
}
}
P = P->Next;
}
}
printf("%s %d", MinPhone, Maxcnt);
if (Pcnt > 1)
{
printf(" %d", Pcnt);
}
printf("\n");
}
void DestroyTable(HashTable H)
{
Position p, tmp;
for (int i = 0; i < H->TableSize; i++)
{
p = H->Heads[i].Next;
while (p)
{
tmp = p->Next;
free(p);
p = tmp;
}
}
free(H->Heads);
free(H);
}
第二题代码
这里参考自https://www.cnblogs.com/A-Little-Nut/p/8159222.html
#include <stdio.h>
#include <stdlib.h>
//#include <windows.h>
#include <math.h>
int IsPrime(int N);
int N, MSize;//数字个数、哈希表最大值
int Tmp;//数组元素
int H[20000];//哈希表是否存储元素的标志
int main()
{
//获取数据
scanf("%d %d", &MSize, &N);
//寻找最小素数
int Tblsize = IsPrime(MSize);
for (int i = 0; i < Tblsize; i++)
{
H[i] = 0;
}
int pos;
for (int i = 0; i < N; i++)
{
int flag = 0;//是否找到空位置
scanf("%d", &Tmp);
for (int j = 0; j < Tblsize; j++)
{
pos = (Tmp%Tblsize + j*j) % Tblsize;
if (H[pos] == 0)//说明之前没有存过数字
{
H[pos] = 1;
flag = 1;
break;
}
}
if (!i)//第一个元素
{
if (flag)//是否找到空位置
{
printf("%d", pos);
}
else
{
printf("-");
}
}
else
{
if (flag)//是否找到空位置
{
printf(" %d", pos);
}
else
{
printf(" -");
}
}
}
// system("pause");
return 0;
}
int IsPrime(int N)
{
int i, j;
int Pm = N % 2 ? N : N + 1;//判断奇数还是偶数,都化为奇数
//2是最小的质数
if(N<=2)
return 2;
for (j = Pm; ; j += 2)
{
for (i = (int)sqrt(j); i > 2; i--)
{
if (j % i == 0)//除以一个数可以除尽,说明不是素数
{
break;
}
}
if (i == 2)
return j;
}
}
第三题代码
这里参考自https://www.cnblogs.com/snzhong/p/12432906.html
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#include <windows.h>
#include <math.h>
typedef enum {false,true} bool;
typedef struct LNode *List;
struct LNode {
char num[11];
char pw[17];
List next;
};
typedef struct HarshTable *HarshTbl;
struct HarshTable {
int tblsize;
List heads;
};
HarshTbl CreateHarshTbl(int size);
int NextPrime(int size);
bool IsPrime(int n);
int Harsh(HarshTbl H, char *num);
List IsExist(HarshTbl H, char *num, int pos);
int main()
{
int size;
char c;//N or L
char num[11] = "\0";//QQ号码
char pwd[17] = "\0";//QQ密码
HarshTbl H;
int pos;
scanf("%d", &size);
H = CreateHarshTbl(size);
for (int i = 0; i < size; i++)
{
getchar();//把数字之后的回车符号读去
scanf("%c %s%s", &c, num, pwd);
pos = Harsh(H, num);//计算存放位置
List p = IsExist(H, num, pos);//检查是否存在QQ号,并返回其位置
if (c == 'N')//新申请号码
{
if (!p)//空节点,说明不存在此QQ号码
{
List node = (List)malloc(sizeof(struct LNode));
strcpy(node->num, num);
strcpy(node->pw, pwd);
//下面这个地方一定不要用p去做!
node->next = H->heads[pos].next;
H->heads[pos].next = node;
printf("New: OK\n");
}
else
printf("ERROR: Exist\n");
}
else if(c == 'L')//登录号码
{
if (p)
{
if (strcmp(p->pw, pwd) == 0)
{
printf("Login: OK\n");
}
else//密码错误
{
printf("ERROR: Wrong PW\n");
}
}
else//说明不存在此QQ号码
{
printf("ERROR: Not Exist\n");
}
}
}
// system("pause");
return 0;
}
HarshTbl CreateHarshTbl(int size)
{
//初始化哈希表
HarshTbl H = (HarshTbl)malloc(sizeof(struct HarshTable));
H->tblsize = NextPrime(size);
H->heads = (List)malloc(sizeof(struct LNode)*H->tblsize);
//初始化链表节点
for (int i = 0; i < H->tblsize; i++)
{
H->heads[i].next = NULL;
H->heads[i].num[0] = '\0';
H->heads[i].pw[0] = '\0';
}
return H;
}
//计算大于N的最小素数
int NextPrime(int size)
{
int i = size + 1;
while (!IsPrime(i))
{
i++;
}
return i;
}
//判断是否是素数
bool IsPrime(int n)
{
if (n == 1 || n == 0)
{
return false;
}
if (n > 2)
{
for (int i = 2; i <= sqrt(n) + 1; i++)
{
if (n%i == 0) return false;
}
}
return true;
}
//返回存放位置
int Harsh(HarshTbl H, char *num)
{
int len = strlen(num);
return atoi(num + len - 4) % H->tblsize;
}
//判断QQ号码是否存在,并返回其位置
List IsExist(HarshTbl H, char *num, int pos)
{
List p = H->heads[pos].next;
while (p)
{
if (strcmp(p->num, num) == 0)//字符串比对成功说明找到了
break;
p = p->next;
}
return p;
}
第四题代码
这里参考自https://blog.youkuaiyun.com/Invokar/article/details/80383159?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-4.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-4.channel_param
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <queue>
//#include <windows.h>
using namespace std;
int Arr[1001];//数组
int indegree[1001];//入度数组
struct cmp
{ /* 比较函数 小顶堆 */
bool operator() (int i, int j)
{
return Arr[i] > Arr[j];
}
};
int main()
{
int N;
int pos;
int flag = 0;
scanf("%d", &N);
vector <vector<int> > v(N);
priority_queue<int, vector<int>, cmp> q;
for (int i = 0; i < N; i++)
{
scanf("%d", &Arr[i]);
pos = Arr[i]%N;//pos应该所在位置
indegree[i] = (i - pos + N) % N;//i实际所在位置
if (Arr[i] >= 0)
{
if (indegree[i])//入度非零,则需与前面所冲突的节点进行连接
{
for (int j = 0; j < indegree[i]; j++)//带不带等于?
{
v[(pos + j) % N].push_back(i);
}
}
else//入度为0则直接进入队列
{
q.push(i);
}
}
}
while (!q.empty())
{
pos = q.top();//取出入度为零,且下标最小
q.pop();//出队
if (flag == 0)
printf("%d", Arr[pos]);
else
printf(" %d", Arr[pos]);
flag = 1;
for (int k = 0; k < v[pos].size(); k++)
{
if (--indegree[v[pos][k]] == 0)
q.push(v[pos][k]);
}
}
// system("pause");
return 0;
}
KMP算法
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <windows.h>
void Bulid_Match(char *pattern, int *match);
int KMP(char *string, char *word);
int main()
{
char string[] = "This is a simple example.";//文本
char word[] = "simple";//单词
int p = KMP(string, word);
if (p == -1)
printf("NULL");
else
printf("%s", string + p);
system("pause");
return 0;
}
void Bulid_Match(char *pattern, int *match)
{
int m = strlen(pattern);
int i;
match[0] = -1;
for (int j = 1; j < m; j++)
{
i = match[j - 1];
while (i >= 0 && pattern[j] != pattern[i + 1])
i = match[i];
if (pattern[j] == pattern[i + 1])
match[j] = i + 1;
else
match[j] = -1;
}
}
int KMP(char *string, char *pattern)
{
int n = strlen(string);
int m = strlen(pattern);
if (n < m) return -1;
int *match = (int *)malloc(sizeof(int)*m);
Bulid_Match(pattern, match);
int s = 0, p = 0;//s是string下标,p是word下标
while (s < n && p < m)//都没有达到末尾的时候
{
if (string[s] == pattern[p])//比对成功s和p分别后移
{
s++;
p++;
}
else if (p > 0)//比对不成功,而且p!=-1
p = match[p - 1] + 1;
else//p=-1说明没有对应的了
s++;
}
return (p == m) ? s - m : -1;
}