说明
- 本文参照严蔚敏《数据结构(C语言版)题集》一书中包含的问答题和算法设计题目,提供解答及算法的解决方案。
- 请读者在自己已经解决了某个题目或进行了充分的思考之后,再参考本解答,以保证复习效果。
- 由于作者水平所限,本解答中一定存在不少这样或者那样的错误和不足,希望读者们在阅读中多动脑、勤思考,争取发现和纠正这些错误,写出更好的算法来。
2.11 设顺序表va中的数据元素递增有序
试写一算法,将x插入到顺序表的适当位置上,以保持该表的有序性。
解:
此题的算法思想:
(1) 查找 x x x在顺序表 a . e l e m [ a . l e n g t h ] a.elem[a.length] a.elem[a.length]中的插入位置,即求满足 a . e l e m [ i ] ≤ x < a . e l e m [ i + 1 ] a.elem[i]\le{x}<a.elem[i+1] a.elem[i]≤x<a.elem[i+1],
e l e m [ i + 1 ] elem[i+1] elem[i+1]的 i i i值( i i i的初值为 a . l e n g t h − 1 a.length-1 a.length−1);
(2) 将顺序表中的 a . l e n g t h − i − 1 a.length-i-1 a.length−i−1个元素 a . e l e m [ i + 1 ⋯ a . l e n g t h − 1 ] a.elem[i+1\cdots{a.length-1}] a.elem[i+1⋯a.length−1]后移一个位置;
(3) 将 x x x插入到 e . e l e m [ i + 1 ] e.elem[i+1] e.elem[i+1]中且将表长 a . l e n g t h a.length a.length加 1 1 1。
上述算法正确执行的参数条件为: 0 ≤ a . l e n g t h < a . l i s t s i z e 0\le{a.length}<a.listsize 0≤a.length<a.listsize。
算法的伪代码如下:
c
Status InsertOrderList(SqList &a,ElemType x)
{
// 顺序表a中的元素依值递增有序,本算法将x插入其中适当位置
// 以保持其有序性。入口断言:0<=a.length<a.listsize
if(a.length==a.listsize) return (OVERFLOW);
else{
i=a.length-1;
while(i>=0&&x<a.elem[i]) i--; // 查找x的插入位置
// i<0 || x>=a.elem[i]
for(j=a.length-1;j>=i+1;j--)
a.elem[j+1] = a.elem[j]; // 元素后移
a.elem[i+1]=x; // 插入x
a.length++; // 表长加1
return OK;
}
} // InsertOrderList
注:
(1) 算法中设置的断言表明以下程序代码正确执行时所要求满足的参数条件,或表明以上程序代码执行后所达到的变量状态;
(2) 在while循环中,条件与&&采用类C的定义,其作用是避免当i<0时,发生数组a.elem越界的错误;
(3) 注意上述算法在a.length=0时也能正确执行;
(4) 可以将上述算法中元素后移的动作并入查找while循环中一起完成。即删去上述算法中的for循环语句,且将while循环语句改为下列形式:
c
while(i>=0&&x<a.elem[i]){
a.elem[i+1]=a.elem[i];
i--;
}
这里实现该算法时,完全遵照原书中的类型和数据结构,并提供随机初始化,调用stdlib库提供的qsort算法便于测试。
关于为什么要用链表常用的开辟方法来开辟和拓展顺序存储的数组,作者本人一开始也觉得不解,
后来发现不仅可以用链表解决超长数组,还可以用数组来灵活表达链表,具体如何实现,下回分解。
c
#include<stdio.h>
#include<stdlib.h>
#include<time.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
#define MAX_TEST_LENGTH 123
#define MAX_TEST_ELEM 1000
typedef int ElemType;
typedef struct{
ElemType *elem; // 存储空间基址
int length; // 当前长度
int listsize; // 当前分配的存储容量
} SqList; // 顺序表类型
typedef struct LNode{
ElemType data;
struct LNode *next;
} LNode, *LinkList; // 线性链表类型
Status InitList_Sq(SqList *pL){
// 构造一个空的线性表
(*pL).elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
if(!(*pL).elem) exit(OVERFLOW); // 存储分配失败
(*pL).length = 0; // 空表长度为0
(*pL).listsize = LIST_INIT_SIZE; // 初始存储容量
return OK;
}// InitList_Sq
Status ListInsert_Sq(SqList *pL, int i, ElemType e){
// 在顺序线性表L中第i个位置之前插入新的元素e
// i的合法值范围:[1,ListLength_Sq(L)+1]
if(i<1 || i>((*pL).length+1)) return ERROR; // i值不合法
if((*pL).length>=(*pL).listsize){ // 当前存储空间已满,增加分配
ElemType *newbase = (ElemType *)realloc((*pL).elem,((*pL).listsize+LISTINCREMENT)*sizeof(ElemType));
if(!newbase) exit(OVERFLOW); // 存储分配失败
(*pL).elem = newbase; // 新基址
(*pL).listsize += LISTINCREMENT; // 增加存储容量
}
ElemType *p = NULL;
ElemType *q = &((*pL).elem[i-1]); // q为插入位置
for(p=&((*pL).elem[(*pL).length-1]);p>=q;--p) *(p+1) = *p; // 插入位置及之后的元素右移
*q = e; // 插入e
++((*pL).length); // 表长增1
return OK;
}// ListInsert_Sq
Status FreeList_Sq(SqList *pL){
// 释放线性表
if(NULL!=(*pL).elem){
free((*pL).elem);
return OK;
}else{
return ERROR;
}
}// FreeList_Sq
int cmp(const void *x,const void *y){
// qsort函数需要调用的比较函数
ElemType *a=(ElemType *)x;
ElemType *b=(ElemType *)y;
return (*a-*b);
}
Status rand_init_sorted_list(SqList *pL){
int pos;
time_t t;
int count = MAX_TEST_LENGTH;
if(OK!=InitList_Sq(pL)) return ERROR;
srand((unsigned)time(&t)); //初始化随机数发生器
while(count--){
if(OK!=ListInsert_Sq(pL,1+rand()%((*pL).length+1),(rand()%MAX_TEST_ELEM)))
return ERROR; // 随机找一个合法位置插入新随机元素
}
qsort((*pL).elem,(*pL).length,sizeof(ElemType),cmp);
return OK;
}
void display_list(SqList L){
int i;
for(i=1;i<=L.length;i++){
printf("%3d.%d\t",i-1,L.elem[i-1]);
if(i%7==0) putchar('\n');
}
}
int InsertOrderSqList(SqList *pL,int x){
//把x插入递增有序表pL中,并返回插入的位置(数组下标)
int i;
if((*pL).length+1>(*pL).listsize) return OVERFLOW;
(*pL).length++;
for(i=(*pL).length-1;(*pL).elem[i]>x&&i>=0;i--)
(*pL).elem[i+1]=(*pL).elem[i];
(*pL).elem[i+1]=x;
return i+1;
}//InsertOrderSqList
int main(){
ElemType x;
SqList L;
if(OK==rand_init_sorted_list(&L)){
display_list(L);
printf("\nInput an integer x:");
scanf("%d",&x);
printf("\nInsert x into list(keep order):\n");
printf("\nInserted elem[%d]=%d\n",InsertOrderSqList(&L,x),x);
printf("\nAfter insert:\n");
display_list(L);
if(OK==FreeList_Sq(&L))
printf("\nFree List success!\n");
}
return 0;
}