浙江大学MOOC数据结构-陈越、何钦铭 编程练习题(第十一讲)

浙江大学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;
	 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值