10.23② 试以L.r[k+1]作为监视哨改写教材10.2.1节
中给出的直接插入排序算法。其中,L.r[1..k]为待排
序记录且k<maxsize。
实现下列函数:
void InsertSort(SqList &L);
顺序表的类型SqList定义如下:
typedef struct {
KeyType key;
…
} RedType;
typedef struct {
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length;
} SqList;
void InsertSort(SqList &L)
{
int i,j;
for(i=2;i<=L.length;++i){
if(LT(L.r[i],L.r[i-1])){
L.r[L.length+1]=L.r[i];
L.r[i]=L.r[i-1];
for(j=i-2;LT(L.r[L.length+1],L.r[j]);--j){
L.r[j+1]=L.r[j];
}
L.r[j+1]=L.r[L.length+1];
}
}
}
10.26② 如下所述改写教科书1.4.3节中的起泡排序算法:
将算法中用以起控制作用的布尔变量change改为一个整型变
量,指示每一趟排序中进行交换的最后一个记录的位置,并
以它作为下一趟起泡排序循环终止的控制值。
实现下列函数:
void BubbleSort(SqList &L);
/* 元素比较和交换必须调用以下比较函数和交换函数:*/
/* Status LT(RedType a, RedType b); 比较:”<" */
/* Status GT(RedType a, RedType b); 比较:">” */
/* void Swap(RedType &a, RedType &b); 交换 */
顺序表的类型SqList定义如下:
typedef struct {
KeyType key;
…
} RedType;
typedef struct {
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length;
} SqList;
比较函数和交换函数:
Status LT(RedType a, RedType b); // 比较函数:”<"
Status GT(RedType a, RedType b); // 比较函数:">”
void Swap(RedType &a, RedType &b); // 交换函数
/* 元素比较和交换必须调用如下定义的比较函数和交换函数:*/
/* Status LT(RedType a, RedType b); 比较:"<" */
/* Status GT(RedType a, RedType b); 比较:">" */
/* void Swap(RedType &a, RedType &b); 交换 */
//不知道为什么,compare正常,但swap一直为0
//终于发现原因了,原来这里的Swap是大写的,如果小写的话,可以通过,但是最终swap为 0
{
int len=L.length,last=0;
int i;
while(len>1){
for(i=1;i<len;++i){
if(GT(L.r[i],L.r[i+1])){
Swap(L.r[i],L.r[i+1]);
last=i;
}
}
if(len!=last){
len=last;
}
else{
break;
}
}
}
10.32⑤ 荷兰国旗问题:设有一个仅由红、白、兰
这三种颜色的条块组成的条块序列。请编写一个时
间复杂度为O(n)的算法,使得这些条块按红、白、
兰的顺序排好,即排成荷兰国旗图案。
实现下列函数:
void HFlag(FlagList &f)
/* “荷兰国旗”的元素为red,white和blue,*/
/* 分别用字符’0′,’1′和’2′表示 */
“荷兰国旗”的顺序表的类型FlagList定义如下:
#define red ’0′
#define white ’1′
#define blue ’2′
typedef char ColorType;
typedef struct {
ColorType r[MAX_LENGTH+1];
int length;
} FlagList;
//如果为0则存放在线性表左端,如果为2则存放在线性表右端
void HFlag(FlagList &f)
{
ColorType t;
int i=1,low=1,high=f.length;
while(f.r[low]==\'0\'){ //找到第一个不为0的位置
++low;
++i;
}
while(f.r[high]==\'2\'){ //找到倒数第一个不为2的结点
--high;
}
while(i<=high){
if(f.r[i]==\'0\'&&low!=i){//如果为0,则与low交换,low!=i的判断极为关键
t=f.r[i];
f.r[i]=f.r[low];
f.r[low]=t;
++low;
}
else if(f.r[i]==\'2\'){//如果为2,则与high交换
t=f.r[i];
f.r[i]=f.r[high];
f.r[high]=t;
--high;
}
else{
++i;
}
while(f.r[low]==\'0\'){ //找到第一个不为0的位置
++low;
}
while(f.r[high]==\'2\'){ //找到倒数第一个不为2的结点
--high;
}
}
}
10.34③ 已知(k1,k2,…,kp)是堆,则可以写一个时
间复杂度为O(log(n))的算法将(k1,k2,…,kp,kp+1)
调整为堆。试编写”从p=1起,逐个插入建堆”的算法,
并讨论由此方法建堆的时间复杂度。
实现下列函数:
void CreateHeap(HeapType &h, char *s);
堆(顺序表)的类型HeapType定义如下:
typedef char KeyType;
typedef struct {
KeyType key;
… …
} RedType;
typedef struct {
RedType r[MAXSIZE+1];
int length;
} SqList, HeapType;
基本思路:
题目要求用逐个插入建堆的算法进行建堆,刚看题目莫名奇妙,
把书上调整大顶堆的算法抄上去,没想到这天杀的题目也提示下这个是小顶堆...
仔细看清题目之后,发现这道题目很简单。
假设当前堆已经是小顶堆,当有新的叶子时,
只需要跟它的双亲结点的key值比较,
如果比双亲的key小则交换
一直交换到跟结点。
*/
//堆调整函数
void HeapAdjust(HeapType &h,int s,int m){
int j;
KeyType temp;
for(j=m;j>s;j/=2){
if(h.r[j].key<h.r[j/2].key){//如果比双亲结点小,则交换
temp=h.r[j].key;
h.r[j].key=h.r[j/2].key;
h.r[j/2].key=temp;
}
}
}
void CreateHeap(HeapType &h, char *s)
{
int i;
h.length=0;
while(s[i]!=\'\0\'){//逐个插入
++h.length;
h.r[h.length].key=s[i];
HeapAdjust(h,1,h.length);//调整堆
++i;
}
}
10.35③ 假设定义堆为满足如下性质的完全三叉树:
(1) 空树为堆;
(2) 根结点的值不小于所有子树根的值,且所有子树
均为堆。
编写利用上述定义的堆进行排序的算法,并分析推导
算法的时间复杂度。
实现下列函数:
void HeapSort(HeapType &h);
堆(顺序表)的类型HeapType定义如下:
typedef char KeyType;
typedef struct {
KeyType key;
… …
} RedType;
typedef struct {
RedType r[MAXSIZE+1];
int length;
} SqList, HeapType;
比较函数和交换函数:
Status LT(RedType a, RedType b)
{ return a.key<b.key ?="" true="" :="" false;="" }<br=""> Status GT(RedType a, RedType b)
{ return a.key>b.key ? TRUE : FALSE; }
void Swap(RedType &a, RedType &b)
{ RedType c; c=a; a=b; b=c; }
解题思路:
近视、眼花,以为题目说的跟书上的一样,又是直接抄上去,结果老是不对
研究后发现,题目说的是完全三叉树....
随便列举一棵完全三叉树,仔细观察可以发现,
若双亲的序号为i,则左、中、右子树为3i-1,3i,3i+1;
模仿完全二叉树算法即可轻松得出算法
主要区别在于参数的变化还有三个子树的比较,特别是j<m和j<m-1的判断,
如果没有判断则会导致compare次数与答案不同(条件判断顺序从左到右)
*/
void HeapAdjust(HeapType &h,int s,int m){
int j;
RedType rc;
rc.key=h.r[s].key;
for(j=s*3-1;j<=m;j=3*j-1){
if(j<m&<(h.r[j],h.r[j+1])){
++j;
if(j<m&<(h.r[j],h.r[j+1])){
++j;
}
}
else if(j<m-1&<(h.r[j],h.r[j+2])){
j+=2;
}
if(!LT(rc,h.r[j])){
break;
}
h.r[s]=h.r[j];
s=j;
}
h.r[s]=rc;
}
void HeapSort(HeapType &h)
/* 元素比较和交换必须调用以下比较函数和交换函数:*/
/* Status LT(RedType a, RedType b); 比较:"<" */
/* Status GT(RedType a, RedType b); 比较:">" */
/* void Swap(RedType &a, RedType &b); 交换 */
{
int i;
if(h.length){
for(i=(h.length+1)/3;i>0;--i){
HeapAdjust(h,i,h.length);
}
for(i=h.length;i>1;--i){
Swap(h.r[1],h.r[i]);
HeapAdjust(h,1,i-1);
}
}
}
10.42④ 序列的”中值记录”指的是:如果将此序列排序
后,它是第n/2个记录。试写一个求中值记录的算法。
实现下列函数:
KeyType MidElement(SqList &L);
顺序表的类型SqList定义如下:
typedef struct {
KeyType key;
…
} RedType;
typedef struct {
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length;
} SqList;
//效率很低的解法:用另外一个线性表储存本来的元素
//然后再用效率很低的选择排序
//最后之间比较
//估计存在一种边排序边计算的方法,有空再研究~
KeyType MidElement(SqList &L)
{
int i,j;
SqList M;
RedType t;
if(!L.length){
return \'#\';
}
for(i=1;i<=L.length;++i){
M.r[i]=L.r[i];
}
for(i=1;i<=L.length;++i){
for(j=1;j<=L.length;++j){
if(L.r[i].key>L.r[j].key){
t=L.r[i];
L.r[i]=L.r[j];
L.r[j]=t;
}
}
}
for(i=1;i<=L.length;++i){
if(M.r[i].key==L.r[L.length/2+1].key){
return M.r[i].key;
}
}
return \'#\';
}
10.43③ 已知记录序列a[1..n] 中的关键字各不相同,
可按如下所述实现计数排序:另设数组c[1..n],对每
个记录a[i], 统计序列中关键字比它小的记录个数存
于c[i], 则c[i]=0的记录必为关键字最小的记录,然
后依c[i]值的大小对a中记录进行重新排列,试编写算
法实现上述排序方法。
实现下列函数:
void CountSort(SqList &L);
/* 采用顺序表存储结构,L.r存储序列a,L.length为n */
/* 在函数内自行定义计数数组c */
顺序表的类型SqList定义如下:
typedef struct {
KeyType key;
…
} RedType;
typedef struct {
RedType r[MAXSIZE+1]; // r[0]闲置或用作哨兵单元
int length;
} SqList;
/* 采用顺序表存储结构,L.r存储序列a,L.length为n */
/* 在函数内自行定义计数数组c */
{
RedType temp[100];
int c[30];
int i,j;
for(i=1;i<=L.length;++i){//初始化计数数组
c[i]=0;
temp[i]=L.r[i];
}
for(i=1;i<=L.length;++i){//统计数据
for(j=1;j<=L.length;++j){
if(L.r[j].key<L.r[i].key){
++c[i];
}
}
}
for(i=0,j=1;i<=L.length-1;++i){
for(j=1;j<=L.length;++j){
if(c[j]==i){//找到排序后第i+1个元素,位置为j
L.r[i+1]=temp[j];
}
}
}
}