1.分析排序方法的时间代价标准是什么?
个人想法:以时间复杂度来衡量,标准是相同数据规模下对应的时间复杂度。通常排序元素的比较和交换消耗时间。
解析:排序方法的时间代价包括排序码的比较次数和元素的移动次数。此外还需注意:
- 选用元素中不同的数据项做排序码,会影响比较时间。例如复合项还是简单项,整数还是字符串。
- 待排序元素的初始排列对某些排序方法是有影响的。
- 待排序元素个数n也影响排序算法的估计。当n很大,可用O估计;当n很小时,可精确估计执行频度
2.为什么元素的移动比排序码比较更费时间
个人理解:元素移动通常是两个元素交换位置,相比 比较,明显耗时。
比如 swap(int a,int b){a^=b;b^=a;a^=b} 和 a>b一比,明显比较用时少
解析:通常,系统数据处理时元素的体积大,存取时间比单纯提取排序码耗费的时间多。不同的排序算法,即使排序码比较次数相同,但元素的移动次数大多不同。
3.元素的移动次数与哪些因素有关
个人理解:移动次数与排序算法的策略有关,同时受到元素的有序度,数据规模的影响
解析:元素的移动次数与排序方法的选择、待排序元素的初始序列有关。静态链表排序避免了数据移动,但是增加了指针空间
4.排序方法的稳定受什么影响
个人理解:排序后相同元素的相对位置是否发生改变
解析:(1)交换导致两个排序码相等的元素发生相对应位置的前后颠倒
(2).排序中,需以较大的间隔互换数据,或者数据隔空搬运一段较大距离,排序必定不稳定。它可能会把原先排在前面的元素搬到具有相同排序码的另一元素的后面,颠倒了具有相同排序码的不同元素的相对前后位置(原文太长,简述)
5.稳定的排序方法为甚什么不一定比不稳定的排序方法好
个人理解:排序方法的稳定指的是排序后相同元素的相对位置是否发生改变。
稳定与否只代表了一种排序结果,不能称之为好坏。
即使在好的排序方法,在面对特定的数据情况,比如数据很少,虽然排序方法差(比如插入,冒泡,选择),但比所谓好的算法(例如归并,快排)用时也没差别。又比如,数据大致有序,使用快排就效果很差。
解析:稳定的排序方法让原来排在前面的元素在排序后仍排在具有相同排序码的其他元素前面。许多稳定的算法,时间或空间代价较高。
例如,稳定:插入,冒泡的空间低时间高;归并的时间低空间高;
不稳定:快排,堆排序,希尔排序的时空都低
所以要根据场合选用适合的排序方法
6.什么是原地排序
个人理解:排序中,不使用额外辅助空间的排序
解析:不使用多于O(1)的附加存储空间进行的排序。非原地的,例如快排和归并排序。
7.排序方法一般适用于何种数据结构
个人理解:通常用于顺序表,数组
解析:
适合顺序表的排序,例如,折半插入,希尔排序,冒泡排序,快速排序,简单选择排序,归并排序,计数排序,奇偶排序等。
适合单链表:直接插入,冒泡排序,简单选择,归并,基数
适合树形:锦标赛排序(胜者树),多路归并(败者树),二叉查找树,堆排序
8.从排序过程中数据总体变化趋势来看,排序方法分为两大类:一是有序区增长,二是有序程度增长。请说明其实现机制,并对已知的排序方法归类
个人理解:
有序区:直接插入,希尔,归并,基数
有序程度:简单选择,冒泡,快排,堆排序
解析:(1)有序区增长:将数据表分为有序区和无序区,在排序过程中逐步扩大排序有序区,缩短无序区。直到有序区扩大到整个数据表为止,如插入排序、选择排序、冒泡排序、堆排序、归并排序
(2)有序程度增长:数据表不能明确区分有序区和无序区,随着排序过程的执行,逐步调整表中元素的排列,使得表中的有序程度不断增长,直到完全有序,如快速排序、希尔排序、基数排序
9.设一个栈的输入序列为1,2,……,n。编写算法判断序列p1,p2,p3……pn是否是一个合理的栈输出序列。
个人思路:挨个试?不行。没思路
解析:当预期输出序列的数据比当前栈顶的数据元素小时,必定出现输出不合理。
出栈序列中,元素i之后所有比i小的元素间必须是降序排列的。
栈顶如果是需要出栈的元素,则出栈,如果不是则将未入栈的元素按入栈序列依次入栈,直到栈顶为出栈的元素。如果所有元素都入栈了,仍然没有找到要弹出的元素,那么该出栈序列一定不是合法的。
void Decision(int p[],int n){
SeqStack S; InitStack(S);
bool s=true;
int i=0,k=0,j;
do{
if(StackEmpty(S)||GetTop(S)<p[k]) Push(S,++i);
else if(!StackEmpty(S) && GetTop(s)==P[K]){
j=Pop(S);k++;}
else if(GetTop(S)>p[k]){s=false;break;}
}while(k<n);
for(j=0;j<n;j++) printf("%d",p[j]);
if(s) printf("true");
else printf("false");
}
10.改写顺序栈的进栈函数Push(x),要求当栈满时执行一个stackFull()操作进行溢出处理。其功能是:动态创建一个比原来的栈数组大一倍的新数组,代替原来的栈数组,原来栈数组中的元素占据新数组的前maxSize个位置。
个人思路:可以考虑copy原数组内容,存入新数组。
void StackFull(SeqStack& S){
SelemType *tep=(SElemType*)malloc(2*S.maxSize*sizeof(SelemType));
if(temp==NULL) {printf("save error");} //将原数组内容复制到新数组
for(int i=0;i<=S.top;i++) temp[i]=S.elem[i];
free(S.elem); //删除原数组
S.maxSize=2*S.maxSize; //扩容
S.elem=temp;
}
void Push(SeqStack& S,SElemType x){
if(S.top==S.maxSize-1) StackFull(S); //栈满做溢出处理
S.elem[++S.top]=x; //进栈
}