数据结构题集-第二章-线性表-算法设计题二

说明

  • 本文参照严蔚敏《数据结构(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;
}
相关推荐
tinker在coding21 分钟前
Coding Caprice - Linked-List 1
算法·leetcode
XH华5 小时前
初识C语言之二维数组(下)
c语言·算法
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
不想当程序猿_5 小时前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯
落魄君子5 小时前
GA-BP分类-遗传算法(Genetic Algorithm)和反向传播算法(Backpropagation)
算法·分类·数据挖掘
菜鸡中的奋斗鸡→挣扎鸡6 小时前
滑动窗口 + 算法复习
数据结构·算法
Lenyiin6 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
郭wes代码6 小时前
Cmd命令大全(万字详细版)
python·算法·小程序
scan7246 小时前
LILAC采样算法
人工智能·算法·机器学习
菌菌的快乐生活6 小时前
理解支持向量机
算法·机器学习·支持向量机