5-1
本题要求实现折半查找的递归查找操作。
#include
#include
typedef int KeyType;
typedef struct {
KeyType *data; /*表基址*/
int length; /*表长*/
}SSTable;
void CreatSSTable(SSTable *ST);/*有序表创建,由裁判实现,细节不表*/
int BiSearch(SSTable ST,KeyType e,int low,int high);
int main()
{
SSTable ST;
int n,result,i;
KeyType e;
CreatSSTable(&ST);
scanf("%d",&n);
for( i=0;i<n;i++)
{
scanf("%d",&e);
result = BiSearch(ST,e,1,ST.length);
if(result) printf("%d is found\n",e);
else printf("%d is not found\n",e);
}
return 0;
}
int BiSearch(SSTable ST,KeyType e,int low,int high)
{
int mid;
if(
low>high
(6分)) return 0;
mid=(low+high)/2;
if(ST.data[mid]==e) return mid;
if(e<ST.data[mid]) return
BiSearch(T, e, low, mid-1)
;
else
BiSearch(T, e, mid, high)
;
}
5-2
本题要求用冒泡排序将一组整数按增序排序。冒泡排序每次从头到尾扫描待排序列,检查相邻两数的顺序,如果顺序不对就交换。请补全下列冒泡排序的代码。
typedef struct node *nodeptr;
struct node{
int value;
nodeptr next;
/* 一些其他的项,在此忽略 */
};
nodeptr BubbleSort (nodeptr h)
{/* h 是带空头结点的链表的头指针 */
nodeptr p, q;
int flag_swap;
if (!h->next) return h;
do{
flag_swap = 0;
p = h;
while (p->next->next){
if (
p->next->value > p->next->next->value
(12分) ){
flag_swap++;
q = p->next;
p->next = q->next
;
q->next = p->next->next
;
p->next->next=q
;
}
else p = p->next;
}
} while (flag_swap > 0);
return h;
}
5-3
以下程序的功能是输入一个正整数n(1<n≤10),再输入n个整数,将它们存入数组a中,再输入1个数x,然后在数组中查找x,如果找到,输出相应的最小下标,否则,输出“Not Found”。请填空。
#include
int main(int argc, char const *argv[])
{
int i, index, n, x, a[10];
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%d",
&a[i]
(6分));
scanf("%d", &x);
index = -1
;
for (i = 0; i < n; i++)
if (a[i] == x) {
index = i;
break
;
}
if (index != -1)
printf("%d\n", index);
else
printf("Not Found\n");
return 0;
}
5-4
有15个已经排好序的数存放在一个数组中,输入一个数,要求用折半查找法找出该数是数组中第几个元素的值。
如果该数不在数组中,则输出无此数。请填空。
变量说明:top,bott为查找区间两端点的下标;loca为查找成功与否的开关变量。
#include
int main(void)
{
int N, number, top, bott, min, loca;
int a[15] = { -3, -1, 0, 1, 2, 4, 6, 7, 8, 9, 12, 19, 21, 23, 50};
N = 15;
scanf("%d", &number);
loca = 0; top = 0; bott = N - 1;
if ((number < a[0]) || (number > a[N - 1]))
loca = -1;
while ((loca == 0) && (top <= bott)) {
min =
(bott+top)/2
(6分);
if (number == a[min]) {
loca = min;
printf("The serial number is %d\n", loca + 1);
break;
} else if (number < a[min])bott = min - 1;
else
top = min
;
}
if (
loca == 0
)
printf("%d isn't in table\n", number);
return 0;
}
5-6
本程序在数组中同时查找最大元素和最小元素的下标,分别存放在函数main()的max和min变量中。
#include
void find(int *, int, int *, int *);
int main(void)
{
int max, min, a[]={5,3,7,9,2,0,4,1,6,8};
find(
a, 10, &max, &min
(3分));
printf("%d,%d\n", max, min);
return 0;
}
void find(int *a, int n, int *max, int *min)
{
int i;
*max=*min=0;
for (i = 1; i < n; i++)
{
if (a[i] > a [*max])
*max = i
;
if (a[i] < a [*min])
*min = i
;
}
}
5-7
输入10个成绩,查找最高分并输出。
#include
int *GetMax(int score[ ], int n);
int main(void)
{
int i, score[10], *p;
for(i = 0; i < 10; i++)
scanf("%d", &score[i]);
p=
GetMax(score, 10)
(2分) ;
printf("%d\n", *p);
return 0;
}
int *GetMax(int score[ ], int n)
{
int i, temp, pos = 0;
temp = score[0] ;
for(i = 0 ; i < 10 ; i++)
if(score[i] > temp)
{ temp = score[i];
pos = i ;
}
return
&score[pos]
;
}
本题要求实现二路归并排序中的归并操作,待排序列的长度1<=n<=1000。
归并排序思路请参考归并排序详解
本题参考代码:
void Merge(SqList L,int low,int m,int high) {
int i=low, j=m+1;
int buf1[m-low+1];//开辟额外空间,分别存储两部分数据
int buf2[high-m];
while(i<=m) {
buf1[i-low] = L.elem[i];
i++;
}
while(j<=high) {
buf2[j-m-1] = L.elem[j];
j++;
}
i=0,j=0;
int index = low;
//进行数据合并,在两个数组中寻找较小的元素,存入L.elem中
while(i<m-low+1&&j<high-m) {
L.elem[index++] = buf1[i]<buf2[j]?buf1[i++]:buf2[j++];
}
//若仍有数据未合并,则分别处理剩余未合并的两个数组
while(i<m-low+1) {
L.elem[index++] = buf1[i++];
}
while(j<high-m) {
L.elem[index++] = buf2[j++];
}
}
已知有两个非降序序列S1, S2, 求S1与S2归并成一个序列的低位中位数。有序序列A0,A1,⋯,AN−1的中位数指A(N−1)/2的值,即第⌊(N+1)/2⌋个数(A0为第1个数)。
限制:
时间限制: 700 ms
内存限制: 24 MB
思路一:将A和B合并成新的数组
本思路利用最笨的方法去实现,利用排序将两个数组合并成一个数组,合并成有序数组后即可求任意k值,其时间复杂度为 O(m+n), 空间复杂图为O(m+n)。
本题N最大值为2500000,则输入总空间为250000024(byte)/1024/1024=19.07MB,如果再申请额外空间(即额外的O(m+n)空间),会产生内存不足。
思路二:采用归并方法
为了降低空间,本思路采用归并排序的归并算法,利用两个分别指向A和B数组头的指针去遍历数组,然后统计元素个数,直到找到中位数。本算法是对思路一的改进,用一个临时变量保存k值,而不需要合并数组单独存储,节省了存储空间。
其 时间复杂度为O(m+n), 空间复杂度为O(1).
参考代码:
#include
#include
#define MAX_LEN 2500001
int a[MAX_LEN], b[MAX_LEN];
int main() {
int n,m;
int i,j;
scanf("%d",&n);
for(i=0;i<n;i++) scanf("%d",&a[i]);
scanf("%d",&m);
for(i=0;i<m;i++) scanf("%d",&b[i]);
i=0,j=0;
int mid = (n+m-1)/2, cur_index = 0;
int result = 0;
while(cur_index<=mid&&i<n&&j<m) {
result = a[i]<b[j]?a[i++]:b[j++];
cur_index++;
}
while(cur_index<=mid&&i<n) {
result = a[i];
i++;cur_index++;
}
while(cur_index<=mid&&j<m) {
result = b[j];
j++;cur_index++;
}
printf("%d",result);
}
思路三:采用二分方法
当数据量增大时,线性增长也可能不满足时间限制。由于已知两个序列是非递减的,所以就可以将原问题转变成一个寻找第k小数的问题,于是中位数实际上是第(m+n)/2小的数。因此可以将原题目求中位数转换为求第 k = (m+n)/2的数。
首先假设数组A和B的元素个数都大于k/2,我们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有三种情况:>、<和=。
如果A[k/2-1],这表示A[0]到A[k/2-1]的元素都在A和B合并之后的前k小的元素中。换句话说,A[k/2-1]不可能大于两数组合并之后的第k小值,所以我们可以将其抛弃。上述描述证明:假设A[k/2-1]大于合并之后的第k小值,我假定其为第(k+1)小值。由于A[k/2-1]小于B[k/2-1],所以B[k/2-1]至少是第(k+2)小值。但实际上,在A中至多存在k/2-1个元素小于A[k/2-1],B中也至多存在k/2-1个元素小于A[k/2-1],所以小于A[k/2-1]的元素个数至多有k/2+ k/2-2,小于k,这与A[k/2-1]是第(k+1)的数矛盾。
当A[k/2-1]>B[k/2-1]时存在类似的结论。
当A[k/2-1]=B[k/2-1]时,则第k小的数就是这个相等的数据。由于在A和B中分别有k/2-1个元素小于m,所以m即是第k小的数。
通过上面的分析,本思想可以采用递归的方式实现寻找第k小的数。
确定的返回条件:
本思想效率较高。每次都有一半的元素被删除,即计算中值时每次将范围缩小一半,故而时间复杂度为O(lg(m+n)),由于不需要开辟额外空间,本算法空间复杂度为O(1)。
参考代码:
#include
#include
#define MAX_LEN 2500001
int a[MAX_LEN], b[MAX_LEN];
int findKthMinValue(int* a, int n, int* b, int m, int k) {
//使得第一个数组的长度永远比第二个小
if(n>m) return findKthMinValue(b, m, a, n, k);
if(n == 0) return b[k-1];
if(k==1) return a[0]>b[0]?b[0]:a[0];
//将k分为两个部分
int pa = k / 2>n?n:k/2, pb = k - pa;
if (a[pa - 1] < b[pb - 1])
return findKthMinValue(a + pa, n - pa, b, m, k - pa);
else if (a[pa - 1] > b[pb - 1])
return findKthMinValue(a, n, b + pb, m - pb, k - pb);
else
return a[pa - 1];
}
int main() {
int n,m;
int i,j;
scanf("%d",&n);
for(i=0;i<n;i++) scanf("%d",&a[i]);
scanf("%d",&m);
for(i=0;i<m;i++) scanf("%d",&b[i]);
printf("%d",result);
if((n+m)&1) {
printf("%d", findKthMinValue(a,n,b,m,(n+m)/2+1));
}else {
printf("%d", findKthMinValue(a,n,b,m,(n+m)/2));
}
}
我们已经知道了将N个整数按从小到大排序的冒泡排序法。本题要求将此方法用于字符串序列,并对任意给定的K( 参考代码:#include