慕课作业题目
串的模式匹配
设主串S=‘abcaabbabcabaacbacba’,模式串P=‘abcabaa’
(1)计算模式串P的next值和nextval函数值;
(2)不写出算法,只画出利用KMP算法(利用改进的nextval值)进行模式匹配时每一趟的匹配过程。
(可以参考课本80页 图4.3、图4.4的匹配过程描述形式。在每一趟匹配后面备注该趟结束时i和j的值。)
Huffman编码
假设用于通信的电文由字符集{a,b,c,d,e,f,g}中的字母构成。它们在电文中出现的频度分别为{0.31,0.16,0.10,0.08,0.11,0.20,0.04},
1 )为这7个字母设计哈夫曼编码;
2 )为这7个字母设计等长编码,至少需要几位二进制数?
3 )哈夫曼编码比等长编码使电文总长压缩多少?
(1)略
(2)3位
(3)
等长编码长度: (0.31+0.16+0.1+0.08+0.11+0.2+0.04)x3=3
哈夫曼编码长度: 0.31x2+0.16x3+0.1x3+0.08x4+0.11x3+0.2x2+0.04x4=2.61
(3 - 2.61) / 3 = 13%
图的综合作业
某国有7个城市,它们互相之间没有公路相通,因此交通十分不便。为解决这一“行路难”的问题,政府决定修建公路,经过调研,如果把这7个城市之间的关系看成一个图,字母代表城市名称,数字代表修路的花费:
(1)请画出该图对应的邻接表,并写出深度优先和广度优先遍历序列
(2)为了最大限度的节约资金,政府只允许修6条路,通过这6条路就能把这7个城市相连通,请从城市A出,发用普利姆算法进行6条路的选择,画出求解过程。
提示:一个图的邻接表答案不唯一,但是邻接表对应的遍历序列答案是唯一的。
该图是带权图,邻接表中也要存储每条边的权值信息。
(1)
DFS序列: A B C D F E G
BFS序列: A B D G C F E
(2)
参考课本P174,还需画出类似图7.17的表
平衡的二叉排序树
依次输入表(30, 15, 28, 20, 24, 10, 68, 35, 50)中的元素,生成一棵平衡的二叉排序树。
请画出构造过程,并在其中注明每一次平衡化的类型(LL型、RR型、LR型、RL型)
哈希表
给定一组查找关键字(32,15,7,11,4,28,56,61,79),哈希表长为m=12,请按照除留余数法设计一个哈希函数,设每个记录的查找概率相等。
(1)画出按照线性探测再散列处理冲突得到的哈希表(给出求解过程),并计算等概率情况下查找成功和查找失败时的平均查找长度各是多少。
(2)画出按照链地址法处理冲突得到的哈希表,并计算等概率情况下查找成功和查找失败时的平均查找长度各是多少。
(1)
(2)
PTA题目
应该只考线性表、树
6-1 线性表元素的区间删
给定一个顺序存储的线性表,请设计一个函数删除所有值大于min而且小于max的元素。删除后表中剩余元素保持顺序存储,并且相对位置不能改变。
函数接口定义:
List Delete( List L, ElementType minD, ElementType maxD );
List Delete(List L, ElementType minD, ElementType maxD) { int i, p = 0; for (i = 0; i <= L->Last; i++) { if (L->Data[i] <= minD || L->Data[i] >= maxD) { L->Data[p++] = L->Data[i]; } } L->Last = p - 1; return L; }
6-2 有序表的插入
设顺序表中的数据元素是按值非递减有序排列的,试编写一算法,将x插入到顺序表的适当位置上,以保持顺序表的有序性。
函数接口定义:
void ListInsertSort(SqList *L, DataType x);
其中 L
和 x
都是用户传入的参数。 L
表示顺序表, x
是要插入的元素。
void ListInsertSort(SqList *L, DataType x) { int i; int temp = 1; for (i = 0; L->items[i] < x; i++) { temp++; } ListInsert(L,temp,x); }
6-3 合并两个有序数组
要求实现一个函数merge,将长度为m的升序数组a和长度为n的升序数组b合并到一个新的数组c,合并后的数组仍然按升序排列。
函数接口定义:
void printArray(int* arr, int arr_size); /* 打印数组,细节不表 */
void merge(int* a, int m, int* b, int n, int* c); /* 合并a和b为c */
其中a和b是按升序排列的数组,m和n分别为数组a、b的长度;c为合并后的升序数组。
void merge(int *a, int m, int *b, int n, int *c) { int i, j, k; while (i < m && j < n) { if (a[i] < b[j]) c[k++] = a[i++]; else c[k++] = b[j++]; } while (i < m) { c[k++] = a[i++]; } while (j < n) { c[k++] = b[j++]; } }
6-4 顺序表操作集
本题要求实现顺序表的操作集。
函数接口定义:
List MakeEmpty();
Position Find( List L, ElementType X );
bool Insert( List L, ElementType X, Position P );
bool Delete( List L, Position P );
其中List
结构定义如下:
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
各个操作函数的定义为:
List MakeEmpty()
:创建并返回一个空的线性表;
Position Find( List L, ElementType X )
:返回线性表中X的位置。若找不到则返回ERROR;
bool Insert( List L, ElementType X, Position P )
:将X插入在位置P并返回true。若空间已满,则打印“FULL”并返回false;如果参数P指向非法位置,则打印“ILLEGAL POSITION”并返回false;
bool Delete( List L, Position P )
:将位置P的元素删除并返回true。若参数P指向非法位置,则打印“POSITION P EMPTY”(其中P是参数值)并返回false。
List MakeEmpty() { List list; list = (List) malloc(sizeof(struct LNode)); list->Last = -1; return list; } Position Find(List L, ElementType X) { int i; for (i = 0; i < MAXSIZE; i++) { if (L->Data[i] == X) return i; } return ERROR; } bool Insert(List L, ElementType X, Position P) { int i; if (L->Last == MAXSIZE - 1) { printf("FULL"); return false; } if (P < 0 || P > L->Last + 1) { printf("ILLEGAL POSITION"); return false; } for (i = L->Last; i >= P; i--) { L->Data[i + 1] = L->Data[i]; } L->Data[P] = X; L->Last++; return true; } bool Delete(List L, Position P) { int i; if (P < 0 || P > L->Last) { printf("POSITION %d EMPTY", P); return false; } for (i = P; i < L->Last; i++) { L->Data[i] = L->Data[i + 1]; } L->Last--; return true; }
6-5 递增的整数序列链表的插入
本题要求实现一个函数,在递增的整数序列链表(带头结点)中插入一个新整数,并保持该序列的有序性。
函数接口定义:
List Insert( List L, ElementType X );
其中List
结构定义如下:
typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
L
是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Insert
要将X
插入L
,并保持该序列的有序性,返回插入后的链表头指针。
List Insert(List L, ElementType X) { List p, s; p = L; s = (List) malloc(sizeof(struct Node)); s->Data = X; while (p->Next && p->Next->Data < X) { p = p->Next; } s->Next = p->Next; p->Next = s; return L; }
6-6 删除单链表偶数节点
本题要求实现两个函数,分别将读入的数据存储为单链表、将链表中偶数值的结点删除。链表结点定义如下:
struct ListNode {
int data;
struct ListNode *next;
};
函数接口定义:
struct ListNode *createlist();
struct ListNode *deleteeven( struct ListNode *head );
函数createlist
从标准输入读入一系列正整数,按照读入顺序建立单链表。当读到−1时表示输入结束,函数应返回指向单链表头结点的指针。
函数deleteeven
将单链表head
中偶数值的结点删除,返回结果链表的头指针。
struct ListNode *createlist() { int m; struct ListNode *p, *s, *l; p = (struct ListNode *) malloc(sizeof(struct ListNode)); scanf("%d", &m); if (m == -1) return NULL; p->data = m; p->next = NULL; s = p; while (1) { scanf("%d", &m); if (m == -1) break; l = (struct ListNode *) malloc(sizeof(struct ListNode)); l->data = m; l->next = NULL; s->next = l; s = l; } return p; } struct ListNode *deleteeven(struct ListNode *head) { struct ListNode *p = NULL, *s = NULL; while (head && head->data % 2 == 0) { p = head; head = head->next; free(p); } if (head == NULL) return NULL; s = head; while (s->next) { if (s->next->data % 2 == 0) s->next = s->next->next; else s = s->next; } return head; }
6-7 逆序数据建立链表
本题要求实现一个函数,按输入数据的逆序建立一个链表。
函数接口定义:
struct ListNode *createlist();
函数createlist
利用scanf
从输入中获取一系列正整数,当读到−1时表示输入结束。按输入数据的逆序建立一个链表,并返回链表头指针。链表节点结构定义如下:
struct ListNode {
int data;
struct ListNode *next;
};
struct ListNode *createlist() { int m; struct ListNode *head, *p; head = (struct ListNode *) malloc(sizeof(struct ListNode)); head->next = NULL; while (1) { scanf("%d", &m); if (m == -1) break; p = (struct ListNode *) malloc(sizeof(struct ListNode)); p->next = head->next; p->data = m; head->next = p; } return head->next; }
6-8 求链表的倒数第m个元素
请设计时间和空间上都尽可能高效的算法,在不改变链表的前提下,求链式存储的线性表的倒数第m(>0)个元素。
函数接口定义:
ElementType Find( List L, int m );
其中List
结构定义如下:
typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
L
是给定的带头结点的单链表;函数Find
要将L
的倒数第m
个元素返回,并不改变原链表。如果这样的元素不存在,则返回一个错误标志ERROR
。
ElementType Find(List L, int m) { int i; PtrToNode p, s; p = s = L; for (i = 0; i < m; i++) { p = p->Next; if (!p) return ERROR; } while (p) { s = s->Next; p = p->Next; } return s->Data; }
6-9 两个有序链表序列的合并
本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列。
函数接口定义:
List Merge( List L1, List L2 );
其中List
结构定义如下:
typedef struct Node *PtrToNode;
struct Node {
ElementType Data; /* 存储结点数据 */
PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
L1
和L2
是给定的带头结点的单链表,其结点存储的数据是递增有序的;函数Merge
要将L1
和L2
合并为一个非递减的整数序列。应直接使用原序列中的结点,返回归并后的带头结点的链表头指针。
List Merge( List L1, List L2 ) { List pa,pb,pc; pa=L1->Next; pb=L2->Next; List L=(List)malloc(sizeof(List)); pc=L; while(pa&&pb) { if(pa->Data>pb->Data) { pc->Next=pb; pb=pb->Next; } else{ pc->Next=pa; pa=pa->Next; } pc=pc->Next; } if(pa) pc->Next = pa; if(pb) pc->Next = pb; L1->Next=NULL; L2->Next=NULL; return L; }
6-10 二叉树的遍历
题要求给定二叉树的4种遍历。
函数接口定义:
void InorderTraversal( BinTree BT );
void PreorderTraversal( BinTree BT );
void PostorderTraversal( BinTree BT );
void LevelorderTraversal( BinTree BT );
其中BinTree
结构定义如下:
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
要求4个函数分别按照访问顺序打印出结点的内容,格式为一个空格跟着一个字符。
void InorderTraversal(BinTree BT) { //中序遍历 if (BT) { InorderTraversal(BT->Left); printf(" %c", BT->Data); InorderTraversal(BT->Right); } } void PreorderTraversal(BinTree BT) { //先序遍历 if (BT) { printf(" %c", BT->Data); PreorderTraversal(BT->Left); PreorderTraversal(BT->Right); } } void PostorderTraversal(BinTree BT) { //后序遍历 if (BT) { PostorderTraversal(BT->Left); PostorderTraversal(BT->Right); printf(" %c", BT->Data); } } void LevelorderTraversal(BinTree BT) { BinTree B[100];//结构体数组 BinTree T; int i = 0, j = 0; if (!BT)return;//树为空,返回 if (BT)//不为空 { B[i++] = BT;//根节点入队 while (i != j)//队列不空 { T = B[j++];//出队 printf(" %c", T->Data); if (T->Left) B[i++] = T->Left; if (T->Right) B[i++] = T->Right; } } }
6-11 二叉树的非递归遍历
本题要求用非递归的方法实现对给定二叉树的 3 种遍历。
函数接口定义:
void InorderTraversal( BinTree BT );
void PreorderTraversal( BinTree BT );
void PostorderTraversal( BinTree BT );
其中BinTree
结构定义如下:
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
int flag;
};
要求 3 个函数分别按照访问顺序打印出结点的内容,格式为一个空格跟着一个字符。
void InorderTraversal( BinTree BT ){ //中序遍历 BinTree T=BT; Stack S =CreateStack(); while(T||!IsEmpty(S)){ while(T!=NULL){ Push(S,T); T=T->Left; } T=Pop(S); printf(" %c",T->Data); T=T->Right; } } void PreorderTraversal( BinTree BT ){ //先序遍历 BinTree T=BT; Stack S =CreateStack(); while(T||!IsEmpty(S)){ while(T!=NULL){ Push(S,T); printf(" %c",T->Data); T=T->Left; } T=Pop(S); T=T->Right; } } void PostorderTraversal( BinTree BT ){ //后序遍历 BinTree T=BT; Stack S =CreateStack(); while(T||!IsEmpty(S)){ while(T!=NULL){ T->flag=0; Push(S,T); T=T->Left; } T=Peek(S); if(T->flag==0){ T->flag++; T=T->Right; } else{ T=Pop(S); printf(" %c",T->Data); T=NULL; } } }
6-12 求二叉树高度
本题要求给定二叉树的高度。
函数接口定义:
int GetHeight( BinTree BT );
其中BinTree
结构定义如下:
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
要求函数返回给定二叉树BT的高度值。
int GetHeight(BinTree BT) { int lNum, rNum, Height; if (BT) { lNum = GetHeight(BT->Left); rNum = GetHeight(BT->Right); if (lNum > rNum) Height = lNum; else Height = rNum; return Height + 1; } else { return 0; } }
6-13 邻接矩阵存储图的深度优先遍历
试实现邻接矩阵存储图的深度优先遍历。
函数接口定义:
void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) );
其中MGraph
是邻接矩阵存储的图,定义如下:
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */
函数DFS
应从第V
个顶点出发递归地深度优先遍历图Graph
,遍历时用裁判定义的函数Visit
访问每个顶点。当访问邻接点时,要求按序号递增的顺序。题目保证V
是图中的合法顶点。
void DFS(MGraph Graph, Vertex V, void (*Visit)(Vertex)) { Vertex i; Visit(V); Visited[V] = true; for (int i = 0; i < Graph->Nv; i++) { if (Graph->G[V][i] == 1 && !Visited[i]) { DFS(Graph, i, Visit);//进行递归 } } }
6-14 邻接表存储图的广度优先遍历
图的内容不一定会考,可以看看
试实现邻接表存储图的广度优先遍历。
函数接口定义:
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) );
其中LGraph
是邻接表存储的图,定义如下:
/* 邻接点的定义 */
typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
Vertex AdjV; /* 邻接点下标 */
PtrToAdjVNode Next; /* 指向下一个邻接点的指针 */
};
/* 顶点表头结点的定义 */
typedef struct Vnode{
PtrToAdjVNode FirstEdge; /* 边表头指针 */
} AdjList[MaxVertexNum]; /* AdjList是邻接表类型 */
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
AdjList G; /* 邻接表 */
};
typedef PtrToGNode LGraph; /* 以邻接表方式存储的图类型 */
函数BFS
应从第S
个顶点出发对邻接表存储的图Graph
进行广度优先搜索,遍历时用裁判定义的函数Visit
访问每个顶点。当访问邻接点时,要求按邻接表顺序访问。题目保证S
是图中的合法顶点。
void BFS(LGraph Graph, Vertex S, void (*Visit)(Vertex)) { Visited[S] = true;//标记起始点 Visit(S); int queue[1000], front = 0, rear = 0; queue[rear++] = S;//起始点入队列 PtrToAdjVNode temp;//temp就代表当前点的邻接点的下标 while (front < rear) { //队伍不为空 temp = Graph->G[queue[front++]].FirstEdge; while (temp) { int p = temp->AdjV;//把temp中的下标提取出来 if (!Visited[p]) { //如果p点没有被标记的话 Visited[p] = true; Visit(p); queue[rear++] = p;//储存在队列中 } temp = temp->Next;//指向下一个邻接点 } } }
GNode LGraph; /* 以邻接表方式存储的图类型 */
**函数`BFS`应从第`S`个顶点出发对邻接表存储的图`Graph`进行广度优先搜索,遍历时用裁判定义的函数`Visit`访问每个顶点。当访问邻接点时,要求按邻接表顺序访问。题目保证`S`是图中的合法顶点。**
>```c
>void BFS(LGraph Graph, Vertex S, void (*Visit)(Vertex)) {
> Visited[S] = true;//标记起始点
> Visit(S);
> int queue[1000], front = 0, rear = 0;
> queue[rear++] = S;//起始点入队列
> PtrToAdjVNode temp;//temp就代表当前点的邻接点的下标
> while (front < rear) {//队伍不为空
> temp = Graph->G[queue[front++]].FirstEdge;
> while (temp) {
> int p = temp->AdjV;//把temp中的下标提取出来
> if (!Visited[p]) {//如果p点没有被标记的话
> Visited[p] = true;
> Visit(p);
> queue[rear++] = p;//储存在队列中
> }
> temp = temp->Next;//指向下一个邻接点
> }
> }
>}