0X0-1 はリンクされたリストの長さを検出します
この質問では、リンクされたリストの長さを見つける関数の実装が必要です。
関数インターフェースの定義:
int Length( List L );
リスト構造は次のように定義されます。
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode List;
L は指定された単一リンク リストであり、関数 Length はリンク リストの長さを返す必要があります。
審判テスト手順の例:
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode List;
List Read(); /* 细节在此不表 */
int Length( List L );
int main()
{
List L = Read();
printf("%d\n", Length(L));
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
1 3 4 5 2 -1
出力サンプル:
5
コード:
int Length( List L )
{
int n = 0;
if (L==NULL) return 0;
while (L!=NULL)
{
L = L->Next;
n++;
}
return n;
}
0X0-2 学生情報リンクリスト作成
この質問では、入力された生徒のスコアを一方向のリンク リストに編成する単純な関数の実装が必要です。
関数インターフェースの定義:
void input();
この関数は、scanf を使用して入力から学生情報を取得し、それを一方向リンク リストに編成します。リンク リストのノード構造は次のように定義されます。
struct stud_node {
int num; /*学号*/
char name[20]; /*姓名*/
int score; /*成绩*/
struct stud_node *next; /*指向下个结点的指针*/
};
一方向リンクリストの先頭ポインタと末尾ポインタは、グローバル変数 head と tail に格納されます。
入力は複数の学生の情報(学生ID、氏名、成績)で、学生IDが0になった時点で終了となります。
審判テスト手順の例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stud_node {
int num;
char name[20];
int score;
struct stud_node *next;
};
struct stud_node *head, *tail;
void input();
int main()
{
struct stud_node *p;
head = tail = NULL;
input();
for ( p = head; p != NULL; p = p->next )
printf("%d %s %d\n", p->num, p->name, p->score);
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
1 zhang 78
2 wang 80
3 li 75
4 zhao 85
0
出力サンプル:
1 zhang 78
2 wang 80
3 li 75
4 zhao 85
コード:
void input()
{
struct stud_node *q;
q = (struct stud_node *)malloc(sizeof(struct stud_node));
scanf("%d",&q->num);
while (q->num != 0)
{
scanf("%s %d",q->name,&q->score);
if (head == NULL)
{
head = q;
head->next = NULL;
}
if (tail != NULL)
{
tail->next = q;
}
tail = q;
tail->next = NULL;
q = (struct stud_node *)malloc(sizeof(struct stud_node));
scanf("%d",&q->num);
}
}
0X0-3 は専門家の数をカウントします
この問題では、学生数リストにコンピュータ サイエンスを専攻する学生の数をカウントする関数の実装が必要です。リンク リスト ノードは次のように定義されます。
struct ListNode {
char code[8];
struct ListNode *next;
};
ここでの学籍番号は合計7桁で、そのうち2桁目と3桁目がメジャー番号となります。コンピュータ専攻の番号は02です。
関数インターフェースの定義:
int countcs( struct ListNode *head );
head は、ユーザーによって渡された学生番号リンク リストの先頭ポインタです。関数 countcs は、先頭リンク リスト内のコンピュータ サイエンスを専攻する学生の数をカウントして返します。
審判テスト手順の例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct ListNode {
char code[8];
struct ListNode *next; };
struct ListNode *createlist(); /*裁判实现,细节不表*/ int countcs( struct ListNode *head );
int main() {
struct ListNode *head;
head = createlist();
printf("%d\n", countcs(head));
return 0; }
/* 你的代码将被嵌在这里 */
入力例:
1021202
2022310
8102134
1030912
3110203
4021205
#
出力サンプル:
3
コード:
int countcs( struct ListNode *head )
{
int num = 0;
while (head)
{
if(head->code[1]=='0'&&head->code[2]=='2')
num++;
head = head->next;
}
return num;
}
0X0-4 リンク リストのスプライシング
この質問では、2 つの順序付けされたリンク リストをマージする単純な関数の実装が必要です。リンク リスト ノードは次のように定義されます。
struct ListNode {
int data;
struct ListNode *next;
};
関数インターフェースの定義:
struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2);
このうち、list1 と list2 は、ユーザーがデータの昇順で渡した 2 つのリンク リストの先頭ポインタであり、関数 mergelists は、2 つのリンク リストをデータの昇順で 1 つのリンク リストにマージし、結果として得られるリンクの先頭ポインタを返します。リスト。
審判テスト手順の例:
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int data;
struct ListNode *next;
};
struct ListNode *createlist(); /*裁判实现,细节不表*/
struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2);
void printlist( struct ListNode *head )
{
struct ListNode *p = head;
while (p) {
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
struct ListNode *list1, *list2;
list1 = createlist();
list2 = createlist();
list1 = mergelists(list1, list2);
printlist(list1);
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
1 3 5 7 -1
2 4 6 -1
出力サンプル:
1 2 3 4 5 6 7
コード:
struct ListNode *mergelists(struct ListNode *list1, struct ListNode *list2)
{
int num = 0; //把两个链表连接成一个数组再排序
int temp[100];
struct ListNode *p = list1;
while(p != NULL)
{
temp[num] = p->data;
num++;
p = p->next;
}
p = list2;
while(p != NULL)
{
temp[num] = p->data;
num++;
p = p->next;
}
int i,j;
for(i = 0; i < num; i++)
for(j = i + 1; j < num; j++)
{
if(temp[i] > temp[j])
{
int t;
t = temp[i];
temp[i] = temp[j];
temp[j] = t;
}
}
struct ListNode *newlist = NULL;
struct ListNode *endlist = NULL;
struct ListNode *q;
for(i = 0; i < num; i++)
{
q = (struct ListNode *)malloc(sizeof(struct ListNode));
q->data = temp[i];
if(newlist == NULL)
{
newlist = q;
newlist->next = NULL;
}
if(endlist != NULL)
{
endlist->next = q;
}
endlist = q;
endlist->next = NULL;
}
return newlist;
}
0X0-5 シーケンステーブルの基本操作
この問題では、シーケンス テーブル要素の追加、削除、検索、出力という 4 つの基本的な操作関数の実装が必要です。L はシーケンス テーブルです。関数 Status ListInsert_Sq(SqList &L, int pos, ElemType e) は、シーケンス テーブルの pos 位置に要素 e を挿入します (pos は 1 から開始する必要があります)。関数 Status ListDelete_Sq(SqList &L, int pos , ElemType &e ) は、シーケンス テーブルの pos の位置にある要素を削除し、参照パラメーター e でそれを戻します (pos は 1 から開始する必要があります)。関数 int ListLocate_Sq(SqList L, ElemType e) は、要素の位置をクエリします。 (複数の項目の最初の位置を取得し、1 から始まる位置を返します。存在しない場合は 0 を返します。) 関数 void ListPrint_Sq (SqList L) は、出力シーケンス リストです。要素。テーブルの全容量拡張の問題は、実装時に考慮する必要があります。
関数インターフェースの定義:
Status ListInsert_Sq(SqList &L, int pos, ElemType e);
Status ListDelete_Sq(SqList &L, int pos, ElemType &e);
int ListLocate_Sq(SqList L, ElemType e);
void ListPrint_Sq(SqList L);
ここで、L はシーケンス リストです。pos は位置、e は要素を表します。挿入および削除操作の pos パラメータが不正な場合、関数は ERROR を返し、それ以外の場合は OK を返します。
審判テスト手順の例:
//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
//顺序表的存储结构定义
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef int ElemType; //假设线性表中的元素均为整型
typedef struct{
ElemType* elem; //存储空间基地址
int length; //表中元素的个数
int listsize; //表容量大小
}SqList; //顺序表类型定义
Status ListInsert_Sq(SqList &L, int pos, ElemType e);
Status ListDelete_Sq(SqList &L, int pos, ElemType &e);
int ListLocate_Sq(SqList L, ElemType e);
void ListPrint_Sq(SqList L);
//结构初始化与销毁操作
Status InitList_Sq(SqList &L){
//初始化L为一个空的有序顺序表
L.elem=(ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!L.elem)exit(OVERFLOW);
L.listsize=LIST_INIT_SIZE;
L.length=0;
return OK;
}
int main() {
SqList L;
if(InitList_Sq(L)!= OK) {
printf("InitList_Sq: 初始化失败!!!\n");
return -1;
}
for(int i = 1; i <= 10; ++ i)
ListInsert_Sq(L, i, i);
int operationNumber; //操作次数
scanf("%d", &operationNumber);
while(operationNumber != 0) {
int operationType; //操作种类
scanf("%d", & operationType);
if(operationType == 1) { //增加操作
int pos, elem;
scanf("%d%d", &pos, &elem);
ListInsert_Sq(L, pos, elem);
} else if(operationType == 2) { //删除操作
int pos; ElemType elem;
scanf("%d", &pos);
ListDelete_Sq(L, pos, elem);
printf("%d\n", elem);
} else if(operationType == 3) { //查找定位操作
ElemType elem;
scanf("%d", &elem);
int pos = ListLocate_Sq(L, elem);
if(pos >= 1 && pos <= L.length)
printf("%d\n", pos);
else
printf("NOT FIND!\n");
} else if(operationType == 4) { //输出操作
ListPrint_Sq(L);
}
operationNumber--;
}
return 0;
}
/* 请在这里填写答案 */
入力形式: 1行目にオペランドを表す整数のoperationNumberを入力し、その後にoperationNumber行を入力し、各行に操作情報(「操作種類番号 操作内容」を含む)を入力します。数値 1 は挿入操作を表します。次の 2 つのパラメータは挿入位置と挿入された要素の値を表します。数値 2 は削除操作を表します。後者のパラメータは削除位置を表します。数値 3 は検索操作を表します。後者のパラメータは4は順序表の出力操作出力形式:操作2は削除した要素の値を出力、操作3は要素の位置を出力、要素が存在しない場合は「NOT FOUND」を出力; 操作 4 では、シーケンス テーブル全体をシーケンス要素で出力し、2 つの要素はスペースで区切られ、最後の要素の後にスペースはありません。
入力例:
4
1 1 11
2 2
3 3
4
出力サンプル:
1
3
11 2 3 4 5 6 7 8 9 10
コード:
//pos位置之后的元素都往后挪一位,给pos让位
//注意:存储可能不够
Status ListInsert_Sq(SqList &L, int pos, ElemType e)
{
if(L.length + 1 < pos || pos<1)
return OVERFLOW;
else
{
if(L.length >= L.listsize)
{
ElemType* newelem;
newelem = (ElemType *)realloc(L.elem,(L.listsize+LISTINCREMENT) * sizeof(ElemType));
if(!newelem)
return ERROR;
L.elem = newelem;
L.listsize += LISTINCREMENT;
}
ElemType *temp, *p;
temp = &(L.elem[pos-1]);
for(p = &(L.elem[L.length-1]); p >= temp; p--)
*(p+1) = *p;
*temp = e;
L.length = L.length + 1;
return OK;
}
}
//将pos位置的元素赋值给e,然后后边的一次覆盖前边的元素
//注意:pos可能不合法
Status ListDelete_Sq(SqList &L, int pos, ElemType &e)
{
if(L.length < pos || pos<1)
return OVERFLOW;
else
{
e = L.elem[pos-1];
ElemType* temp;
for(temp = &(L.elem[pos-1]); temp <= &(L.elem[L.length-1]); temp++)
*temp = *(temp+1);
L.length = L.length - 1;
//return OK;
}
}
//遍历,只要有相同的就标记并结束
int ListLocate_Sq(SqList L, ElemType e)
{
int i;
for(i = 0; i < L.length; i++)
{
if(L.elem[i] == e)
{
//break;
return i+1;
}
}
return ERROR;
}
void ListPrint_Sq(SqList L)
{
int i;
for (i=0;i<L.length;i++)
{
if (i==0) printf("%d",L.elem[i]);
else printf(" %d",L.elem[i]);
}
}
1X1-1シーケンステーブルの基本操作
この問題では、シーケンス テーブル要素の追加、削除、検索、出力という 4 つの基本的な操作関数の実装が必要です。L はシーケンス テーブルです。関数 Status ListInsert_Sq(SqList &L, int pos, ElemType e) は、シーケンス テーブルの pos 位置に要素 e を挿入します (pos は 1 から開始する必要があります)。関数 Status ListDelete_Sq(SqList &L, int pos , ElemType &e ) は、シーケンス テーブルの pos の位置にある要素を削除し、参照パラメーター e でそれを戻します (pos は 1 から開始する必要があります)。関数 int ListLocate_Sq(SqList L, ElemType e) は、要素の位置をクエリします。 (複数の項目の最初の位置を取得し、1 から始まる位置を返します。存在しない場合は 0 を返します。) 関数 void ListPrint_Sq (SqList L) は、出力シーケンス リストです。要素。テーブルの全容量拡張の問題は、実装時に考慮する必要があります。
関数インターフェースの定義:
Status ListInsert_Sq(SqList &L, int pos, ElemType e);
Status ListDelete_Sq(SqList &L, int pos, ElemType &e);
int ListLocate_Sq(SqList L, ElemType e);
void ListPrint_Sq(SqList L);
ここで、L はシーケンス リストです。pos は位置、e は要素を表します。挿入および削除操作の pos パラメータが不正な場合、関数は ERROR を返し、それ以外の場合は OK を返します。
審判テスト手順の例:
//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
//顺序表的存储结构定义
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef int ElemType; //假设线性表中的元素均为整型
typedef struct{
ElemType* elem; //存储空间基地址
int length; //表中元素的个数
int listsize; //表容量大小
}SqList; //顺序表类型定义
Status ListInsert_Sq(SqList &L, int pos, ElemType e);
Status ListDelete_Sq(SqList &L, int pos, ElemType &e);
int ListLocate_Sq(SqList L, ElemType e);
void ListPrint_Sq(SqList L);
//结构初始化与销毁操作
Status InitList_Sq(SqList &L){
//初始化L为一个空的有序顺序表
L.elem=(ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!L.elem)exit(OVERFLOW);
L.listsize=LIST_INIT_SIZE;
L.length=0;
return OK;
}
int main() {
SqList L;
if(InitList_Sq(L)!= OK) {
printf("InitList_Sq: 初始化失败!!!\n");
return -1;
}
for(int i = 1; i <= 10; ++ i)
ListInsert_Sq(L, i, i);
int operationNumber; //操作次数
scanf("%d", &operationNumber);
while(operationNumber != 0) {
int operationType; //操作种类
scanf("%d", & operationType);
if(operationType == 1) { //增加操作
int pos, elem;
scanf("%d%d", &pos, &elem);
ListInsert_Sq(L, pos, elem);
} else if(operationType == 2) { //删除操作
int pos; ElemType elem;
scanf("%d", &pos);
ListDelete_Sq(L, pos, elem);
printf("%d\n", elem);
} else if(operationType == 3) { //查找定位操作
ElemType elem;
scanf("%d", &elem);
int pos = ListLocate_Sq(L, elem);
if(pos >= 1 && pos <= L.length)
printf("%d\n", pos);
else
printf("NOT FIND!\n");
} else if(operationType == 4) { //输出操作
ListPrint_Sq(L);
}
operationNumber--;
}
return 0;
}
/* 请在这里填写答案 */
入力形式: 1行目にオペランドを表す整数のoperationNumberを入力し、その後にoperationNumber行を入力し、各行に操作情報(「操作種類番号 操作内容」を含む)を入力します。数値 1 は挿入操作を表します。次の 2 つのパラメータは挿入位置と挿入された要素の値を表します。数値 2 は削除操作を表します。後者のパラメータは削除位置を表します。数値 3 は検索操作を表します。後者のパラメータは4は順序表の出力操作出力形式:操作2は削除した要素の値を出力、操作3は要素の位置を出力、要素が存在しない場合は「NOT FOUND」を出力; 操作 4 では、シーケンス テーブル全体をシーケンス要素で出力し、2 つの要素はスペースで区切られ、最後の要素の後にスペースはありません。
入力例:
4
1 1 11
2 2
3 3
4
出力サンプル:
1
3
11 2 3 4 5 6 7 8 9 10
コード:
//添加元素
//pos位置之后的元素都往后挪一位,给pos让位
//注意:存储可能不够
Status ListInsert_Sq(SqList &L, int pos, ElemType e)
{
if (pos<1 || pos>L.length+1) return OVERFLOW; //注意判断条件限制的临界值
if (L.length >= L.listsize)
{
L.elem = (ElemType *)realloc(L.elem,(L.listsize + LISTINCREMENT)*sizeof(ElemType));
if (!L.elem) exit(OVERFLOW);
L.listsize += LISTINCREMENT;
}
ElemType*p;
for(p = L.elem+L.length-1; p >= L.elem+pos-1; p--)
*(p+1) = *p;
*(L.elem+pos-1) = e;
L.length++;
return OK;
}
//删除元素
//将pos位置的元素赋值给e,然后后边的一次覆盖前边的元素
//注意:pos可能不合法
Status ListDelete_Sq(SqList &L, int pos, ElemType &e)
{
if (pos<1 || pos>L.length)
return OVERFLOW;
e = L.elem[pos-1];
ElemType *p;
for (p = L.elem+pos-1;p<=L.elem+L.length-1;p++)
*p = *(p+1);
L.length--;
return OK;
}
//查询元素
//遍历,只要有相同的就标记并结束
int ListLocate_Sq(SqList L, ElemType e)
{
for (int i=0;i<L.length;i++)
if (e==L.elem[i]) return i+1;
return ERROR;
}
//输出元素
void ListPrint_Sq(SqList L)
{
ElemType *p;
for (p = L.elem;p<L.elem+L.length;p++)
{
if (p==L.elem) printf("%d",*p);
else printf(" %d",*p);
}
}
2X2-1 メモリ爆発関数の例
この質問には再帰関数の実装が必要です。ユーザーは非負の整数パラメーター n を渡し、ユーザーは 1 から n までの整数を順番に出力します。いわゆる再帰関数とは、それ自体を呼び出す関数を指します。
例証します:
- 再帰関数解決の基本的な考え方は、大規模な問題の解決策を比較的小規模な問題の解決策に還元し、小規模な
問題を比較的小規模な問題の解決策に還元することです。問題の規模が境界と同じくらい小さくなるまで続きます (境界問題は直接解決できます)。再帰関数は 2 つの
部分で構成され、1 つは再帰境界、もう 1 つは再帰関係です。階乗関数を例にとると、再帰境界Factorial(1)=1;
再帰式:Factorial(n)=n*Factorial(n-1),
対応する再帰関数は次のとおりです。
int GetFactorial(int n)
{
int result;
if(n==1) result = 1; //递归边界,此时问题答案易知,可直接求解
else result =n* GetFactorial(n-1); //递归关系,大问题求解归结为小问题求解
return result;
}
- 再帰的な関数呼び出し(自身の呼び出し)や通常の関数呼び出しが発生した場合、システムは呼び出し前の実行場面
情報これにより、呼び出された関数が実行され、スムーズに戻って
以降の操作を続けることができます。各呼び出しではシーン情報を保存する必要があります。このシーン情報を保存するために必要な補助領域のサイズは、
関数呼び出しの数に比例します。つまり、その領域の複雑さは O(n) (n は呼び出しの数) です。 - この例の目的は、学生が再帰関数を作成し、メモリが爆発してメモリ オーバーフロー エラーが発生するまでに再帰呼び出しが何回発生するかを自分のマシンでテストできるようにすることです (パラメータが 66000 に設定されているとオーバーフローします)
。私のオフィスのマシンで)。同じ問題に対して、
再帰関数を使用せずに通常のループ文を使用して問題を解決すると、メモリ オーバーフローは発生しません。
関数インターフェースの定義:
void PrintN (long n);
ここで、n はユーザーによって渡されたパラメータです。
審判テスト手順の例:
テストのために呼び出される関数の例をここに示します。例えば:
#include <stdio.h>
void PrintN(long n);
int main()
{
PrintN(66000L);
return 0;
}
/* 请在这里填写答案 */
入力例:
5
出力サンプル:
12345
コード:
//找递归的结束条件:到1时结束就好
void PrintN(long n)
{
if(n==1)
printf("%d",n);
else
{
PrintN(n-1);
printf("%d",n);
}
}
3X3-1 シーケンス テーブルの作成とその場での反転
この問題では、順序表の作成とその場反転演算関数が必要です。L はシーケンス テーブルです。関数 ListCreate_Sq(SqList &L) は、シーケンス テーブルの作成に使用されます。関数 ListReverse_Sq(SqList &L) は、補助配列を導入せずにシーケンス テーブル内の要素を反転します。たとえば、元の順序表は 1,2,3,4 の順になっており、反転すると 4,3,2,1 になります。
関数インターフェースの定義:
Status ListCreate_Sq(SqList &L);
void ListReverse_Sq(SqList &L);
審判テスト手順の例:
//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
//顺序表的存储结构定义
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef int ElemType; //假设线性表中的元素均为整型
typedef struct{
ElemType* elem; //存储空间基地址
int length; //表中元素的个数
int listsize; //表容量大小
}SqList; //顺序表类型定义
Status ListCreate_Sq(SqList &L);
void ListReverse_Sq(SqList &L);
int main() {
SqList L;
ElemType *p;
if(ListCreate_Sq(L)!= OK) {
printf("ListCreate_Sq: 创建失败!!!\n");
return -1;
}
ListReverse_Sq(L);
if(L.length){
for(p=L.elem;p<L.elem+L.length-1;++p){
printf("%d ",*p);
}
printf("%d",*p);
}
return 0;
}
/* 请在这里填写答案 */
入力形式: 最初の行に、順序テーブルの要素数を表す整数 n を入力します。次の n 個の整数は、スペースで区切られたテーブル要素です。出力形式: 逆順テーブルの各要素をスペースで区切って出力し、最後の要素の後にはスペースを入れません。
入力例:
4
1 2 3 4
出力サンプル:
4 3 2 1
コード:
//思路:动态分配空间,设置表长,设置指针p,通过p++来输入元素,表容量为100
//注意:有可能分配空间会失败
Status ListCreate_Sq(SqList &L)
{
int n;
ElemType *p;
L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if (!L.elem) exit(OVERFLOW);
L.listsize = LIST_INIT_SIZE;
scanf("%d",&n);
L.length = n;
for (p = L.elem;p<L.elem + L.length; p++)
scanf("%d",p);
return OK;
}
//思路:定义两个指针First和last分别指向顺序表的首地址和最后元素的地址,First和Last的元素交换,Frist和Last自增,一直到中间元素结束
//注意:
void ListReverse_Sq(SqList &L)
{
ElemType* First;
ElemType* Last;
ElemType temp;
for (First = L.elem,Last = L.elem + L.length - 1 ;First<=(L.elem + L.length/2),Last>=(L.elem + L.length/2);First++,Last--)
{
temp = *First;
*First = *Last;
*Last = temp;
}
}
3X3-2 順序付けシーケンス テーブルへの挿入
この質問では、昇順シーケンス テーブルの順序付き挿入関数の実装が必要です。L は昇順のシーケンス リストであり、関数 Status ListInsert_SortedSq(SqList &L, ElemType e) を使用してデータを昇順でシーケンス テーブルに挿入します。例: 元のデータは 2 5 で、要素 3 が挿入されると、挿入後のシーケンス テーブルは 2 3 5 になります。拡張の問題を考慮してください。
関数インターフェースの定義:
Status ListInsert_SortedSq(SqList &L, ElemType e);
審判テスト手順の例:
//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
//顺序表的存储结构定义
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
typedef int ElemType; //假设线性表中的元素均为整型
typedef struct{
ElemType* elem; //存储空间基地址
int length; //表中元素的个数
int listsize; //表容量大小
}SqList; //顺序表类型定义
//函数声明
Status ListInsert_SortedSq(SqList &L, ElemType e);
//顺序表初始化函数
Status InitList_Sq(SqList &L)
{
//开辟一段空间
L.elem = (ElemType*)malloc(LIST_INIT_SIZE * sizeof(ElemType));
//检测开辟是否成功
if(!L.elem){
exit(OVERFLOW);
}
//赋值
L.length = 0;
L.listsize = LIST_INIT_SIZE;
return OK;
}
//顺序表输出函数
void ListPrint_Sq(SqList L)
{
ElemType *p = L.elem;//遍历元素用的指针
for(int i = 0; i < L.length; ++i){
if(i == L.length - 1){
printf("%d", *(p+i));
}
else{
printf("%d ", *(p+i));
}
}
}
int main()
{
//声明一个顺序表
SqList L;
//初始化顺序表
InitList_Sq(L);
int number = 0;
ElemType e;
scanf("%d", &number);//插入数据的个数
for(int i = 0; i < number; ++i)
{
scanf("%d", &e);//输入数据
ListInsert_SortedSq(L, e);
}
ListPrint_Sq(L);
return 0;
}
/* 请在这里填写答案 */
入力形式:1行目に挿入する数字の個数を入力 2行目には数字を入力 出力形式:挿入後の数字を出力 入力
例:
5
2 3 9 8 4
出力サンプル:
2 3 4 8 9
コード:
//设置指针p,从最后一位开始如果待插入的元素比当前元素小,就把当前元素后移一位,一直到当前元素比待插入元素小
//注意:有可能表满,需要扩容
Status ListInsert_SortedSq(SqList &L, ElemType e)
{
//对表满情况的处理
if (L.length>=L.listsize)
{
L.elem = (ElemType *)realloc(L.elem,(L.listsize + LISTINCREMENT)*sizeof(ElemType));//注意每次扩容的基础
if (!L.elem) exit(OVERFLOW);
L.listsize += LISTINCREMENT;
}
ElemType *p = L.elem + L.length -1;
while (p>=L.elem && *p>e) //定位以及移动
{
*(p+1) = *p;
p--;
}
*(p+1) = e; //插入
L.length++;
return OK;
}
3X3-3 配列循環左シフト
この質問では、配列を左に循環シフトする単純な関数の実装が必要です。配列 a には n (>0) 個の整数があり、他の配列の使用が許可されていないという前提で、各整数は循環シフトされます。 m (≥0 ) 個の位置だけ左に移動します。つまり、 a のデータは (a 0 a 1 ⋯a n−1 ) から (am m ⋯a) に変換されます。 n−1 a 0 a 1 ⋯am m-1 )(最初の m 個の数値が最後の m 個の位置に循環的に移動されます)。プログラムによるデータの移動回数をできるだけ少なくすることも考慮する必要がある場合、移動方法をどのように設計すればよいでしょうか?
入力形式:
入力の最初の行は正の整数 n (≤100) と整数 m (≥0) を与え、2 行目はスペースで区切られた n 個の整数を与えます。
出力フォーマット:
m ビットだけ左回転された整数シーケンスをスペースで区切って 1 行に出力します。シーケンスの最後に余分なスペースがあってはなりません。
入力例:
8 3
1 2 3 4 5 6 7 8
出力サンプル:
4 5 6 7 8 1 2 3
コード:
//思路:需要左移的串逆转,需要右移的串逆转,将两个串拼接起来,再逆转就会得到结果
#include <stdio.h>
//实现字符串的逆转
void Reverse(int *s,int left,int right)
{
int temp;
while (left<right)
{
temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
}
//输出数组
void Print(int *s,int len)
{
int i;
for (i=0;i<len;i++)
{
if (i==0) printf("%d",s[i]);
else printf(" %d",s[i]);
}
}
int main()
{
int s[110];
int n,m;
int i;
scanf("%d %d",&n,&m);
m = m%n;
for (i=0;i<n;i++)
scanf("%d",&s[i]);
Reverse(s,0,m-1); //逆转前半部分需要左移的
Reverse(s,m,n-1); //逆转后半部分需要右移的
Reverse(s,0,n-1); //逆转整个字符串
Print(s,n);
}
4X4-1線形テーブル要素の間隔削除
連続的に格納された線形リストが与えられた場合、最小値より大きく最大値より小さい値を持つすべての要素を削除する関数を設計してください。削除後、テーブル内の残りの要素は順番に格納されたままとなり、それらの相対位置を変更することはできません。
関数インターフェースの定義:
List Delete( List L, ElementType minD, ElementType maxD );
リスト構造は次のように定義されます。
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
L はユーザーによって渡される線形テーブルで、ElementType 要素は >、==、< を通じて比較できます。minD と maxD はそれぞれ、削除される要素の値の範囲の下限と上限です。関数 Delete は、minD より大きく、maxD より小さい値を持つ Data[] 内のすべての要素を削除する必要があります。その一方で、テーブル内の残りの要素が順番に格納され、それらの相対位置が変更されないことを確認し、最終的に削除されたテーブルを返します。
審判テスト手順の例:
#include <stdio.h>
#define MAXSIZE 20
typedef int ElementType;
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
List ReadInput(); /* 裁判实现,细节不表。元素从下标0开始存储 */
void PrintList( List L ); /* 裁判实现,细节不表 */
List Delete( List L, ElementType minD, ElementType maxD );
int main()
{
List L;
ElementType minD, maxD;
int i;
L = ReadInput();
scanf("%d %d", &minD, &maxD);
L = Delete( L, minD, maxD );
PrintList( L );
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
10
4 -8 2 12 1 5 9 3 3 10
0 4
出力サンプル:
4 -8 12 5 9 10
コード:
//思路:遍历数组元素,将每一个元素需要前移的位数找出来,再分别将元素前移多少位数即可
//注意:L.length需要变化;有可能会有minD和maxD不合理的请求
List Delete( List L, ElementType minD, ElementType maxD )
{
if(minD >= maxD) return L;
int i;
int num = 0;
for (i = 0;i<=L->Last;i++) //注意L->Last是最后一个元素
{
if (L->Data[i]>minD && L->Data[i]<maxD) num++;
else L->Data[i-num] = L->Data[i];
}
L->Last -= num;
return L;
}
//补充:在移动元素的时候,不是使用覆盖的方法,只需要把当前元素直接向前移动num就行,不用使用while
4X4-2 最長連続増加サブシーケンス
連続的に格納された線形リストを指定して、線形リスト内で最も長く連続して増加するサブシーケンスを見つけるアルゴリズムを設計します。たとえば、(1,9,2,5,7,3,4,6,8,0) 内の最長の増加部分列は (3,4,6,8) です。
入力形式:
入力行 1 は正の整数 n (≤10 5 ) を与え、行 2 はスペースで区切られた n 個の整数を与えます。
出力フォーマット:
1 行に初めて出現する、連続して増加するサブシーケンスを出力します。数値はスペースで区切られます。シーケンスの最後に余分なスペースがあってはなりません。
入力例:
15
1 9 2 5 7 3 4 6 8 0 11 15 17 17 10
出力サンプル:
3 4 6 8
コード:
/*思路:首先,创建一个结构体,定义一个maxIncSeq,用来记录最长连续递增子序列,再定义一个curIncSeq,用来记录当前连续递增子序列的信息
只要后一位的数比前一位要大,就更新curIncSeq的信息。
如果,当前长度大于最长的,就把maxIncSeq的信息更新。
注意:最后一个连续递增子序列需要单独处理*/
#include <stdio.h>
typedef struct IncSeq
{
int *p; //记录序列的开始位置
int length; //记录序列的长度
} IncSeq;
int main()
{
IncSeq maxIncSeq;
IncSeq curIncSeq;
int n;
int num = 0;
int a[100001];
int *q = a;
scanf("%d",&n);
for (int i=0;i<n;i++)
a[i] = 0;
maxIncSeq.p = a; //初始化连续递增子序列的信息
maxIncSeq.length = 0;
curIncSeq.p = a;
curIncSeq.length = 0;
scanf("%d",&a[0]);
for (q = a+1;q<a+n;q++)
{
scanf("%d",q);
num++;
if (*(q-1) >= *q)
{
curIncSeq.p = q-num; //更新curIncSeq的信息
curIncSeq.length = num;
if ( maxIncSeq.length < curIncSeq.length) //更新maxIncSeq的信息
{
maxIncSeq.p = curIncSeq.p;
maxIncSeq.length = curIncSeq.length;
}
num = 0;
}
}
//对最后一个递增子序列的单独处理
int lastLen = (a+n)-(curIncSeq.p + curIncSeq.length);
if (lastLen > maxIncSeq.length)
{
maxIncSeq.p = curIncSeq.p + curIncSeq.length;
maxIncSeq.length = lastLen;
}
for (q = maxIncSeq.p;q<maxIncSeq.p + maxIncSeq.length;q++) //输出最长连续递增子序列
{
if (q == maxIncSeq.p) printf("%d",*q);
else printf(" %d",*q);
}
}
/*补充:(1)比较连续递增子序列是否结束时,必须使用前一位和当前位的比较
(2)最后一位的单独处理注意开始位置和长度
(3)使用num计数,更新最大序列的信息时,不要忘记把num清0,而且注意num=0放的位置
*/
5X5-1 単一リンクリスト要素の配置
この質問では、リンク リスト内の最初のデータ フィールド値が x であるノードを見つけて、ノードの順序を返す必要があります。L はヘッド ノードを持つ単一リンク リストです。関数 ListLocate_L (LinkList L, ElemType x) では、リンク リスト内の最初のデータ フィールド値が x であるノードを見つけて、その順序 (1 から開始) を返す必要があります。見つかった場合は 0 を返します。たとえば、元の単一リンク リストの各要素ノードの要素が 1、2、3、および 4 である場合、ListLocate_L(L, 1) は 1 を返し、ListLocate_L(L, 3) は 3 を返し、ListLocate_L(L, 100) は 0 を返します。
関数インターフェースの定義:
int ListLocate_L(LinkList L, ElemType x);
ここで、L は主要ノードの単一リンクリストです。x は指定された値です。この関数は、リンク リスト内の最初のデータ フィールド値 x を持つノードを検索する必要があります。見つかった場合はそのビット順序 (1 から始まる) が返され、見つからなかった場合は 0 が返されます。
審判テスト手順の例:
//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType; //假设线性表中的元素均为整型
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status ListCreate_L(LinkList &L,int n)
{
LNode *rearPtr,*curPtr; //一个尾指针,一个指向新节点的指针
L=(LNode*)malloc(sizeof (LNode));
if(!L)exit(OVERFLOW);
L->next=NULL; //先建立一个带头结点的单链表
rearPtr=L; //初始时头结点为尾节点,rearPtr指向尾巴节点
for (int i=1;i<=n;i++){ //每次循环都开辟一个新节点,并把新节点拼到尾节点后
curPtr=(LNode*)malloc(sizeof(LNode));//生成新结点
if(!curPtr)exit(OVERFLOW);
scanf("%d",&curPtr->data);//输入元素值
curPtr->next=NULL; //最后一个节点的next赋空
rearPtr->next=curPtr;
rearPtr=curPtr;
}
return OK;
}
//下面是需要实现的函数的声明
int ListLocate_L(LinkList L, ElemType x);
int main()
{
LinkList L;
int n;
int x,k;
scanf("%d",&n); //输入链表中元素个数
if(ListCreate_L(L,n)!= OK) {
printf("表创建失败!!!\n");
return -1;
}
scanf("%d",&x); //输入待查找元素
k=ListLocate_L(L,x);
printf("%d\n",k);
return 0;
}
/* 请在这里填写答案 */
入力例:
4
1 2 3 4
1
出力サンプル:
1
コード:
/*
思路:遍历链表,使用count计数的同时比较L->data和x,只要相等就返回count,否则返回0
注意:如果x不存在于链表中,那么最后指针p为NULL
*/
int ListLocate_L(LinkList L, ElemType x)
{
LNode *p=L;
int count=1;
while(p->next != NULL)
{
p = p->next;
if(p->data == x) return count;
count++;
}
return 0;
}
5X5-2 指定された値と等しい単一リンクリスト内の最後のノードを削除します。
この質問では、リンク リスト内の最後のデータ フィールド値 x を持つノードを削除する必要があります。L はヘッド ノードを持つ単一リンク リストです。関数 ListLocateAndDel_L(LinkList L, ElemType x) では、リンク リスト内の最後のデータ フィールド値 x を持つノードを見つけて削除する必要があります。たとえば、元の単一リンク リストの各ノードのデータ フィールドは 1 3 1 4 3 5 です。ListLocateAndDel_L(L,3) の実行後、リンク リストの残りのノードのデータ フィールドは 1 3 1 4 5 になります。 。
関数インターフェースの定義:
void ListLocateAndDel_L(LinkList L, ElemType x);
ここで、L は主要ノードの単一リンクリストです。x は指定された値です。この関数は、リンク リスト内の最後のデータ フィールド値 x を持つノードを見つけて削除する必要があります。
審判テスト手順の例:
//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define NULL 0
typedef int Status;
typedef int ElemType; //假设线性表中的元素均为整型
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//链表创建函数
Status ListCreate_L(LinkList &L,int n)
{
LNode *rearPtr,*curPtr;
L=(LNode*)malloc(sizeof (LNode));
if(!L)exit(OVERFLOW);
L->next=NULL;
rearPtr=L;
for (int i=1;i<=n;i++){
curPtr=(LNode*)malloc(sizeof(LNode));
if(!curPtr)exit(OVERFLOW);
scanf("%d",&curPtr->data);
curPtr->next=NULL;
rearPtr->next=curPtr;
rearPtr=curPtr;
}
return OK;
}
//链表输出函数
void ListPrint_L(LinkList L)
{
LNode *p=L->next;
if(!p){
printf("空表");
return;
}
while(p!=NULL)
{
if(p->next!=NULL)
printf("%d ",p->data);
else
printf("%d",p->data);
p=p->next;
}
}
//下面是需要实现的函数的声明
void ListLocateAndDel_L(LinkList L, ElemType x);
int main()
{
LinkList L;
int n;
int x;
scanf("%d",&n); //输入链表中元素个数
if(ListCreate_L(L,n)!= OK) {
printf("表创建失败!!!\n");
return -1;
}
scanf("%d",&x); //输入待查找元素
ListLocateAndDel_L(L,x);
ListPrint_L(L);
return 0;
}
/* 请在这里填写答案 */
入力例:
6
1 3 1 4 3 5
3
出力サンプル:
1 3 1 4 5
コード:
/*
思路:先遍历一遍链表,把与x相等的值的个数num找出来,然后再遍历一遍链表,使用count计数器,只要遇到x,count就自增。
当count与num相等时,就把对应的x值删除
注意:x有可能不存在于链表中,那么此时的num==0;当x位于最后一位时需要特殊处理
*/
void ListLocateAndDel_L(LinkList L, ElemType x)
{
//遍历链表找出与x相等的个数
LNode *p = L;
int num = 0;
while (p->next != NULL)
{
if (p->data == x) num++;
p = p->next;
}
if (p->data == x) num++;
//删除最后一个与x相等的值
LNode *q = L;
int count = 0;
while (q->next != NULL)
{
if (q->next->data == x) count++;
if (count == num && num != 0) //注意元素不存在的判断
{
q->next = q->next->next;
break;
}
q = q->next;
}
}
5X5-3 2 つの順序付きリンク リスト シーケンスのマージ
2 つの非降順リンク リスト シーケンス S1 および S2 が与えられると、設計機能は S1 と S2 を結合した後に新しい非降順リンク リスト S3 を構築します。
入力形式:
入力は 2 行に分割され、各行は、シーケンスの終わりを表す -1 を使用した、いくつかの正の整数で構成される非降順シーケンスを示します (-1 はこのシーケンスに属しません)。数字はスペースで区切られます。
出力フォーマット:
マージされた新しい非降順リンク リストを 1 行で出力します。数値はスペースで区切られ、末尾に余分なスペースはありません。新しいリンク リストが空の場合は、NULL が出力されます。
入力例:
1 3 5 -1
2 4 6 8 10 -1
出力サンプル:
1 2 3 4 5 6 8 10
コード:
/*
思路:定义两个指针p、q分别指向s1和s2,从第一个元素开始比较,如果p->data大于q->data的话,就把q->next放入新的链表中。
然后,q = q->next,p不动,继续和下一个比较,以此类推
注意:总有一个链表要先遍历完,直接把剩余链表的元素接上就行
*/
#include <bits/stdc++.h>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define NULL 0
typedef int Status;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
//函数实现
Status CreatList(LinkList &L); //创建一个链表
LinkList InsertList(); //往链表里插入元素
LinkList Merge(LinkList s1,LinkList s2); //合并两个链表
void Print(LinkList L); //输出链表的元素
int main()
{
LinkList s1,s2,L;
CreatList(s1);
CreatList(s2);
CreatList(L);
s1 = InsertList();
s2 = InsertList();
L = Merge(s1,s2);
Print(L);
}
//创建链表
Status CreatList(LinkList &L)
{
L = (LNode*)malloc(sizeof(LNode));
if (!L) exit(OVERFLOW);
L->next = NULL;
return OK;
}
//向链表中插入元素
LinkList InsertList()
{
int n;
LinkList L;
CreatList(L);
LNode *p = L;
scanf("%d",&n);
while (n != -1)
{
LNode *temp;
temp = (LNode*)malloc(sizeof(LNode));
temp->data = n;
p->next = temp;
p = temp;
scanf("%d",&n);
p->next = NULL;
}
return L;
}
//合并链表
LinkList Merge(LinkList s1,LinkList s2)
{
LNode *p = s1->next; //用来遍历s1
LNode *q = s2->next; //用来遍历s2
LinkList L; //不要忘记初始化
L = (LNode *)malloc(sizeof(LNode));
LNode *temp = L;
while (p && q)
{
if (p->data < q->data)
{
temp->next = p; //连接元素
temp = p; //新表移动
p = p->next; //原来的表移动
}
else
{
temp->next = q;
temp = q;
q = q->next;
}
}
//将剩余元素接上
temp->next = p?p:q;
s1->next = NULL;
s2->next = NULL;
return L;
}
//输出元素
//注意与顺序表不同的是要在循环里边加上L = L->next
void Print(LinkList L)
{
L = L->next;
int num = 0;
if (L==NULL) printf("NULL");
else
{
while (L)
{
if (!num) printf("%d",L->data);
else printf(" %d",L->data);
num++;
L = L->next;
}
printf("\n");
}
}
6X6-1 先頭ノードの単一リンクリストがその場で反転されます
この質問では、ヘッド ノードを使用した単一リンク線形リストのインプレース反転演算関数を実装する関数を記述する必要があります。L はヘッド ノードを持つ単一リンク リストです。関数 ListReverse_L (LinkList &L) では、新しいノードを開かずに単一リンク リストの要素を反転する必要があります。たとえば、元の単一リンク リストの要素は 1、2、 3、4の順で反転すると4、3、2、1となります。
関数インターフェースの定義:
void ListReverse_L(LinkList &L);
ここで、L はヘッド ノードを持つ単一リンク リストです。
審判テスト手順の例:
//库函数头文件包含
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int ElemType; //假设线性表中的元素均为整型
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status ListCreate_L(LinkList &L,int n)
{
LNode *rearPtr,*curPtr; //一个尾指针,一个指向新节点的指针
L=(LNode*)malloc(sizeof (LNode));
if(!L)exit(OVERFLOW);
L->next=NULL; //先建立一个带头结点的单链表
rearPtr=L; //初始时头结点为尾节点,rearPtr指向尾巴节点
for (int i=1;i<=n;i++){ //每次循环都开辟一个新节点,并把新节点拼到尾节点后
curPtr=(LNode*)malloc(sizeof(LNode));//生成新结点
if(!curPtr)exit(OVERFLOW);
scanf("%d",&curPtr->data);//输入元素值
curPtr->next=NULL; //最后一个节点的next赋空
rearPtr->next=curPtr;
rearPtr=curPtr;
}
return OK;
}
void ListReverse_L(LinkList &L);
void ListPrint_L(LinkList &L){
//输出单链表
LNode *p=L->next; //p指向第一个元素结点
while(p!=NULL)
{
if(p->next!=NULL)
printf("%d ",p->data);
else
printf("%d",p->data);
p=p->next;
}
}
int main()
{
LinkList L;
int n;
scanf("%d",&n);
if(ListCreate_L(L,n)!= OK) {
printf("表创建失败!!!\n");
return -1;
}
ListReverse_L(L);
ListPrint_L(L);
return 0;
}
/* 请在这里填写答案 */
入力形式:
最初の行に、単一リンク リストの要素の数を表す整数 n を入力します。次の行には、スペースで区切られた合計 n 個の整数が含まれます。
出力フォーマット:
逆順リストの各要素を出力します。2 つの要素はスペースで区切られ、最後の要素の後にスペースはありません。
入力例:
4
1 2 3 4
出力サンプル:
4 3 2 1
コード:
/*思路:使用指针p来指向当前元素,另一个指针q赋值为当前元素的next成员,p的next成员赋值为q的next成员,这就实现把链表中的元素取出来。
取出来的元素用q来表示,把q添加到头结点的后边,q的next成员赋值为第一个元素即可。以此类推,直至链表为NULL。
注意:有可能链表为空或者链表只有一个元素
*/
void ListReverse_L(LinkList &L)
{
LNode *p; //用于指向当前元素
LNode *q; //用于取出元素
p = L->next;
while (p->next != NULL)
{
//取出当前元素
q = p->next;
p->next = q->next;
//添加到头结点后边
q->next = L->next;
L->next = q;
}
}
6X6-2 1 変数多項式の導出
1 つの変数の多項式の導関数を求める関数を設計します。
入力形式:
多項式のゼロ以外の係数と指数を指数降順で入力します (絶対値はすべて 1000 を超えない整数です)。数字はスペースで区切ります。
出力フォーマット:
微分多項式の非ゼロ項の係数と指数を入力と同じ形式で出力します。数字はスペースで区切る必要がありますが、末尾に余分なスペースがあってはなりません。
入力例:
3 4 -5 2 6 1 -2 0
出力サンプル:
12 3 -10 1 6 0
コード:
/*思路:多项式的求导就是系数变成指数和原来系数相同,指数减一。由于该多项式是一元多项式而且指数按照递降顺序排列,所以不需要求导以后的合并。
求导过程:指数乘以系数,然后指数减一
注意:创造结构体时data的类型是Elemtype,而此时的data包括两个内容,系数和指数,又是结构体类型
*/
#include <bits/stdc++.h>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef struct Elemtype
{
int coef; //系数
int index; //指数
}Elemtype;
typedef struct LNode
{
Elemtype data;
struct LNode *next;
}LNode,*LinkList;
//函数实现
Status CreatList(LinkList &L); //创建链表
LinkList InputList(); //输入多项式
void Deri_List(LinkList &L); //求导
void Print_L(LinkList L); //输出多项式
int Flag1 = 0;
int Flag2 = 0;
int Flag3 = 0;
int main()
{
LinkList L;
CreatList(L);
L = InputList();
Deri_List(L);
Print_L(L);
}
Status CreatList(LinkList &L)
{
L = (LNode*)malloc(sizeof(LNode));
if (!L) exit(OVERFLOW);
L->next = NULL;
return OK;
}
LinkList InputList()
{
int m,n = 1;
LinkList L;
CreatList(L);
LNode *p = L;
int flag = 0;
while (scanf("%d",&m)!=EOF)
{
Flag1 = 1;
if (m==0 && flag == 0) Flag2 = 2;
LNode *temp = (LNode*)malloc(sizeof(LNode));
temp->data.coef = m; //系数
if (scanf("%d",&n)!=EOF)
{
temp->data.index = n; //指数
if (n == 0 && flag == 0) Flag2 = 2;
else if (n==0) Flag3 = 3;
}
else break;
flag++;
p->next = temp;
p = temp;
p->next = NULL;
}
return L;
}
void Deri_List(LinkList &L)
{
LNode *p = L->next;
while (p != NULL)
{
p->data.coef *= p->data.index;
p->data.index--;
p = p->next;
}
}
void Print_L(LinkList L)
{
if (!Flag1||Flag2 == 2) printf("0 0");
else
{
LNode *p = L->next;
int flag = 0;
while (p != NULL)
{
if (p->data.index != -1)
{
if (flag != 0) printf(" %d %d",p->data.coef,p->data.index);
else printf("%d %d",p->data.coef,p->data.index);
flag++;
}
p = p->next;
}
printf("\n");
}
}
/*补充:(1)输入函数的结束标记:由于while循环体里面要求输入m,所以要在输入m之前break;
(2)如果只输入一个系数的情况
(3)如果输入的第一个数是0的情况
*/
6X6-3 連結線形テーブルの逆数から K 番目の項を求める
一連の正の整数が与えられた場合、下から K 番目の位置にある数値を見つけるためにできるだけ効率的なアルゴリズムを設計してください。
入力形式:
入力は最初に正の整数 K を与え、次にいくつかの正の整数が続き、最後に負の整数で終わります (負の数はシーケンスに含まれないため、処理する必要はありません)。
出力フォーマット:
最後からK番目のデータを出力します。存在しない場合はNULLのエラーメッセージが出力されます。
入力例:
4 1 2 3 4 5 6 7 8 9 0 -1
出力サンプル:
7
コード:
//求链式线性表的倒数第K项
/*
思路:设置两个指针p和q,两个指针之间的距离始终保持K个单位,当q指针指向末尾时,p指针就指向了倒数第K项
注意:链表长度可能小于K,此时要输出错误信息NULL
*/
#include <bits/stdc++.h>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
//函数实现
Status CreatList(LinkList &L); //创建链表
LinkList InputList(); //输入数据
void Print_K(LinkList L,int k); //按要求输出数据
int main()
{
LinkList L;
CreatList(L);
int k;
scanf("%d",&k);
L = InputList();
Print_K(L,k);
}
//创建链表
Status CreatList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode));
if (!L) exit(OVERFLOW);
L->next = NULL;
return OK;
}
//输入元素
LinkList InputList()
{
int n;
LinkList L;
CreatList(L);
LNode *p = L;
scanf("%d",&n);
while (n >= 0)
{
LNode *temp = (LNode*)malloc(sizeof(LNode));
temp->data = n;
p->next = temp;
p = temp;
scanf("%d",&n);
p->next = NULL;
}
return L;
}
void Print_K(LinkList L,int k)
{
LNode *p = L->next;
LNode *q = L->next;
int flag = 1;
while (p->next != NULL && flag < k)
{
p = p->next;
flag++;
}
while (p->next != NULL)
{
p = p->next;
q = q->next;
}
if (flag<k) printf("NULL");
else printf("%d",q->data);
}
7X7-1 スタック操作の合法性
S と X はそれぞれプッシュ操作とポップ操作を表すと仮定します。S と S だけからなるシーケンスに基づいて空のスタックを操作した場合 S および X シーケンスを入力して、シーケンスが正当であるかどうかを判断するプログラムを作成してください。
入力形式:
入力の最初の行は 2 つの正の整数 N と M を与えます。N はテストするシーケンスの数、M (≤50) はスタックの最大容量です。次に、N 行があり、それぞれが S と X のみからなるシーケンスを示します。シーケンスは空ではなく、長さが 100 を超えないことが保証されます。
出力フォーマット:
各シーケンスについて、そのシーケンスがスタック操作の正当なシーケンスである場合は YES を 1 行に出力し、そうでない場合は NO を出力します。
入力例:
4 10
SSSXXSXXSX
SSSXXSXXS
SSSSSSSSSSXSSXXXXXXXXXXX
SSSXXSXXX
出力サンプル:
YES
NO
NO
NO
コード:
/*
思路:定义一个栈,栈的容量就是待输入的m,如果输入s,那么栈顶指针后移,如果输入x,那么栈顶指针前移
如果栈顶指针超过栈底指针+栈容量,返回ERROR;
如果栈顶指针小于栈底指针,返回ERROR;
如果输入结束时,栈顶指针不等于栈底指针,返回ERROR;
*/
#include <bits/stdc++.h>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef struct Stack
{
int *base;
int *top;
int Stacksize;
}Stack;
Status InitStack(Stack &S,int len)
{
S.base = (int *)malloc(len * sizeof(int));
if (!S.base) exit(OVERFLOW);
S.top = S.base;
S.Stacksize = len;
return OK;
}
Status ClearStack(Stack &S)
{
S.top = S.base;
return OK;
}
int main()
{
Stack S;
string s;
int n,m;
scanf("%d %d",&n,&m);
InitStack(S,m);
int flag = 0;
while (n--)
{
cin>>s;
int len = s.length();
for (int i=0; i<len; i++)
{
if (s[i] == 'S') S.top++;
else if (s[i] == 'X') S.top--;
if (S.top > S.base + S.Stacksize || S.top < S.base) flag++;
if (i == len - 1 && S.top != S.base) flag++;
}
if (!flag) printf("YES\n");
else
{
printf("NO\n");
flag = 0;
}
ClearStack(S);
}
}
7X7-2 シンボルのペアリング
C言語ソースプログラム中の/と/、(and)、[and]、{and}の記号が一致するかどうかをチェックするプログラムを作成してください。
入力形式:
入力はC言語ソースプログラムです。特定の行にピリオドとキャリッジ リターンが 1 つだけある場合は、入力の終了を示します。プログラム内で一致をチェックする必要があるシンボルは 100 個までです。
出力フォーマット:
まず、すべてのシンボルが正しくペアになっている場合は、最初の行に YES を出力し、それ以外の場合は NO を出力します。次に、ペアになっていない最初のシンボルが 2 行目に示されます。左のシンボルが欠落している場合は、? - 右のシンボルが出力され、右のシンボルが欠落している場合は、左のシンボル - ? が出力されます。
入力例1:
void test()
{
int i, A[10];
for (i=0; i<10; i++) /*/
A[i] = i;
}
.
出力サンプル 1:
NO
/*-?
入力例2:
void test()
{
int i, A[10];
for (i=0; i<10; i++) /**/
A[i] = i;
}]
.
出力サンプル 2:
NO
?-]
入力例3:
void test()
{
int i
double A[10];
for (i=0; i<10; i++) /**/
A[i] = 0.1*i;
}
.
出力サンプル 3:
YES
コード:
/*
思路:定义一个栈,然后读入字符,只要没有同时遇到.和回车就判断是不是给定的符号,要是左半部分就存入栈,要是右半部分就出栈,如果二者对应即匹配
否则,即为不匹配。如果不匹配的话,输出对应缺少部分
*/
#include <bits/stdc++.h>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define STACK_INIT_SIZE 100
#define STACK_ADDSIZE 10
typedef int Status;
typedef struct Stack
{
char *top;
char *base;
int StackSize;
}Stack;
Status InitStack(Stack &S); //初始化栈
Status push(Stack &S,char ch); //往栈中压入元素
Status Pop(Stack &S); //弹出元素
Status GetTop(Stack &S,char &temp); //获取栈顶元素
void Right(char ch); //检查是否配对
int main()
{
Stack S;
InitStack(S);
char a[110];
int flag = 1;
while (cin>>a)
{
if (a[0] == '.') break;
int len = strlen(a);
for (int i=0;i<len;i++)
{
if (a[i] == '(' || a[i] == '[' || a[i] == '{')
push(S,a[i]);
else if (a[i] == '/' && a[i+1] == '*' && i+1<len) //特殊处理有两个字符出现的/**/,使用@代替
{
i++;
push(S,'@');
}
else if (a[i] == ')')
{
if(S.top!=S.base) //栈不为空
{
char temp;
GetTop(S,temp);
if(temp == '(') Pop(S); //符号匹配,出栈
else if(flag) //符号不匹配
{
cout<<"NO"<<endl;
flag = 0;
Right(temp);
}
}
else if(flag) //栈空并且从未输出的情况,缺少左符号
{
cout<<"NO"<<endl;
flag = 0;
cout<<"?-)"<<endl;
}
}
else if (a[i] == ']')
{
if(S.top != S.base)//如果栈不空
{
char temp;
GetTop(S,temp);
if(temp == '[') Pop(S);
else if(flag)
{
cout<<"NO"<<endl;
flag = 0;
Right(temp);
}
}
else if(flag)
{
cout<<"NO"<<endl;
flag = 0;
cout<<"?-]"<<endl;
}
}
else if (a[i] == '}')
{
if(S.top!=S.base)//如果栈不空
{
char temp;
GetTop(S,temp);
if(temp == '{') Pop(S);
else if(flag)
{
cout<<"NO"<<endl;
flag = 0;
Right(temp);
}
}
else if(flag)
{
cout<<"NO"<<endl;
flag = 0;
cout<<"?-}"<<endl;
}
}
else if(a[i]=='*' && a[i+1]=='/' && i+1<len)
{
i++;
if(S.top!=S.base)
{
char temp;
GetTop(S,temp);
if(temp == '@')
Pop(S);
else if(flag)
{
cout<<"NO"<<endl;
flag=0;
Right(temp);
}
}
else if(flag)
{
cout<<"NO"<<endl;
flag=0;
cout<<"?-*/"<<endl;
}
}
}
}
if(flag) //从未有过输出符号的情况
{
if(S.base == S.top) //没出现过符号或者符号都出栈,匹配成功
cout<<"YES"<<endl;
else //有剩余符号
{
char temp;
GetTop(S,temp);
cout<<"NO"<<endl;
Right(temp);
}
}
}
Status InitStack(Stack &S)
{
S.base = (char *)malloc(STACK_INIT_SIZE * sizeof(char));
if (!S.base) exit(OVERFLOW);
S.top = S.base;
S.StackSize = STACK_INIT_SIZE;
return OK;
}
Status push(Stack &S,char ch)
{
if (S.top == S.base + STACK_INIT_SIZE)
{
S.base = (char*)realloc(S.base,(STACK_INIT_SIZE + STACK_ADDSIZE) * sizeof(char));
if (!S.base) exit(OVERFLOW);
S.top = S.base + S.StackSize;
S.StackSize += STACK_ADDSIZE;
return OK;
}
*S.top = ch;
S.top++;
return OK;
}
Status Pop(Stack &S)
{
if (S.base == S.top) return ERROR;
S.top--;
return OK;
}
Status GetTop(Stack &S,char &temp)
{
if (S.top == S.base)
return ERROR;
temp = *(S.top - 1);
return OK;
}
void Right(char ch)
{
if(ch == '(')
cout<<"(-?"<<endl;
else if(ch == '[')
cout<<"[-?"<<endl;
else if(ch == '{')
cout<<"{-?"<<endl;
else if(ch == '@')//用@代替/*
cout<<"/*-?"<<endl;
}
/*
补充:(1)注意GetTop()函数中temp用于带回值,必须加上引用
(2)比较特殊的是注释符号,这也决定了字符的输入先用数组存起来才能判断下一位是否为*,然后用@代替整体的注释符
(3)缺少左右符号时第一位还得输出?-或者-?,所以需要用到标记变量判断是否是第一次或者最后一次输出
(4)缺少右符号的情况就是栈中有元素但是与当前元素不匹配,缺少左符号是栈为空,但此时还有符号等待匹配
*/
8X8-1 は指数関数を再帰的に実装します
この質問では、xn (n≥1) を計算する関数の実装が必要です。
関数インターフェースの定義:
double calc_pow( double x, int n );
関数 calc_pow は、x の n 乗値を返す必要があります。再帰を使用することをお勧めします。この質問は、結果が倍精度の範囲内にあることを保証します。
審判テスト手順の例:
#include <stdio.h>
double calc_pow( double x, int n );
int main()
{
double x;
int n;
scanf("%lf %d", &x, &n);
printf("%.0f\n", calc_pow(x, n));
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
2 3
出力サンプル:
8
コード:
double calc_pow( double x, int n )
{
if (n == 1) return x;
else return x * calc_pow(x,n-1);
}
8X8-2 はアッカーメン関数を再帰的に計算します
この質問では、アッカーメン関数の計算が必要です。その関数は次のように定義されます。
関数インターフェースの定義:
int Ack( int m, int n );
ここで、m と n はユーザーによって渡された負ではない整数です。関数 Ack は、Ackermenn 関数の対応する値を返します。この質問により、入力と出力の両方が長整数型であることが保証されます。
範囲内です。
審判テスト手順の例:
#include <stdio.h>
int Ack( int m, int n );
int main()
{
int m, n;
scanf("%d %d", &m, &n);
printf("%d\n", Ack(m, n));
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
2 3
出力サンプル:
9
コード:
int Ack( int m, int n )
{
if (m == 0) return n+1;
else if(n == 0 && m>0) return Ack(m-1,1);
else if (m>0 && n>0) return Ack(m-1,Ack(m,n-1));
}
8X8-3 は再帰的にファボナッチ数列を見つけます
この質問では、ファボナッチ数列の項を見つける関数の実装が必要です。ファボナッチ数列の定義は次のとおりです。
f(n)=f(n−2)+f(n−1) (n≥2),其中f(0)=0,f(1)=1。
関数インターフェースの定義:
int f( int n );
関数 f は n 番目のファボナッチ数を返す必要があります。この質問により、入力と出力が長整数の範囲内にあることが保証されます。再帰を使用することをお勧めします。
審判テスト手順の例:
#include <stdio.h>
int f( int n );
int main()
{
int n;
scanf("%d", &n);
printf("%d\n", f(n));
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
6
出力サンプル:
8
コード:
int f( int n )
{
if (n == 0) return 0;
else if (n == 1) return 1;
else return f(n-1) + f(n-2);
}
8X8-4 10 進数から 2 進数への変換
この質問では、正の整数 n をバイナリに変換して出力する関数の実装が必要です。
関数インターフェースの定義:
void dectobin( int n );
関数 dectobin は、バイナリ n を 1 行に出力する必要があります。再帰を使用することをお勧めします。
審判テスト手順の例:
#include <stdio.h>
void dectobin( int n );
int main()
{
int n;
scanf("%d", &n);
dectobin(n);
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
10
出力サンプル:
1010
コード:
void dectobin( int n )
{
if (n == 0 || n == 1) printf("%d",n);
else
{
dectobin(n/2);
printf("%d",n%2);
}
}
8X8-5 は P 関数を再帰的に計算します
この質問では、関数 P(n,x) を計算する必要があります。関数の定義は次のとおりです。
関数インターフェースの定義:
double P( int n, double x );
ここで、n はユーザーによって渡された非負の整数、x は倍精度浮動小数点数です。関数 P は、P(n,x) 関数の対応する値を返します。この質問により、入力と出力が倍精度の範囲内にあることが保証されます。
審判テスト手順の例:
#include <stdio.h>
double P( int n, double x );
int main()
{
int n;
double x;
scanf("%d %lf", &n, &x);
printf("%.2f\n", P(n,x));
return 0;
}
/* 你的代码将被嵌在这里 */
入力例:
10 1.7
出力サンプル:
3.05
コード:
double P( int n, double x )
{
if (n == 0) return 1;
else if (n == 1) return x;
else return ((2*n-1)*P(n-1,x) - (n-1)*P(n-2,x))/n;
}
8X8-6 整数はいくつかの項の合計に分解されます
正の整数 N をいくつかの正の整数に分解し、それらを加算するには、7=6+1、7=5+2、7=5+1+1、... など、多くの分解方法があります。正の整数 N のすべての整数分解式を求めるプログラム。
入力形式:
各入力には、正の整数 N (0<N≤30) であるテスト ケースが含まれています。
出力フォーマット:
N のすべての整数分解を昇順に出力します。昇順は次のことを意味します: 2 つの分解シーケンス N 1 ={n 1 ,n 2 ,⋯} および N 2 ={m 1 ,m 2 ,⋯}、n 1 =m 1 、⋯,ni i =mi i 、ただし ni i+1 <mi i+1 となるような i がある場合の場合、N 1 シーケンスは N 2 シーケンスの前に出力する必要があります。各式は最小から最大の順に追加され、式はセミコロンで区切られ、4 つの式の後に新しい行が出力されます。
入力例:
7
出力サンプル:
7=1+1+1+1+1+1+1;7=1+1+1+1+1+2;7=1+1+1+1+3;7=1+1+1+2+2
7=1+1+1+4;7=1+1+2+3;7=1+1+5;7=1+2+2+2
7=1+2+4;7=1+3+3;7=1+6;7=2+2+3
7=2+5;7=3+4;7=7
コード:
/*
思路:如果n等于0,直接输出等号以及前边部分
如果n不等于0,依次递增分解输出,并且输出长度未分解的时候最小,越分解长度越大
*/
#include <bits/stdc++.h>
using namespace std;
int Num[35]; //存储分解的值
int N; //将最初输入的值保存下来以便等号前边的输出
int flag = 0; //控制换行符的输出
int k = 1; //用于控制初始不变的输出分解值
void Print(int len)
{
for (int i=0;i<len;i++)
{
if (i==0) printf("%d",Num[i]);
else printf("+%d",Num[i]);
}
}
int Decompose(int n,int len)
{
//递归边界
if (n<=0)
{
if (flag == 4) //每四个式子输出一个换行符
{
printf("\n");
flag = 0;
}
flag++;
if (flag == 1) //控制分号的输出
{
printf("%d=",N);
Print(len);
}
else
{
printf(";%d=",N);
Print(len);
}
return 0;
}
//递归条件
for (int i=1;i<=n;i++)
{
if (i>=k)
{
Num[len] = i;
k = i;
Decompose(n-i,len+1);
k = i; //回归到前边应该输出的数字
}
}
}
int main()
{
int n;
scanf("%d",&n);
N = n; //用于记录初始值
Decompose(n,0);
return 0;
}
8X8-7出力フル配置
最初の n 個の正の整数 (n < 10) の完全な配列を出力するプログラムを作成し、9 つのテスト ケース (つまり、n が 1 から 9) を通じて n が徐々に増加するときのプログラムの実行時間を観察してください。
入力形式:
入力は正の整数 n (<10) として与えられます。
出力フォーマット:
1 から n までのすべての順列を出力します。各順列は 1 行を占め、数値の間にスペースはありません。配列の出力順序は辞書順です。つまり、シーケンス a 1 ,a 2 ,⋯,an n は、シーケンス b 1 ,b 2 にランク付けされます。 ,⋯,bn bk+1 。
入力例:
3
出力サンプル:
123
132
213
231
312
321
コード:
/*
思路:(1)把n之前的所有数字存入一个数组。
(2)从第一个数字开始,以第一个数字为首元素一共排列n个数字
(3)以第一个数字为首排列完成后,将第一个数字和第二个数字交换,重复(2)的操作
(4)以此类推,直到为首的数字是最后一个数字
注意:排列的输出顺序为字典顺序
*/
#include <bits/stdc++.h>
using namespace std;
int a[15];
void Swap(int &m,int &n)
{
int temp;
temp = m;
m = n;
n = temp;
}
//用于排列数组顺序使其按照字典序输出
void Sort(int a[],int start,int end)
{
for (int i=start;i<=end;i++)
{
for (int j = i;j<=end;j++)
{
if (a[i]>a[j])
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
}
void Array(int a[],int start,int n)
{
if (start == n)
{
for (int i=1;i<=n;i++)
printf("%d",a[i]);
printf("\n");
}
else
{
for (int i=start;i<=n;i++)
{
Sort(a,start,n);
Swap(a[start],a[i]); //为首的数字进行交换
Array(a,start+1,n);
Swap(a[start],a[i]); //进行下一个全排列的时候将上一次交换的数字归位
}
}
}
int main()
{
int n;
cin>>n;
for (int i = 1;i<=n;i++)
a[i] = i;
Array(a,1,n);
}
8X8-8 接頭辞式の値を検索します
算術式には、前置表記、中置表記、および後置表記の形式があります。接頭辞式は、二項演算子が 2 つのオペランドの前に配置されることを意味します。たとえば、2+3*(7-4)+8/4 の接頭辞式は、+ + 2 * 3 - 7 4 / 8 4 となります。接頭辞式の結果値を計算するプログラムを設計してください。
入力形式:
+、-、*、/およびオペランドのみを含む1行30文字以内のプレフィックス式を入力します。異なるオブジェクト(オペランド、演算記号)はスペースで区切られます。
出力フォーマット:
前置式の演算結果を小数点以下1桁残して出力するか、エラーメッセージERRORを出力します。
入力例:
+ + 2 * 3 - 7 4 / 8 4
出力サンプル:
13.0
コード:
/*
思路:只要字符串中是数字字符,就把字符转化成数字;
只要遇见运算符就按照运算规则进行运算;
只要有两个及以上的运算符,先把第一个数字运算上后边整个剩下字符串,直至只有一个数字
注意:(1)运算出来的结构是保留一位小数的double型;
(2)分母为零的情况返回ERROR,并且直接退出程序
(3)判断数字前边是否带有正负号
*/
#include <bits/stdc++.h>
using namespace std;
double Prefix()
{
char str[30];
scanf("%s",str);
if (!str[1]) //判断数字前边是否有符号
{
if (str[0] == '+')
return Prefix() + Prefix();
else if (str[0] == '-')
return Prefix() - Prefix();
else if (str[0] == '*')
return Prefix() * Prefix();
else if (str[0] == '/')
{
double mol = Prefix();
double den = Prefix();
if (den != 0) return mol / den;
else
{
printf("ERROR");
exit(0); //不能用return 0代替,exit(0)强制退出程序
}
}
else return atof(str); //应当将数字字符直接转化成浮点数,不能用str[0]-'0'
}
else //数字前边有符号的情况
{
if (str[0] == '-' || str[0] == '+')
{
char flag = str[0]; //先把数字符号记录下来,然后依次用后边的覆盖前边字符
int i = 0;
while (str[i])
{
str[i] = str[i+1];
i++;
}
if (flag == '-') return 0 - atof(str);
else return atof(str);
}
else return atof(str);
}
}
int main()
{
printf("%.1f",Prefix());
return 0;
}
9X9-1銀行業務キューの簡単なシミュレーション
銀行に A と B の 2 つの営業窓口があり、処理速度が異なるとします。窓口 A の処理速度は窓口 B の処理速度の 2 倍です。つまり、窓口 A が 2 人の顧客の処理を完了するとき、窓口 B は 1 人の顧客の処理を完了します。お客様。銀行に到着する顧客の順序を考慮して、業務が完了した順序で顧客の順序を出力してください。次々に来店する顧客の時間間隔は考慮せず、異なる窓口で同時に2人の顧客を処理した場合、窓口Aの顧客が先に出力されるものとする。
入力形式:
入力は正の整数の行で、最初の数値 N (≤1000) は顧客の総数で、その後に N 顧客の数が続きます。奇数番号のお客様はA窓口へ、偶数番号のお客様はB窓口へご対応ください。数字はスペースで区切ります。
出力フォーマット:
業務処理が完了した順に顧客番号を出力します。数字はスペースで区切る必要がありますが、最後の数字の後に余分なスペースを入れないでください。
入力例:
8 2 1 3 9 4 11 13 15
出力サンプル:
1 3 2 9 11 4 13 15
コード:
/*
思路:先把所有输入的数据按照奇偶数分别插入到两个队列里,并分别计数。然后循环删除队列元素,A队列每删除一个,B队列删除两个,并且计数器对应相减,直到一方为0
注意:两边窗口有特殊人数需要特殊处理
(1)A有两人以上 :一般处理
(2)A只有一人 :A出一个,B出一个
(3)有一边窗口没有人 :直接让一边的队列元素出队即可
*/
#include <bits/stdc++.h>
using namespace std;
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
typedef int Status;
typedef int Elemtype;
typedef struct QNode
{
Elemtype data;
struct QNode *next;
} QNode, *QueuePtr;
typedef struct
{
QueuePtr front;
QueuePtr rear;
} LinkQueue;
Status InitLinkQueue(LinkQueue &Q); //初始化队列
Status InsetLinkQueue(LinkQueue &Q,Elemtype n); //向队列中插入元素
Status DeleteLinkQueue(LinkQueue &Q,Elemtype &e);//删除队列元素,同时带回(注意引用)
int main()
{
LinkQueue A;
LinkQueue B;
InitLinkQueue(A);
InitLinkQueue(B);
int n,number;
int flag = 0; //控制输出格式
int countA = 0,countB = 0;
cin>>n;
for (int i = 0;i<n;i++) //将所有编号存起来
{
cin>>number;
if (number % 2 == 0) //奇数在A,偶数在B
{ InsetLinkQueue(B,number); countB++;}
else { InsetLinkQueue(A,number); countA++;}
}
while (countA && countB) //当两边窗口都有人的时候
{
int a,b,c;
if (countA >= 2 && countB >= 1)
{
DeleteLinkQueue(A,a); //根据题目窗口处理效率出队
DeleteLinkQueue(A,b);
DeleteLinkQueue(B,c);
countA -= 2;
countB--;
if (!flag) {cout<<a<<" "<<b<<" "<<c;flag = 1;}
else {cout<<" "<<a<<" "<<b<<" "<<c;}
}
else if (countA == 1 && countB >= 1) //特殊:A窗口不足两个人,所以只能A出一个,B出一个
{
DeleteLinkQueue(A,a);
DeleteLinkQueue(B,b);
countA--;
countB--;
if (!flag) {cout<<a<<" "<<b;flag = 1;}
else {cout<<" "<<a<<" "<<b;}
}
}
while (countA) //只有A窗口有人
{
int a;
DeleteLinkQueue(A,a);
countA--;
if (!flag) {cout<<a;flag = 1;}
else {cout<<" "<<a;}
}
while (countB) //只有B窗口有人
{
int a;
DeleteLinkQueue(B,a);
countB--;
if (!flag) {cout<<a;flag = 1;}
else {cout<<" "<<a;}
}
}
Status InitLinkQueue(LinkQueue &Q)
{
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
if (!Q.front) exit(OVERFLOW);
Q.front->next = NULL; //注意!!!
return OK;
}
Status InsetLinkQueue(LinkQueue &Q,Elemtype n)
{
QueuePtr p;
p = (QNode *)malloc(sizeof(QNode));
if (!p) exit(OVERFLOW);
p->data = n;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}
Status DeleteLinkQueue(LinkQueue &Q,Elemtype &e)
{
if (Q.front == Q.rear) return ERROR;
QueuePtr p = Q.front->next; //队列是先进先出,所以要指向队头
e = p->data;
Q.front->next = p->next;
if (Q.rear == p) Q.rear = Q.front;
free(p);
return OK;
}
11X11-1 バイナリ ツリーの深さと葉の数を求める
バイナリ ツリーの深さとリーフ ノードの数を計算する関数を作成します。バイナリ ツリーはバイナリ リンク リスト記憶構造を使用します
。関数インターフェイスの定義:
int GetDepthOfBiTree ( BiTree T);
int LeafCount(BiTree T);
ここで、T はユーザーによって渡されるパラメータで、バイナリ ツリーのルート ノードのアドレスを示します。この関数はバイナリ ツリーの深さ (高さとも呼ばれます) を返します。
審判テスト手順の例:
//头文件包含
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define INFEASIBLE -2
#define NULL 0
typedef int Status;
//二叉链表存储结构定义
typedef int TElemType;
typedef struct BiTNode{
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
//创建二叉树各结点,输入零代表创建空树
//采用递归的思想创建
//递归边界:空树如何创建呢:直接输入0;
//递归关系:非空树的创建问题,可以归结为先创建根节点,输入其数据域值;再创建左子树;最后创建右子树。左右子树递归即可完成创建!
Status CreateBiTree(BiTree &T){
TElemType e;
scanf("%d",&e);
if(e==0)T=NULL;
else{
T=(BiTree)malloc(sizeof(BiTNode));
if(!T)exit(OVERFLOW);
T->data=e;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
return OK;
}
//下面是需要实现的函数的声明
int GetDepthOfBiTree ( BiTree T);
int LeafCount(BiTree T);
//下面是主函数
int main()
{
BiTree T;
int depth, numberOfLeaves;
CreateBiTree(T);
depth= GetDepthOfBiTree(T);
numberOfLeaves=LeafCount(T);
printf("%d %d\n",depth,numberOfLeaves);
}
/* 请在这里填写答案 */
入力例:
1 3 0 0 5 7 0 0 0
出力サンプル:
3 2
コード:
//求树的深度
int GetDepthOfBiTree ( BiTree T)
{
if (T == NULL) return 0;
int depth1 = GetDepthOfBiTree(T->lchild);
int depth2 = GetDepthOfBiTree(T->rchild);
if (depth1>depth2) return depth1 + 1;
else return depth2 + 1;
}
//求叶子节点数
int LeafCount(BiTree T)
{
if (T == NULL) return 0;
if (T->lchild == NULL && T->rchild == NULL)
return 1;
else return LeafCount(T->lchild) + LeafCount(T->rchild);
}
11X11-2 バイナリ ツリーのノード数を求める
バイナリ ツリー内のノードの数をカウントする関数を作成します。バイナリ ツリーは、バイナリ リンク リスト記憶構造を使用します。
関数インターフェースの定義:
int NodeCountOfBiTree ( BiTree T);
ここで、T はバイナリ ツリーのルート ノードのアドレスです。
審判テスト手順の例:
//头文件包含
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define INFEASIBLE -2
typedef int Status;
//二叉链表存储结构定义
typedef int TElemType;
typedef struct BiTNode{
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
//创建二叉树各结点,输入0代表创建空树。
//采用递归的思想创建
//递归边界:空树如何创建呢:直接输入0;
//递归关系:非空树的创建问题,可以归结为先创建根节点,输入其数据域值;再创建左子树;最后创建右子树。左右子树递归即可完成创建!
Status CreateBiTree(BiTree &T){
TElemType e;
scanf("%d",&e);
if(e==0)T=NULL;
else{
T=(BiTree)malloc(sizeof(BiTNode));
if(!T)exit(OVERFLOW);
T->data=e;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
return OK;
}
//下面是需要实现的函数的声明
int NodeCountOfBiTree ( BiTree T);
//下面是主函数
int main()
{
BiTree T;
int n;
CreateBiTree(T); //先序递归创建二叉树
n= NodeCountOfBiTree(T);
printf("%d",n);
return 0;
}
/* 请在这里填写答案 */
入力例 (0 を入力すると空のサブツリーを表すことに注意してください):
1 3 0 0 5 3 0 0 0
出力サンプル:
4
コード:
int NodeCountOfBiTree ( BiTree T)
{
if (T == NULL) return 0;
else return NodeCountOfBiTree(T->lchild) + NodeCountOfBiTree(T->rchild) + 1;
}
12X12-1 は、事後および順序内トラバーサルに基づいて事前順序トラバーサルを出力します。
この質問では、指定されたバイナリ ツリーの事後探索結果と順序内探索結果に基づいて、事前順序探索結果を出力する必要があります。
入力形式:
最初の行は、ツリー内のノードの数を表す正の整数 N (≤30) を示します。次の 2 行はそれぞれ、ポストオーダー トラバーサルとインオーダー トラバーサルの結果に対応する N 個の整数を示します。数値はスペースで区切られています。この質問により、入力がバイナリ ツリーに正しく対応することが保証されます。
出力フォーマット:
出力 Preorder: およびツリーの事前順序走査の結果を 1 行に表示します。数字の間にはスペースを 1 つ入れ、行末に余分なスペースを入れないでください。
入力例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
出力サンプル:
Preorder: 4 1 3 2 6 5 7
コード:
/*
思路:使用递归方法,只要得出根节点、左子树和右子树即可
递归边界:输入的个数N<=0的时候返回
递归关系:先找到后序遍历数组中的最后一位在中序遍历中的位置,这就是根节点,根节点的左侧是左子树,右侧是右子树
然后按照递归的思想,继续分别构造左子树和右子树的根节点、左子树和右子树
*/
//头文件包含
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
//函数状态码定义
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define INFEASIBLE -2
typedef int Status;
typedef int TElemType;
typedef struct BiNode
{
TElemType data;
struct BiNode *lchild, *rchild;
}BiNode, *BiTree;
BiTree Create(int *Post,int *In,int N)
{
//递归边界
if (N <= 0) return NULL;
//递归关系
int *p = In; //定义一个指针用来遍历中序序列
while (*p != *(Post + N -1))
p++; //找到后序序列的最后一位,即根节点
BiTree T;
T = (BiTree)malloc(sizeof(BiNode));
T->data = *p;
int len = p - In; //找到根节点位置左边有几位数字,即左子树
T->lchild = Create(Post,In,len);
T->rchild = Create(Post + len,p + 1,N - len -1);
return T;
}
void Print(BiTree T)
{
if (T)
{
printf(" %d",T->data);
Print(T->lchild);
Print(T->rchild);
}
return ;
}
int main()
{
int N;
int *Post, *In;
scanf("%d",&N);
Post = (int*)malloc(N * sizeof(int));
In = (int*)malloc(N * sizeof(int));
for (int i=0; i<N; i++)
scanf("%d",&Post[i]);
for (int i=0; i<N; i++)
scanf("%d",&In[i]);
BiTree T = Create(Post,In,N);
printf("Preorder:");
Print(T);
free(Post);
free(In);
return 0;
}
13X13-1 家系図処理
人類学の研究は家族に非常に興味を持っているため、研究者たちは研究のためにいくつかの家族の系図を収集しました。実験では、家系図の処理にコンピューターが使用されました。これを達成するために、研究者らは家系図をテキスト ファイルに変換しました。以下は家系図テキスト ファイルの例です。
John
Robert
Frank
Andrew
Nancy
David
家系図のテキスト ファイルでは、各行に個人の名前が含まれます。最初の行の名前は、家族の最も古い祖先です。家系図には最も古い先祖の子孫のみが含まれ、その夫や妻は家系図には表示されません。各人の子は、親よりも 2 スペース多くインデントされます。上記の家系図テキスト ファイルを例にとると、家族の最も古い先祖であるジョンにはロバートとナンシーという 2 人の子供がいます。ロバートにはフランクとアンドリューという 2 人の子供がいますが、ナンシーにはデビッドという 1 人の子供しかいません。
実験では、研究者らは家族文書も収集し、家系図の中の2人の関係についての記述を抽出した。以下は、家系図内の関係に関する宣言的ステートメントの例です。
John is the parent of Robert
Robert is a sibling of Nancy
David is a descendant of Robert
研究者は各発言の真偽を判断する必要があるので、研究者が判断できるようにプログラムを書いてください。
入力形式:
入力では、まず 2 つの正の整数 N (2≤N≤100) と M (≤100) が与えられます。ここで、N は家系図内の名前の数、M は家系図内のステートメントの数です。各入力行は次のようになります。 70文字を超えないでください。
名前の文字列は 10 文字以内の英字で構成されます。家系図の最初の行にある名前の前にインデントされたスペースはありません。家系図内の他の名前は、少なくとも 2 つのスペースでインデントされます。つまり、それらは家系図内の最も古い祖先 (最初の行に指定されている名前) の子孫であり、家系図内の名前が k 個のスペースでインデントされている場合は、前の場合、次の行の名前は最大でも k+2 個のスペースでインデントする必要があります。
家系図に同じ名前が 2 回表示されることはなく、家系図に表示されない名前は明細書に表示されません。各ステートメントの形式は次のとおりです。ここで、X と Y は家系図内の異なる名前です。
X is a child of Y
X is the parent of Y
X is a sibling of Y
X is a descendant of Y
X is an ancestor of Y
出力フォーマット:
テスト ケース内の各ステートメントについて、ステートメントが true の場合は True を、ステートメントが false の場合は False を 1 行に出力します。
入力例:
6 5
John
Robert
Frank
Andrew
Nancy
David
Robert is a child of John
Robert is an ancestor of Andrew
Robert is a sibling of Nancy
Nancy is the parent of Frank
John is a descendant of Andrew
出力サンプル:
True
True
True
False
False
コード:
#include <bits/stdc++.h>
using namespace std;
struct people
{
char name[15]; //结点名字
char father[15]; //双亲名字
int num; //空格数
}People[101];
void Gets(char temp[])
{
int i = 0;
scanf("%c",&temp[0]);
while (temp[i] != '\n')
{i++;scanf("%c",&temp[i]);}
temp[i] = '\0';
}
int main()
{
int N; //家谱中名字的数量
int M; //判断家谱关系的语句
char temp[75]; //用来临时存储输入的名字和空格,注意名字不超过10个字符,但是还有空格,要把数组开大一点
scanf("%d %d",&N,&M);
getchar(); //注意接下来输入的是字符串,要用getchar把回车吃掉
for (int i = 0; i < N; i++)
{
memset(temp,'0',sizeof(temp));
People[i].num = 0; //先把家谱数组中所有的名字初始化
Gets(temp);
int L = strlen(temp);
for (int j = 0; j < L; j++)
{
if (temp[j] == ' ')
People[i].num++; //记录空格的个数,以便于判断家族关系
else
{
strcpy(People[i].name, temp + j); //把空格之后的名字复制下来
break;
}
}
if (!People[i].num)
strcpy(People[i].father, "root"); //空格数为0则表示根
else
{
for (int k = i-1; k >= 0; k--) //从后往前寻找父节点
{
if (People[i].num > People[k].num)
{
strcpy(People[i].father,People[k].name);
break;
}
}
}
}
char a[15], b[15], c[15], d[15]; //用来存储输入判断语句,a和c分别对应前后两个人名,b表示等待判断的关系
char temp1[15], temp2[15];
for (int i = 0; i < M; i++)
{
scanf("%s %s %s %s %s %s",a,d,d,b,d,c);
if (b[0] == 'c')
{
//X是Y的孩子
for (int k = 0; k < N; k++)
{
if (!strcmp(People[k].name,a)) //首先在数组中找到a,然后判断c是否与a的father一致
{
if (!strcmp(People[k].father,c))
printf("True\n");
else printf("False\n");
break;
}
}
}
else if (b[0] == 'p')
{
//X是Y的双亲
for (int k = 0; k < N; k++)
{
if (!strcmp(People[k].name,c))
{
if (!strcmp(People[k].father,a))
printf("True\n");
else printf("False\n");
break;
}
}
}
else if (b[0] == 's')
{
//X是Y的兄弟
for (int k = 0; k < N; k++)
{
//寻找两个结点的父节点
if (!strcmp(People[k].name,a))
strcpy(temp1,People[k].father);
if (!strcmp(People[k].name,c))
strcpy(temp2,People[k].father);
}
if (!strcmp(temp1,temp2)) printf("True\n");
else printf("False\n");
}
else if (b[0] == 'd')
{
//X是Y的子孙
for (int k = 0; k < N; k++)
{
if (!strcmp(People[k].name,a))
strcpy(temp1,People[k].father);
}
while (strcmp(temp1,c) && strcmp(temp1,"root"))
{
for (int k = 0; k < N; k++)
{
if (!strcmp(People[k].name,temp1))
strcpy(temp1,People[k].father);
}
}
if (!strcmp(temp1,"root"))
printf("False\n");
else printf("True\n");
}
else if (b[0] == 'a')
{
//X是Y的祖先
for (int k = 0; k < N; k++ )
{
if (!strcmp(People[k].name,c))
strcpy(temp1,People[k].father);
}
while (strcmp(temp1,a) && strcmp(temp1,"root"))
{
for (int k = 0; k < N; k++)
{
if (!strcmp(People[k].name,temp1))
strcpy(temp1,People[k].father);
}
}
if (!strcmp(temp1,"root"))
printf("False\n");
else printf("True\n");
}
}
getchar();
return 0;
}
14X14-1 ハフマンエンコーディング
与えられたテキストに対して、文字の出現頻度をカウントすると、ハフマン アルゴリズムに基づいて一連のコードが得られるため、このコードを使用して元のテキストを圧縮すると、合計のコード長が最短になります。ただし、ハフマン符号化は独自のものではありません。たとえば、文字列「aaaxuaxz」の場合、4、2、1、および 1 に対応する文字「a」、「x」、「u」、および「z」の出現頻度を取得するのは簡単です。エンコーディング {'a'=0, 'x'=10, 'u'=110, 'z'=111} を設計することも、別のセットの {'a'=1, 'x'=01, ' を使用することもできます。 u'=001, 'z'=000}、{'a'=0, 'x'=11, 'u'=100, 'z'=101} も使用できます。3 つのエンコード セットはすべて、元のテキストを 14 バイトにします。ただし、{'a'=0, 'x'=01, 'u'=011, 'z'=001} はハフマン エンコーディングではありません。このエンコーディングを使用して 00001011001001 を圧縮した後のデコード結果は一意ではないからです。"両方"デコード結果としては、「aaaxuaxz」と「aazuaxax」が対応できる。この質問では、コードのセットがハフマン コードであるかどうかを判断するように求められます。
入力形式:
まず、最初の行では正の整数 N (2≤N≤63) が与えられ、次に 2 行目では N 個の非繰り返し文字とその出現頻度が与えられます。形式は次のとおりです。
c[1] f[1] c[2] f[2] ... c[N] f[N]
ここで、c[i] はセット {'0' - '9', 'a' - 'z', 'A' - 'Z', '_'} 内の文字、f[i] は c の文字です[i] 出現頻度は 1000 を超えない整数です。次の行では、正の整数 M (≤1000) が指定され、その後にチェックされるコードの M セットが続きます。コードの各セットは N 行を占め、形式は次のとおりです。
c[i] コード[i]
ここで、c[i] は i 番目の文字、code[i] は 63 個以下の 0 と 1 からなる空ではない文字列です。
出力フォーマット:
チェック対象のコードごとに、正しいハフマンコードであれば「Yes」を1行で出力し、それ以外の場合は「No」を出力します。
注: 最適なエンコーディングは、必ずしもハフマン アルゴリズムを通じて得られるわけではありません。最適な長さに圧縮されるプレフィックス エンコーディングは正しいと見なされます。
入力例:
7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11
出力サンプル:
Yes
Yes
No
No
コード:
/*
思路:对于给定的字符及其出现的频率,先构建对应霍夫曼树,然后求出对应霍夫曼编码的最大路径长度。
判断是否是正确的霍夫曼编码只要满足前缀规则,并且每一个字符的最大路径长度与最先构建的霍夫曼编码所求出来的长度相等即可。
*/
#include <bits/stdc++.h>
using namespace std;
typedef int Status;
typedef struct HTNode
{
unsigned int weight;
unsigned int parent, lchild, rchild;
} HTNode, *HuffmanTree;
typedef char* *HuffmanCode;
void Select(HuffmanTree &HT, int index, int &s1, int &s2) //在HT数组前index个中选择parent为0,并且权值最小的两个节点,其序号用s1,s2带回
{
int minvalue1, minvalue2;
s1 = s2 = index;
minvalue1 = minvalue2 = 100000; //将最小值设置成无穷大,方便以后比较替换
for(int i = 1; i < index; ++i)
{
if(HT[i].parent == 0)
{
if(HT[i].weight <= minvalue1)
{
minvalue2 = minvalue1;
minvalue1 = HT[i].weight;
s2 = s1;
s1 = i;
}
else if(HT[i].weight <= minvalue2)
{
s2 = i;
minvalue2 = HT[i].weight;
}
}
}
}
int HuffmanCoding(int *w, int n) //已知权值和总数量,构造霍夫曼树,求出编码,并且返回最短路径长度
{
int m = 2 * n - 1;
HuffmanTree HT = (HTNode *)malloc(sizeof(HTNode) * (m + 1));
HuffmanTree p = HT + 1;
w++;
//初始化霍夫曼树
for(int i = 1; i <= n; ++i, ++w, ++p)
{
p->weight = *w;
p->parent = p->lchild = p->rchild = 0;
}
for(int i = n + 1; i <= m; ++i, ++p)
p->weight = p->parent = p->lchild = p->rchild = 0;
p = HT + n + 1;
for(int i = n + 1; i <= m; ++i, ++p)
{
int s1, s2;
Select(HT, i, s1, s2);
p->weight = HT[s1].weight + HT[s2].weight;
p->lchild = s1, p->rchild = s2;
HT[s1].parent = HT[s2].parent = i;
}
int pathnum[n + 1]; //求出每个字符的最大路径长度
for(int i = 1; i <= n; ++i)
{
int length = 0;
for(int cpos = i, ppos = HT[i].parent; ppos != 0; cpos = ppos, ppos = HT[ppos].parent)
length++;
pathnum[i] = length;
}
int min_length = 0;
for(int i = 1; i <= n; i++)
min_length += (pathnum[i] * HT[i].weight);
return min_length;
}
int isUncertain(char Codes[][65], int n) //判断是否符合前缀规则
{
for(int i = 0; i < n; ++i)
for(int j = i + 1; j < n; ++j)
{
int length = strlen(Codes[i]) > strlen(Codes[j]) ? strlen(Codes[j]):strlen(Codes[i]);
int k;
for(k = 0; k < length; ++k)
if(Codes[i][k] != Codes[j][k])
break;
if(k == length)
return 1;
}
return 0;
}
int GetLen(char Codes[][65], int *w, int n)
{
int len = 0;
for(int i = 0; i < n; ++i)
{
int length = strlen(Codes[i]);
len += (length * w[i + 1]);
}
return len;
}
int main()
{
int N, M, W[70];
char ch;
scanf("%d", &N);
getchar();
for(int i =1; i <= N; ++i) //输入字符以及出现的频率,注意空格也是一个字符,在末尾特殊处理
{
if(i <= N - 1)
scanf("%c %d ", &ch, &W[i]);
else
scanf("%c %d", &ch, &W[i]);
}
int min_length = HuffmanCoding(W, N);
scanf("%d", &M);
for(int i = 0; i < M; ++i)
{
char Codes[65][65]; //用来存放等待判断的编码
for(int i = 0; i < N; ++i)
{
getchar(); //吃掉每一行的回车
scanf("%c %s", &ch, Codes[i]);
}
if(isUncertain(Codes, N)) //
printf("No\n");
else
{
if(min_length == GetLen(Codes, W, N))
printf("Yes\n");
else
printf("No\n");
}
}
}
15X15-1 隣接リストは無向グラフを作成します
隣接リストを使用して無向グラフ G を作成し、各頂点の次数を順番に出力します。
入力形式:
入力の最初の行は、2 つの整数 i (0<i≤10) と j (j≥0) を与えます。これらはそれぞれ、グラフ G の頂点とエッジの数です。2 行目に頂点情報を入力します。各頂点は 1 文字でのみ表現できます。j 行を順番に入力し、各行のエッジに接続される頂点を入力します。
出力フォーマット:
行末に最後のスペースを入れずに、各頂点の次数を順番に出力します。
入力例:
5 7
ABCDE
AB
AD
BC
BE
CD
CE
DE
出力サンプル:
2 3 3 3 3
コード:
/*
思路:使用一个结构体类型的数组,一个存放顶点字符,一个边的信息。
顶点按照输入顺序直接存放起来即可。
边要读取两个字符,第一个字符是起点,用来定位到对应顶点;另一个用来存终点下标
*/
#include <bits/stdc++.h>
using namespace std;
#define OK 1;
#define ERROR 0;
typedef int Status;
typedef struct VerNode
{
char ch;
struct VerNode *next;
}VerNode;
typedef struct
{
char V; //顶点
VerNode *start; //存放边的链表
int degree; //顶点的度数
}UDirGraph;
Status Create(UDirGraph graph[],int i,int j)
{
if (i < 0 || j < 0) return ERROR;
for (int k=0;k<i;k++)
{
graph[k].V = '0';
graph[k].start = NULL;
graph[k].degree = 0;
}
return OK;
}
int main()
{
int i, j;
char ch1, ch2;
scanf("%d %d",&i,&j);
getchar();
UDirGraph graph[i+1];
Create(graph,i,j);
for (int k=0; k<i; k++)
scanf("%c",&graph[k].V); //注意不要忘记&
graph[i].V = '\0';
getchar();
for (int k=0; k<j; k++)
{
scanf("%c%c",&ch1,&ch2);
getchar();
int n = 0;
int m = 0;
for (m=0; m<i; m++)
{
if (ch1 == graph[m].V)
{
graph[m].degree++;
for (n=0; n<i; n++)
if (ch2 == graph[n].V)
graph[n].degree++;
}
// printf("==%d==\n",graph[m].degree);
}
}
for (int k=0;k<i;k++)
{
if (k==0) printf("%d",graph[k].degree);
else printf(" %d",graph[k].degree);
}
}
16X16-1 隣接行列ストレージ グラフの深さ優先トラバーサル
隣接行列ストレージ グラフの深さ優先トラバーサルを実装してみてください。
関数インターフェースの定義:
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 がグラフ内の正当な頂点であることが保証されます。
審判テスト手順の例:
#include <stdio.h>
typedef enum {false, true} bool;
#define MaxVertexNum 10 /* 最大顶点数设为10 */
#define INFINITY 65535 /* ∞设为双字节无符号整数的最大值65535*/
typedef int Vertex; /* 用顶点下标表示顶点,为整型 */
typedef int WeightType; /* 边的权值设为整型 */
typedef struct GNode *PtrToGNode;
struct GNode{
int Nv; /* 顶点数 */
int Ne; /* 边数 */
WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */
bool Visited[MaxVertexNum]; /* 顶点的访问标记 */
MGraph CreateGraph(); /* 创建图并且将Visited初始化为false;裁判实现,细节不表 */
void Visit( Vertex V )
{
printf(" %d", V);
}
void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) );
int main()
{
MGraph G;
Vertex V;
G = CreateGraph();
scanf("%d", &V);
printf("DFS from %d:", V);
DFS(G, V, Visit);
return 0;
}
/* 你的代码将被嵌在这里 */
入力サンプル: 与えられた画像は次のとおりです
5
出力サンプル:
DFS from 5: 5 1 3 0 2 4 6
コード:
void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) )
{
int w;
Visited[V] = true; //标记为true,说明已经访问过该点
Visit(V);
for (w = 0; w < Graph->Nv; w++)
{
if (Graph->G[V][w] == 1 && !Visited[w]) //有节点而且没有被访问过的情况
{
DFS(Graph,w,Visit);
}
}
return ;
}
16X16-2 隣接リスト ストレージ グラフの幅優先トラバーサル
隣接リスト ストレージ グラフの幅優先走査を実装してみてください。
関数インターフェースの定義:
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 番目の頂点から幅優先検索を実行し、参照者によって定義された関数 Visit を使用して、トラバーサル中に各頂点にアクセスします。隣接ポイントにアクセスする場合は、隣接リスト順にアクセスする必要があります。この質問により、S がグラフ内の正当な頂点であることが保証されます。
審判テスト手順の例:
#include <stdio.h>
typedef enum {false, true} bool;
#define MaxVertexNum 10 /* 最大顶点数设为10 */
typedef int Vertex; /* 用顶点下标表示顶点,为整型 */
/* 邻接点的定义 */
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; /* 以邻接表方式存储的图类型 */
bool Visited[MaxVertexNum]; /* 顶点的访问标记 */
LGraph CreateGraph(); /* 创建图并且将Visited初始化为false;裁判实现,细节不表 */
void Visit( Vertex V )
{
printf(" %d", V);
}
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) );
int main()
{
LGraph G;
Vertex S;
G = CreateGraph();
scanf("%d", &S);
printf("BFS from %d:", S);
BFS(G, S, Visit);
return 0;
}
/* 你的代码将被嵌在这里 */
入力サンプル: 与えられた画像は次のとおりです
2
出力サンプル:
BFS from 2: 2 0 3 5 4 1 6
コード:
/*
思路:设置一个数组队列,先把这一行读取到的结点存放到队列中一直到NULL,只要队列中有元素就往后取出一个结点访问。
同时更新标记数组Visited的值来避免结点的重复访问。
*/
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) )
{
int len = Graph->Nv;
int Queue[len + 1];
int v;
PtrToAdjVNode p = NULL;
int i = 0;
int j = 0;
Queue[i++] = S;
Visited[S] = true;
while (j != i)
{
v = Queue[j++];
Visit(v);
p = Graph->G[v].FirstEdge;
while (p)
{
if (!Visited[p->AdjV])
{
Queue[i++] = p->AdjV;
Visited[p->AdjV] = true;
}
p = p->Next;
}
}
}
16X16-3 交通円滑化プロジェクトの最小コスト建設問題
ある地域の都市交通状況を調査した結果、既存の町間の高速道路に関する統計データが得られ、地域全体の任意の2つの町の間を迅速に移動できるようにするという「スムーズプロジェクト」の目標が提案されました。高速道路は、高速道路を介して間接的に到達できる限り、接続されています。都市道路の統計表ができました。この表には、高速道路に建設される可能性のあるいくつかの道路のコストがリストされています。円滑な交通プロジェクトに必要な最小限のコストを求めてください。
入力形式:
入力の最初の行は、町の数 N (1<N≤1000) と候補道路の数 M≤3N を示します。後続の M 行では、各行に道路で直接接続されている 2 つの町を表す 3 つの正の整数が与えられます。 . 番号 (1 から N までの番号が付けられます) と道路再建の推定コスト。
出力フォーマット:
ブロックされていないプロジェクトに必要な最小コストを出力します。入力データが不十分な場合は「不可能」と出力されます。
入力例1:
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
出力サンプル 1:
12
入力例2:
5 4
1 2 1
2 3 2
3 1 3
4 5 4
出力サンプル 2:
Impossible
コード:
/*
思路:定义一个结构体,里面的变量包括起点,终点,权值
定义一个标记数组
输入完成信息后根据权值把所有的元素排序,从最小的开始挑选能够建设的路
需要满足的条件:起点和终点不能同时在已经挑选的结点里面。用标记变量来确定是否已经被挑选
判断连通分量的时候看标记变量的大小,若只有一个连通分量,标记变量只有两个为1,其余都大于1
*/
#include <bits/stdc++.h>
using namespace std;
typedef struct Info
{
int start;
int last;
int value;
}Info;
void Swap(Info &i,Info &j);
int main()
{
int N,M; //结点个数以及候选道路数目
scanf("%d %d",&N,&M);
Info info[M*2];
int flag[N*2];
for (int i=1;i<=N;i++)
flag[i] = 0; //初始化标记数组
//输入并存储信息
for (int i=0;i<M;i++)
{
scanf("%d %d %d",&info[i].start,&info[i].last,&info[i].value);
flag[info[i].start] = 0;
flag[info[i].last] = 0;
}
//将所有信息进行排序
for (int i=0;i<M;i++)
{
for (int j=i+1;j<M;j++)
{
if (info[i].value > info[j].value)
{
Swap(info[i],info[j]);
}
}
}
//挑选成本小的路
int sum = 0;
int num = 0;
for (int i=0; i<M; i++)
{
//if (num == N-1) break;
if(flag[info[i].start] && flag[info[i].last]) //两个同时都已经在的情况
{
continue;
}
else
{
sum += info[i].value;
num++;
flag[info[i].start]++;
flag[info[i].last]++;
}
}
int con = 0;
for (int i=1; i<=N; i++)
{
if (flag[i] == 0)
{
con++;
break;
}
}
if (num != N-1 ||con) printf("Impossible\n");
else printf("%d\n",sum);
}
void Swap(Info &i,Info &j)
{
int temp;
temp = i.start;
i.start = j.start;
j.start = temp;
temp = i.last;
i.last = j.last;
j.last = temp;
temp = i.value;
i.value = j.value;
j.value = temp;
}
18X18-1 都市間緊急救助
都市の緊急救助チームのリーダーとして、あなたはその国の特別な地図を持っています。この地図には、点在する複数の都市と、それらの都市を接続するいくつかの高速道路が示されています。各都市の救助チームの数と、2 つの都市を結ぶ各高速道路の長さが地図上にマークされています。他の都市から緊急援助の要請があった場合、あなたの任務は、救助チームをできるだけ早く事件現場に導き、同時にできるだけ多くの救助チームを途中で呼び出すことです。
入力形式:
1 行目の入力では、N、M、S、D の 4 つの正の整数が与えられます (N (2≤N≤500) は都市の数です。ちなみに、都市の数は 0 ~ (N− 1); M は速い 道路の数; S は出発地の都市番号; D は目的地の都市番号。
2 行目は N 個の正の整数を示します。ここで、i 番目の数字は i 番目の都市の救助チームの数であり、数字はスペースで区切られています。後続の M 行では、各行に高速道路に関する情報 (都市 1、都市 2、および高速道路の長さがスペースで区切られています) が表示されます。数値はすべて 500 を超えない整数です。入力により、救助が可能であり、最適な解決策が唯一のものであることが保証されます。
出力フォーマット:
最初の行は、最短パスの数と、呼び出すことができる救助チームの最大数を出力します。2 行目は、S から D へのパスで渡される都市番号を出力します。数値はスペースで区切られ、出力の末尾に余分なスペースがあってはなりません。
入力例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
出力サンプル:
2 60
0 1 3
コード:
#include<bits/stdc++.h>
using namespace std;
#define INF 1000000
int a[1001][1001];
int cnt[1001],exs[1001]={0},cf[1001],ccf[1001],pre[1001];
//最短路径条数,各城市是否经过,各城市的救援队数量,到达该城市时所召集的所有救援队数量,到达该城市前经过的城市编号
int n,m,s,d;
int Dijkstra()
{
cnt[s] = 1;//开始时路径条数为1
exs[s] = 1;//当前在出发城市
for(int i = 0; i<n; i++)
{
int mm = INF,f = -1;
for(int j = 0; j<n; j++)
{
if(exs[j] == 0 && a[s][j] < mm) //寻找下一个距离最短的城市
{
mm = a[s][j];
f = j;//做好下一城市编号的标记
}
}
if(f == -1)break;//与其他未经过的城市不连通,退出循环
else exs[f] = 1;//到达下一城市
for(int j = 0; j<n; j++)
{
if(exs[j] == 0 && a[s][j] > a[s][f] + a[f][j]) //到达某一城市的最短路径
{
a[s][j] = a[s][f] + a[f][j];//最短路径更新
pre[j] = f;//记录上一个城市编号
cnt[j] = cnt[f];//拷贝到达上一个城市时的最短路径条数
ccf[j] = ccf[f] + cf[j];//到达某城市召集的全部救援队数量
}
else if(exs[j] == 0&&a[s][j] == a[s][f] + a[f][j]) //发现其他的最短路径
{
cnt[j] = cnt[j] + cnt[f];//更新到达当前城市时的最短路径条数
if(ccf[j] < ccf[f] + cf[j]) //最多救援队数量更新
{
pre[j] = f;//记录所经过的上一个城市编号
ccf[j] = ccf[f] + cf[j];//更新救援队总数
}
}
}
}
}
int main()
{
cin>>n>>m>>s>>d;
for(int i = 0;i<n;i++){
cin>>cf[i];
ccf[i] = cf[i];
cnt[i] = 1;
}
for(int i = 0;i<n;i++){
for(int j = 0;j<n;j++){
if(i != j) a[i][j] = a[j][i] = INF;//初始化(双向图)
}
}
for(int i = 0;i<m;i++){
int q,w,e;
cin>>q>>w>>e;
a[q][w] = a[w][q] = e;
}
Dijkstra();
cout<<cnt[d]<<" "<<ccf[d]+cf[s]<<endl;
int road[1001];
int x = 0,t = d;
while(pre[t] != 0)
{//所经历的城市的从后往前的顺序
road[x++]=pre[t];
t=pre[t];
}
cout<<s;//出发地
for(int i = x-1;i >= 0;i--)
cout<<" "<<road[i];
cout<<" "<<d;//目的地
}
19X19-1 二分探索
この質問には二分探索アルゴリズムの実装が必要です。
関数インターフェースの定義:
Position BinarySearch( List L, ElementType X );
リスト構造は次のように定義されます。
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
L はユーザーによって渡される線形リストで、ElementType 要素は >、==、< によって比較でき、質問によって受信データが昇順であることが保証されます。関数 BinarySearch は、配列の添え字である Data 内の X の位置を見つけようとしています (注: 要素は添え字 1 から格納されます)。見つかった場合は添え字が返され、そうでない場合は特別な失敗マーク NotFound が返されます。
審判テスト手順の例:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
#define NotFound 0
typedef int ElementType;
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position Last; /* 保存线性表中最后一个元素的位置 */
};
List ReadInput(); /* 裁判实现,细节不表。元素从下标1开始存储 */
Position BinarySearch( List L, ElementType X );
int main()
{
List L;
ElementType X;
Position P;
L = ReadInput();
scanf("%d", &X);
P = BinarySearch( L, X );
printf("%d\n", P);
return 0;
}
/* 你的代码将被嵌在这里 */
入力例1:
5
12 31 55 89 101
31
出力サンプル 1:
2
入力例2:
3
26 78 233
31
出力サンプル 2:
0
コード:
Position BinarySearch( List L, ElementType X )
{
if (L == NULL) return NotFound;
int left = 1; //最左边位置
int right = L->Last; //最右边位置
int flag = 0;
int mid;
while (left <= right)
{
mid = (left + right)/2; //中间位置
if (L->Data[mid] == X) {flag = 1;return mid;}
else if (L->Data[mid] < X) left = mid + 1;
else right = mid - 1;
}
if (!flag) return NotFound;
}
19X19-2 2 つの順序付けされたシーケンスの中央値
2 つの等しい長さの非降順シーケンス S1 と S2 があることがわかっています。S1 と S2 の和集合の中央値を求める関数を設計します。順序付けされたシーケンス A0 ,A 1 ,⋯,AN N−1 の中央値は、A (N−1)/2 の値、つまり ⌊( N+1) )/2⌋数値 (A 0 は最初の数値です)。
入力形式:
入力は 3 行に分かれています。最初の行はシーケンスの共通の長さ N (0<N ≤100000) を示し、後続の各行にはシーケンスの情報、つまり非降順に並べられた N 個の整数が入力されます。数字はスペースで区切られます。
出力フォーマット:
2 つの入力シーケンスの結合シーケンスの中央値を 1 行に出力します。
入力例1:
5
1 3 5 7 9
2 3 4 5 6
出力サンプル 1:
4
入力例2:
6
-100 -10 1 1 1 1
-50 0 2 3 4 5
出力サンプル 2:
1
コード:
#include <bits/stdc++.h>
using namespace std;
int main(){
int str[100001],arr[100001];
int n;scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&str[i]);
for(int i=0;i<n;i++) scanf("%d",&arr[i]);
//中位数在大的左边 小的右边
int start1=0,end1=n-1,mid1=(n-1)/2;
int start2=0,end2=n-1,mid2=(n-1)/2;
int mid;int flag=0;
while(start1!=end1&&start2!=end2){
if(str[mid1]==arr[mid2]) {
mid=str[mid1];
flag=1;
break;
}
else if(str[mid1]>arr[mid2]){
if((end1-start1)%2==0&&(end2-start2)%2==0){
end1=mid1;
start2=mid2;
}
else{
end1=mid1;
start2=mid2+1;
}
mid1=(start1+end1)/2;
mid2=(start2+end2)/2;
}
else{
if((end1-start1)%2==0&&(end2-start2)%2==0){
start1=mid1;
end2=mid2;
}
else {
start1=mid1+1;
end2=mid2;
}
mid1=(start1+end1)/2;
mid2=(start2+end2)/2;
}
}
if(!flag) {
if(start1==end1) {
int a=str[start1],b=arr[end2];
if(a>b) mid=b;
else mid=a;
}
else {
int a=arr[start2],b=str[end1];
if(a>b) mid=b;
else mid=a;
}
}
printf("%d\n",mid);
}
20X20-1 は二分探索木ですか?
この質問では、指定された二分木が二分探索木であるかどうかを判断する関数の実装が必要です。
関数インターフェースの定義:
bool IsBST ( BinTree T );
BinTree 構造は次のように定義されます。
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
関数 IsBST は、指定された T が二分探索木、つまり次の定義を満たす二分木であるかどうかを判断する必要があります。
定義: 二分探索木は、空にすることもできる二分木です。空でない場合は、次のプロパティを満たします。
非空左子树的所有键值小于其根结点的键值。
非空右子树的所有键值大于其根结点的键值。
左、右子树都是二叉搜索树。
T が二分探索ツリーの場合、関数は true を返し、それ以外の場合は false を返します。
審判テスト手順の例:
#include <stdio.h>
#include <stdlib.h>
typedef enum { false, true } bool;
typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
ElementType Data;
BinTree Left;
BinTree Right;
};
BinTree BuildTree(); /* 由裁判实现,细节不表 */
bool IsBST ( BinTree T );
int main()
{
BinTree T;
T = BuildTree();
if ( IsBST(T) ) printf("Yes\n");
else printf("No\n");
return 0;
}
/* 你的代码将被嵌在这里 */
入力サンプル 1: 以下に示すように
出力サンプル 1:
Yes
入力サンプル 2: 以下に示すように
出力サンプル 2:
No
コード:
int a[101];
int i = 0;
bool IsBST ( BinTree T )
{//中序遍历,得到的结果是从小到大排列,只要满足左边小于右边即可
if (T != NULL)
{
IsBST(T->Left);
a[i++] = T->Data;
IsBST(T->Right);
}
for (int j=0;j<i;j++)
{
if (a[j-1] >= a[j])
return false;
}
return true;
}
21X21-1 分離リンク方式の削除操作機能
分離リンク方式の削除操作機能を実装してみます。
関数インターフェースの定義:
bool Delete( HashTable H, ElementType Key );
ここで、HashTable は、次のように定義される、分離されたリンクされたハッシュ テーブルです。
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
typedef struct TblNode *HashTable; /* 散列表类型 */
struct TblNode { /* 散列表结点定义 */
int TableSize; /* 表的最大长度 */
List Heads; /* 指向链表头结点的数组 */
};
関数 Delete は、ハッシュ テーブル H から Key の場所を見つけ、参照者によって定義されたハッシュ関数 Hash(Key, H->TableSize) に基づいてそれを削除し、次のテキスト行を出力します。 [i]、Key は渡された削除されたキーワード、i はキーが配置されているリンク リストの番号で、最後に true を返します。キーが存在しない場合は false を返します。
審判テスト手順の例:
#include <stdio.h>
#include <string.h>
#define KEYLENGTH 15 /* 关键词字符串的最大长度 */
typedef char ElementType[KEYLENGTH+1]; /* 关键词类型用字符串 */
typedef int Index; /* 散列地址类型 */
typedef enum {false, true} bool;
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
typedef struct TblNode *HashTable; /* 散列表类型 */
struct TblNode { /* 散列表结点定义 */
int TableSize; /* 表的最大长度 */
List Heads; /* 指向链表头结点的数组 */
};
Index Hash( ElementType Key, int TableSize )
{
return (Key[0]-'a')%TableSize;
}
HashTable BuildTable(); /* 裁判实现,细节不表 */
bool Delete( HashTable H, ElementType Key );
int main()
{
HashTable H;
ElementType Key;
H = BuildTable();
scanf("%s", Key);
if (Delete(H, Key) == false)
printf("ERROR: %s is not found\n", Key);
if (Delete(H, Key) == true)
printf("Are you kidding me?\n");
return 0;
}
/* 你的代码将被嵌在这里 */
入力例1:ハッシュテーブルは以下のとおりです
able
出力サンプル 1:
able is deleted from list Heads[0]
入力サンプル 2: サンプル 1 に示すハッシュ テーブル
date
出力サンプル 2:
ERROR: date is not found
コード:
bool Delete( HashTable H, ElementType Key )
{
int w = Hash(Key,H->TableSize); //题目已知的函数,返回Key对表长的求余,即Key在数组中的下标
if (H->Heads[w].Next == NULL) return false; //Key应该在的下标处没有元素,直接返回没找到
PtrToLNode p = H->Heads[w].Next;
PtrToLNode q = p;
while (strcmp(Key,p->Data) && p->Next != NULL)
{
q = p; //记录要删除的结点的上一位
p = p->Next;
}
if (!strcmp(Key,p->Data))
{
printf("%s is deleted from list Heads[%d]",Key,w);
q = p->Next; //删除后的连接结点
free(p); //释放已经删除结点的空间
return true;
}
return false;
}
21X21-2 直接挿入ソート
この質問には直接挿入ソート関数の実装が必要で、ソートされる列の長さは 1<=n<=1000 です。
関数インターフェースの定義:
void InsertSort(SqList L);
ここで、L はソート対象のテーブルであり、ソートされたデータは小さいものから大きいものへと配置されます。
型定義:
typedef int KeyType;
typedef struct {
KeyType *elem; /*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
審判テスト手順の例:
#include<stdio.h>
#include<stdlib.h>
typedef int KeyType;
typedef struct {
KeyType *elem; /*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
void CreatSqList(SqList *L);/*待排序列建立,由裁判实现,细节不表*/
void InsertSort(SqList L);
int main()
{
SqList L;
int i;
CreatSqList(&L);
InsertSort(L);
for(i=1;i<=L.Length;i++)
{
printf("%d ",L.elem[i]);
}
return 0;
}
/*你的代码将被嵌在这里 */
入力例:
最初の行の整数は、並べ替えに参加するキーワードの数を表します。2 行目はキーワード値です。例:
10
5 2 4 1 8 9 10 12 3 6
出力サンプル:
小さいものから大きいものまで順序付けられたシーケンスを出力します。各キーワードはスペースで区切られ、最後のキーワードの後にはスペースが入ります。
1 2 3 4 5 6 8 9 10 12
コード:
void InsertSort(SqList L)
{//先排第一个,然后第二个插入到前边的序列,第三个插入,以此类推。
int i,j;
for (i = 1; i <= L.Length; i++)
{
L.elem[0] = L.elem[i];
for (j = i; L.elem[j-1]>L.elem[0] && j > 0; j--)
{
L.elem[j] = L.elem[j-1];
L.elem[j-1] = L.elem[0];
}
}
}