6-16 直接插入排序 (10分)
本题要求实现直接插入排序函数,待排序列的长度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;
}
/*你的代码将被嵌在这里 */
输入样例:
第一行整数表示参与排序的关键字个数。第二行是关键字值 例如:
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=2;i<=L.Length;++i)
{
if(L.elem[i]<L.elem[i-1])
{
L.elem[0]=L.elem[i];//备份无序块首元素
L.elem[i]=L.elem[i-1];
for(j=i-2;L.elem[j]>L.elem[0];--j)
{
L.elem[j+1]=L.elem[j]; //比首元素大的元素后移
}
L.elem[j+1]=L.elem[0];//填入终止位置右侧
}
}
}
6-1 希尔排序的实现 (10分)
本题要求实现一趟希尔排序函数,待排序列的长度1<=n<=1000。
函数接口定义:
void ShellInsert(SqList L,int dk);
其中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 ShellInsert(SqList L,int dk);
void ShellSort(SqList L);
int main()
{
SqList L;
int i;
CreatSqList(&L);
ShellSort(L);
for(i=1;i<=L.Length;i++)
{
printf("%d ",L.elem[i]);
}
return 0;
}
void ShellSort(SqList L)
{
/*按增量序列dlta[0…t-1]对顺序表L作Shell排序,假设规定增量序列为5,3,1*/
int k;
int dlta[3]={5,3,1};
int t=3;
for(k=0;k<t;++k)
ShellInsert(L,dlta[k]);
}
/*你的代码将被嵌在这里 */
输入样例:
第一行整数表示参与排序的关键字个数。第二行是关键字值 例如:
10
5 2 4 1 8 9 10 12 3 6
输出样例:
输出由小到大的有序序列,每一个关键字之间由空格隔开,最后一个关键字后有一个空格。
1 2 3 4 5 6 8 9 10 12
void ShellInsert(SqList L,int dk)
{
int i,j;
for(i=dk+1;i<=L.Length;i++)//从第dk+1个元素开始子序列内插入排序
{
if(L.elem[i]<L.elem[i-dk])//子序列内前一个不再是i-1,而是i-dk
{
L.elem[0]=L.elem[i];
L.elem[i]=L.elem[i-dk];
for(j=i-dk;L.elem[j]>L.elem[0]&&j>0;j-=dk)//子序列后移dk位
{
L.elem[j+dk]=L.elem[j];
}
L.elem[j+dk]=L.elem[0];
}
}
}
7-2 人以群分 (25分)
社交网络中我们给每个人定义了一个“活跃度”,现希望根据这个指标把人群分为两大类,即外向型(outgoing,即活跃度高的)和内向型(introverted,即活跃度低的)。要求两类人群的规模尽可能接近,而他们的总活跃度差距尽可能拉开。
输入格式:
输入第一行给出一个正整数N(2≤N≤105 )。随后一行给出N个正整数,分别是每个人的活跃度,其间以空格分隔。题目保证这些数字以及它们的和都不会超过2^31。
输出格式:
按下列格式输出:
Outgoing #: N1
Introverted #: N2
Diff = N3
其中N1是外向型人的个数;N2是内向型人的个数;N3是两群人总活跃度之差的绝对值。
输入样例1:
10
23 8 10 99 46 2333 46 1 666 555
输出样例1:
Outgoing #: 5
Introverted #: 5
Diff = 3611
输入样例2:
13
110 79 218 69 3721 100 29 135 2 6 13 5188 85
输出样例2:
Outgoing #: 7
Introverted #: 6
Diff = 9359
//要求两类人群的规模尽可能接近,而他们的总活跃度差距尽可能拉开。
//如果输入的n为奇数个,那么多的那一个人一定是放到外向的人数里面,来使大的更大
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include <algorithm>
using namespace std;
int main()
{
int i,n;
scanf("%d",&n);
int a[100000];
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
int n1=0,n2=0,n3=0;
int outsum=0;//外向型总活跃度
int insum=0;//内向型总活跃度
int out[50000];
int in[50000];
int outp;//外向型人数
outp=(n%2==0 ? n/2 : n/2+1);
int inp=n-outp;//内向型人数
for(i=1;i<=inp;i++)
{
in[i]=a[i];
// printf("%d ",in[i]);
insum+=in[i];
}
// printf("\n");
for(i=1;i<=outp;i++)
{
out[i]=a[i+inp];
// printf("%d ",out[i]);
outsum+=out[i];
}
// printf("\n");
n1=outp;
n2=inp;
n3=outsum-insum;
printf("Outgoing #: %d\n",n1);
printf("Introverted #: %d\n",n2);
printf("Diff = %d\n",n3);
return 0;
}
7-1 排序 (25分)
给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。
本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下:
数据1:只有1个元素;
数据2:11个不相同的整数,测试基本正确性;
数据3:103个随机整数;
数据4:104个随机整数;
数据5:105个随机整数;
数据6:105个顺序整数;
数据7:105个逆序整数;
数据8:105个基本有序的整数;
数据9:105个随机正整数,每个数字不超过1000。
加粗样式输入格式:
输入第一行给出正整数N(≤10^5),随后一行给出N个(长整型范围内的)整数,其间以空格分隔。
输出格式:
在一行中输出从小到大排序后的结果,数字间以1个空格分隔,行末不得有多余空格。
输入样例:
11
4 981 10 -17 0 -20 29 50 8 43 -5
输出样例:
-20 -17 -5 0 4 8 10 29 43 50 981
//heapsort
#include<stdio.h>
#include<stdlib.h>
typedef int KeyType;
typedef struct {
KeyType *elem;/*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
void CreatSqList(SqList &H);/*待排序列建立*/
void HeapAdjust(SqList &H,int head ,int tail);
void HeapSort(SqList &H);
int main()
{
SqList H;
int i;
CreatSqList(H);
HeapSort(H);
printf("%d",H.elem[1]);
for(i=2;i<=H.Length;i++)
{
printf(" %d",H.elem[i]);
}
printf("\n");
return 0;
}
void CreatSqList(SqList &H)
{
int i,n;
scanf("%d",&n);
if(n<=0) return;
else
{
H.elem=(KeyType*)malloc(sizeof(KeyType)*n);
H.Length=0;
for(i=1;i<=n;i++) //0号作为哨兵
{
scanf("%d",&H.elem[i]);
H.Length++;
}
}
}
void HeapAdjust(SqList &H,int head ,int tail)
{
//H内存中是顺序表,逻辑上是二叉树、堆
int rc=H.elem[head];
int lchild=2*head;
int rchild=2*head+1;
int gchild;//大孩子
while(lchild<=tail)//只要左孩子存在
{
if(rchild<=tail&&H.elem[lchild]<H.elem[rchild])
gchild=rchild;
else gchild=lchild;
if(rc<H.elem[gchild])
{
H.elem[head]=H.elem[gchild];
head=gchild;
lchild=2*head;
rchild=2*head+1;
}
else break;
}
H.elem[head]=rc;
}
void HeapSort(SqList &H)
{
int i;
for(i=H.Length/2;i>0;--i)
{
HeapAdjust(H,i,H.Length);
}
for(i=1;i<=H.Length-1;i++)
{
int t=H.elem[1];
H.elem[1]=H.elem[H.Length-i+1];
H.elem[H.Length-i+1] = t;
HeapAdjust(H,1,H.Length-i);
}
}
//shellsort
//#include<stdio.h>
//#include<stdlib.h>
//typedef int KeyType;
//typedef struct {
// KeyType *elem; /*elem[0]一般作哨兵或缓冲区*/
// int Length;
//}SqList;
//void CreatSqList(SqList *L);/*待排序列建立*/
//void ShellInsert(SqList L,int dk);
//void ShellSort(SqList L);
//
//int main()
//{
// SqList L;
// int i;
// CreatSqList(&L);
// ShellSort(L);
// printf("%d",L.elem[1]);
// for(i=2;i<=L.Length;i++)
// {
// printf(" %d",L.elem[i]);
// }
// printf("\n");
//
// return 0;
//}
//void CreatSqList(SqList *L)
//{
// int i,n;
// scanf("%d",&n);
// if(n<=0) return;
// else
// {
// L->elem=(KeyType*)malloc(sizeof(KeyType)*n);
// L->Length=0;
// for(i=1;i<=n;i++)//0号作为哨兵
// {
// scanf("%d",&L->elem[i]);
// L->Length++;
// }
// }
//}
//void ShellSort(SqList L)
//{
// /*按增量序列dlta[0…t-1]对顺序表L作Shell排序,假设规定增量序列为5,3,1*/
// int k;
// int dlta[3]={5,3,1};
// int t=3;
// for(k=0;k<t;++k)
// ShellInsert(L,dlta[k]);
//}
//void ShellInsert(SqList L,int dk)
//{
// int i,j;
// for(i=dk+1;i<=L.Length;i++)
// {
// if(*(L.elem+i)<*(L.elem+i-dk))
// {
// *(L.elem)=*(L.elem+i);//备份无序子序列首元素
// for(j=i-dk;j>0&&*(L.elem+j)>*(L.elem);j-=dk)
// {
// *(L.elem+j+dk)=*(L.elem+j);
// }
// *(L.elem+j+dk)=*(L.elem);
// }
// }
//}
//sort
//#include<stdio.h>
//#include<stdlib.h>
//#include<iostream>
//#include <algorithm>
//using namespace std;
//
//int main()
//{
// int i,n;
// scanf("%d",&n);
// int a[100000];
// for(i=1;i<=n;i++)
// {
// scanf("%d",&a[i]);
// }
// sort(a+1,a+n+1);
// printf("%d",a[1]);
// for(i=2;i<=n;i++)
// {
// printf(" %d",a[i]);
// }
// printf("\n");
// return 0;
//}
//quicksort
#include<stdio.h>
#include<stdlib.h>
typedef int KeyType;
typedef struct {
KeyType *elem;/*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
void CreatSqList(SqList *L);/*待排序列建立*/
int Partition(SqList L,int low,int high);
void QSort(SqList L,int low,int high);
int main()
{
SqList L;
int i;
CreatSqList(&L);
QSort(L,1,L.Length);
printf("%d",L.elem[1]);
for(i=2;i<=L.Length;i++)
{
printf(" %d",L.elem[i]);
}
printf("\n");
return 0;
}
void CreatSqList(SqList *L)
{
int i,n;
scanf("%d",&n);
if(n<=0) return;
else
{
L->elem=(KeyType*)malloc(sizeof(KeyType)*n);
L->Length=0;
for(i=1;i<=n;i++) //0号作为哨兵
{
scanf("%d",&L->elem[i]);
L->Length++;
}
}
}
int Partition(SqList L,int low,int high)
{
L.elem[0]=L.elem[low];
while(low<high)
{
while(high>low&&L.elem[high]>=L.elem[0])
--high;//high左移
L.elem[low]=L.elem[high];
while(low<high&&L.elem[low]<=L.elem[0])
++low;
L.elem[high]=L.elem[low];
}
L.elem[low]=L.elem[0];
return low;
}
void QSort(SqList L,int low,int high)
{
if(!(low<high)) return;
else
{
int pivotloc=Partition(L,low,high);
QSort(L,low,pivotloc-1);
QSort(L,pivotloc+1,high);
}
}
7-2 寻找大富翁 (25分)
胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人。假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁。
输入格式:
输入首先给出两个正整数N(≤10^6)和M(≤10),其中N为总人数,M为需要找出的大富翁数;接下来一行给出N个人的个人资产值,以百万元为单位,为不超过长整型范围的整数。数字间以空格分隔。
输出格式:
在一行内按非递增顺序输出资产排前M位的大富翁的个人资产值。数字间以空格分隔,但结尾不得有多余空格。
输入样例:
8 3
8 12 7 3 20 9 5 18
输出样例:
20 18 12
#include<stdio.h>
#include<stdlib.h>
typedef int KeyType;
typedef struct {
KeyType *elem;/*elem[0]一般作哨兵或缓冲区*/
int Length;
}SqList;
void CreatSqList(SqList &H);/*待排序列建立*/
void HeapAdjust(SqList &H,int head ,int tail);
void HeapSort(SqList &H);
int main()
{
SqList H;
int i;
int n;
scanf("%d",&n);
int m;
scanf("%d",&m);
if(n<=0) printf("error");
else
{
H.elem=(KeyType*)malloc(sizeof(KeyType)*n);
H.Length=0;
for(i=1;i<=n;i++)//0号作为哨兵
{
scanf("%d",&H.elem[i]);
H.Length++;
}
}
HeapSort(H);
if(m>n)
{
printf("%d",H.elem[1]);
for(i=2;i<=n;i++)
printf(" %d",H.elem[i]);
}
else
{
printf("%d",H.elem[1]);
for(i=2;i<=m;i++)
{
printf(" %d",H.elem[i]);
}
}
printf("\n");
return 0;
}
void HeapAdjust(SqList &H,int head ,int tail)
{
//H内存中是顺序表,逻辑上是二叉树、堆
int rc=H.elem[head];
int lchild=2*head;
int rchild=2*head+1;
int gchild;//大孩子 (非递增排序时大孩子数值小)
while(lchild<=tail)//只要左孩子存在
{
if(rchild<=tail&&H.elem[lchild]>H.elem[rchild])
gchild=rchild;
else gchild=lchild;
if(rc>H.elem[gchild])
{
H.elem[head]=H.elem[gchild];
head=gchild;
lchild=2*head;
rchild=2*head+1;
}
else break;
}
H.elem[head]=rc;
}
void HeapSort(SqList &H)
{
int i;
for(i=H.Length/2;i>0;--i)
{
HeapAdjust(H,i,H.Length);
}
for(i=1;i<=H.Length-1;i++)
{
int t=H.elem[1];
H.elem[1]=H.elem[H.Length-i+1];
H.elem[H.Length-i+1] = t;
HeapAdjust(H,1,H.Length-i);
}
}
6-1 Iterative Mergesort (25分)
How would you implement mergesort without using recursion?
The idea of iterative mergesort is to start from N sorted sublists of length 1, and each time to merge a pair of adjacent sublists until one sorted list is obtained. You are supposed to implement the key function of merging.
Format of functions:
void merge_pass( ElementType list[], ElementType sorted[], int N, int length );
The function merge_pass performs one pass of the merge sort that merges adjacent pairs of sublists from list into sorted. N is the number of elements in the list and length is the length of the sublists.
Sample program of judge:
#include <stdio.h>
#define ElementType int
#define MAXN 100
void merge_pass( ElementType list[], ElementType sorted[], int N, int length );
void output( ElementType list[], int N )
{
int i;
for (i=0; i<N; i++) printf("%d ", list[i]);
printf("\n");
}
void merge_sort( ElementType list[], int N )
{
ElementType extra[MAXN]; /* the extra space required */
int length = 1; /* current length of sublist being merged */
while( length < N ) {
merge_pass( list, extra, N, length ); /* merge list into extra */
output( extra, N );
length *= 2;
merge_pass( extra, list, N, length ); /* merge extra back to list */
output( list, N );
length *= 2;
}
}
int main()
{
int N, i;
ElementType A[MAXN];
scanf("%d", &N);
for (i=0; i<N; i++) scanf("%d", &A[i]);
merge_sort(A, N);
output(A, N);
return 0;
}
/* Your function will be put here */
Sample Input:
10
8 7 9 2 3 5 1 6 4 0
Sample Output:
7 8 2 9 3 5 1 6 0 4
2 7 8 9 1 3 5 6 0 4
1 2 3 5 6 7 8 9 0 4
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
void merge_pass( ElementType list[], ElementType sorted[], int N, int length )
{
int *a=list;
int *b=sorted;
int t=0;
int pos=0;
while(pos<N)
{
int left=pos;
int right=pos+length;
while(left<pos+length&&right<pos+length+length&&left<N&&right<N)
{
if(a[left]<a[right])
{
b[t++]=a[left++];
}
else
{
b[t++]=a[right++];
}
}
while(left<pos+length&&left<N)//合并剩余元素
{
b[t++]=a[left++];
}
while(right<pos+2*length&&right<N)
{
b[t++]=a[right++];
}
pos+=2*length;
}
}
7-2 链式基数排序 (20分)
实现链式基数排序,待排序关键字n满足1≤n≤1000,最大关键字数位≤5。
输入样例:
第一行输入待排序个数n(1≤n≤1000),再输入n个数(n的数位≤5)。
10
278 109 63 930 589 184 505 269 8 83
输出样例:
输出每趟分配-收集后链表中的关键字,趟数为序列中最大值的数位(如样例中930的数位为3),每行结尾有空格。
930 63 83 184 505 278 8 109 589 269
505 8 109 930 63 269 278 83 184 589
8 63 83 109 184 269 278 505 589 930
#include<iostream>
#include<malloc.h>
using namespace std;
//链式队列的节点结构,模拟桶
struct Node
{
int data;//数据域
Node *next;//指针域
};
//定义程序所需的特殊队列
class Queue
{
private:
Node *front;//链式对列的头指针
Node *rear;//链队的尾指针
public:
//构造函数,初始化队列(带头结点的链式队列)
Queue()
{
//开始先构造一个空结点,没有数据元素存储
Node *p = new Node;
p->data = 0;
p->next = NULL;
//开始是空链队,首尾指针分别去指向队头结点
front = p;
rear = p;
}
//析构函数,销毁链队的结点占据的内存
~Queue()
{
Node *p = front;
Node *q;
while (p != NULL)
{
q = p;
p = p->next;
delete q;
}
}
//入队函数,从尾进入,节点不存在,需要自行创建结点
void push(int e)
{
Node *p = new Node;
p->data = e;
p->next = NULL;
rear->next = p;
rear = p;
}
//入队函数重载,尾进入,节点原来就存在的函数,不需要再新建结点和存储结点的内容
void push(Node *p)
{
p->next = NULL;
rear->next = p;
rear = p;
}
//求数据元素的最大位数的函数,也就是求出需要分配和收集的次数
int lengthData()
{
int length = 0;
int n = 0;
int d;
//指示指针
Node *p = front->next;
//遍历
while (p != NULL)
{
d = p->data;
while (d > 0)
{
d /= 10;
n++;
}
p = p->next;
if (length < n)
{
length = n;
}
n = 0;
}
return length;
}
//判断队列是否为空
bool empty()
{
if (front == rear)
{
return true;
}
return false;
}
//清除队列中的元素
void clear()
{
front->next = NULL;
rear = front;
}
//输出队列中的元素
void print(Queue &que)
{
Node *p = que.front->next;
while (p != NULL)
{
cout << p->data << " ";
p = p->next;
}
}
//基数排序过程
void RadixSort(Queue& que)
{
Queue *arr[10];
for (int i = 0; i < 10; i++)
{
arr[i] = new Queue;
}
int maxLen = que.lengthData();
int d = 1;
for (int i = 0; i < maxLen; i++)
{
Node *p = que.front->next;
Node *q;
int k;
while (p != NULL)
{
k = (p->data / d) % 10;
q = p->next;
arr[k]->push(p);
p = q;
}
que.clear();
for (int i = 0; i < 10; i++)
{
if (!arr[i]->empty())
{
Node *p = arr[i]->front->next;
Node *q;
while (p != NULL)
{
q = p->next;
que.push(p);
p = q;
}
}
}
for (int i = 0; i < 10; i++)
{
arr[i]->clear();
}
d *= 10;
//输出每一趟队列中排好序的元素
print(que);
cout<<endl;
}
}
};
int main(void)
{
Queue queue;
int i,n;
cin>>n;
//顺序输入元素
while (n>0)
{
cin>>i;
queue.push(i);
n--;
}
//基数排序
queue.RadixSort(queue);
return 0;
}