数据结构.docx

上传人:b****8 文档编号:10497801 上传时间:2023-02-14 格式:DOCX 页数:70 大小:69.42KB
下载 相关 举报
数据结构.docx_第1页
第1页 / 共70页
数据结构.docx_第2页
第2页 / 共70页
数据结构.docx_第3页
第3页 / 共70页
数据结构.docx_第4页
第4页 / 共70页
数据结构.docx_第5页
第5页 / 共70页
点击查看更多>>
下载资源
资源描述

数据结构.docx

《数据结构.docx》由会员分享,可在线阅读,更多相关《数据结构.docx(70页珍藏版)》请在冰豆网上搜索。

数据结构.docx

数据结构

**********************************************************************

1、排序

**********************************************************************

内排序与外排序:

内排序是指在排序期间数据对象全部存放在内存的排序;外排序是指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。

################################################

快速排序(QuickSort)

快速排序方法的基本思想:

是任取待排序对象序列中的某个对象(例如取第一个对象)作为基准,按照该对象的关键码大小,将整个对象序列划分为左右两个子序列:

左侧子序列中所有对象的关键码都小于或等于基准对象的关键码;

右侧子序列中所有对象的关键码都大于基准对象的关键码;

基准对象则排在这两个子序列中间(这也是该对象最终应安放的位置)。

然后分别对这两个子序列重复施行上述方法,直到所有的对象都排在相应位置上为止。

是一种不稳定的排序方法。

快速排序算法的基本特性:

时间复杂度:

O(n*lgn)

最坏:

O(n^2)

空间复杂度:

O(n*lgn)

快速排序算法的描述:

快速排序时基于分治模式处理的,对一个典型子数组A[p...r]排序的分治过程为三个步骤:

1.分解:

A[p..r]被划分为俩个(可能空)的子数组A[p..q-1]和A[q+1..r],使得

A[p..q-1]<=A[q]<=A[q+1..r]

2.解决:

通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]排序。

3.合并。

intpartition(intdata[],intlo,inthi)//引自whatever。

{

intkey=data[lo];

intl=lo;

inth=hi;

while(l

{

while(key<=data[h]&&l

data[l]=data[h];

while(data[l]<=key&&l

data[h]=data[l];

}//如此,小的在前,大的在后,一分为二

data[l]=key;

returnl;

}

*******************************

intpartition(intdata[],intlo,inthi)

{

intkey=data[hi];//以最后一个元素,data[hi]为主元

inti=lo-1;

for(intj=lo;j

{

if(data[j]<=key)

{

i=i+1;

swap(&data[i],&data[j]);

}

}

swap(&data[i+1],&data[hi]);//不能改为swap(&data[i+1],&key)

returni+1;

}

**********************************

intpartition(intdata[],intlo,inthi)//请读者思考

{

intkey=data[hi];//以最后一个元素,data[hi]为主元

inti=lo-1;

for(intj=lo;j<=hi;j++)//现在,我让j从lo指向了hi,不是hi-1。

{

if(data[j]<=key)

{

i=i+1;

swap(&data[i],&data[j]);

}

}

//swap(&data[i+1],&data[hi]);//去掉这行

returni;//返回i,非i+1.

}

//////////////////////////////////////////////////

voidswap(int*a,int*b)

{

inttemp=*a;

*a=*b;

*b=temp;

}

//然后是,调用partition,对整个数组进行递归排序:

voidQuickSort(intdata[],intlo,inthi)

{

if(lo

{

intk=partition(data,lo,hi);

QuickSort(data,lo,k-1);

QuickSort(data,k+1,hi);

}

}

################################################

插入排序(InsertSorting)

插入排序的基本方法是:

每步将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。

直接插入排序的基本思想是:

当插入第i(i>=1)个对象时,前面的v[0],v[1],…,v[i-1]已经排好序。

这时,用v[i]的关键码与v[i-1],v[i-2],…的关键码顺序进行比较,找到插入位置即将v[i]插入,原来位置上的对象向后顺移。

时间复杂度为O(n^2)。

是一种稳定的排序方法。

voidInsertSort(KeyTypear[],intn)

{

for(inti=2;i<=n;++i)

{

if(ar[i]

{

ar[0]=ar[i];

intj=i-1;

do

{

ar[j+1]=ar[j];

--j;

}while(ar[0]

ar[j+1]=ar[0];

}

}

}

折半插入排序基本思想是:

设在顺序表中有一个对象序列v[0],v[1],…,v[n-1]。

其中,v[0],v[1],…,v[i-1]是已经排好序的对象。

在插入v[i]时,利用折半搜索法寻找v[i]的插入位置。

是一个稳定的排序方法。

voidBinaryInsertSort(KeyTypear[],intn)

{

for(inti=2;i<=n;++i)

{

if(ar[i]

{

ar[0]=ar[i];

intleft=1,right=i-1;

while(left<=right)//

{

intmid=(right-left)/2+left;

if(ar[0]

right=mid-1;

else

left=mid+1;

}

for(intj=i;j>=left;--j)

{

ar[j]=ar[j-1];

}

ar[left]=ar[0];

}

}

}

################################################

希尔排序(ShellSort)

该方法的基本思想是:

设待排序对象序列有n个对象,首先取一个整数gap

然后缩小间隔gap,例如取gap=gap/2,重复上述的子序列划分和排序工作。

直到最后取gap==1,将所有对象放在同一个序列中排序为止。

是一个不稳定的排序方法;平均时间复杂度:

O(

voidShellInsert(KeyTypear[],intn,intgap)

{

for(inti=1+gap;i<=n;++i)

{

if(ar[i]

{

ar[0]=ar[i];

intj=i-gap;

do

{

ar[j+gap]=ar[j];

j-=gap;

}while(j>0&&ar[0]

ar[j+gap]=ar[0];

}

}

}

voidShellSort(KeyTypear[],intn)

{

intgap=n/3;

while(gap>=1)

{

ShellInsert(ar,n,gap);

gap=gap==2?

1:

(int)(gap/3);

}

}

################################################

起泡排序(BubbleSort)

起泡排序的基本方法是:

设待排序对象序列中的对象个数为n。

最多作n-1趟,i=1,2,...,n-2。

在第i趟中顺次两两比较v[n-j-1].Key和v[n-j].Key,j=n-1,n-2,...,i。

如果发生逆序,则交换v[n-j-1]和v[n-j]。

voidSwap(KeyType&a,KeyType&b)

{

KeyTypex=a;

a=b;

b=x;

}

voidBubbleSort(KeyTypear[],intn)

{

for(inti=1;i

{

inttag=1;

intj;

for(j=1;j<=n-i;++j)

{

if(ar[j]>ar[j+1])

{

tag=0;

Swap(ar[j],ar[j+1]);

}

}

if(tag==1)break;

tag=1;

for(j=n-i;j>i;--j)

{

if(ar[j]

{

tag=0;

Swap(ar[j],ar[j-1]);

}

}

if(tag==1)break;

}

}

################################################

交换排序(ExchangeSort)

交换排序的基本思想:

是两两比较待排序对象的关键码,如果发生逆序(即排列顺序与排序后的次序正好相反),则交换之,直到所有对象都排好序为止。

################################################

选择排序

选择排序的基本思想是:

每一趟(例如第i趟,i=0,1,…,n-2)在后面n-i个待排序对象中选出关键码最小的对象,作为有序对象序列的第i个对象。

待到第n-2趟作完,待排序对象只剩下1个,就不用再选了。

voidSelectSort(KeyTypear[],intn)

{

for(inti=1;i

{

intk=i;

for(intj=i+1;j<=n;++j)

{

if(ar[k]>ar[j])

{

k=j;

}

}

if(k!

=i)

{

Swap(ar[k],ar[i]);

}

}

}

################################################

锦标赛排序(TournamentTreeSort)

它的思想与体育比赛时的淘汰赛类似。

首先取得n个对象的关键码,进行两两比较,得到n/2个比较的优胜者(关键码小者),作为第一步比较的结果保留下来。

然后对这n/2个对象再进行关键码的两两比较,…,如此重复,直到选出一个关键码最小的对象为止。

structDataNode

{

KeyTypedata;//数据值

intindex;//结点在满二叉树中顺序号

intactive;//参选标志:

=1,参选,=0,不参选

};

intPowerOfTwo(intn)

{

inti=1;

while(i

{

i<<=1;//00000000000000000000000000010000

}

returni;

}

voidUpdateTree(DataNode*tree,intindex)

{

inti=0,j;

if(index%2==0)i=index+1;

elsei=index-1;

tree[i/2]=tree[i];

i=i/2;

while(i>1)

{

if(i%2==0)j=i+1;

elsej=i-1;

if(tree[i].active==1&&tree[j].active==1)

{

if(tree[i].data

{

tree[i/2]=tree[i];

}

else

{

tree[i/2]=tree[j];

}

}

else

{

if(tree[i].active==1)

tree[i/2]=tree[i];

else

tree[i/2]=tree[j];

}

i=i/2;

}

}

voidTournamentSort(KeyTypear[],intn)//7

{

DataNode*tree;

DataNodeitem;

intbottomRowSize=PowerOfTwo(n);//8

intTreeSize=2*bottomRowSize;//16

intloadindex=bottomRowSize;

tree=newDataNode[TreeSize];

inti,j;

for(i=loadindex,j=1;i

{

if(j<=n)

{

tree[i].data=ar[j];

tree[i].active=1;

}else

{

tree[i].active=0;

}

tree[i].index=i;

}

i=loadindex;

while(i>1)

{

j=i;

while(j<2*i)

{

if(tree[j+1].active==0||tree[j].data

tree[j/2]=tree[j];

else

tree[j/2]=tree[j+1];

j+=2;

}

i=i/2;

}

for(i=1;i

?

{

ar[i]=tree[1].data;

tree[tree[1].index].active=0;

UpdateTree(tree,tree[1].index);

}

ar[i]=tree[1].data;

delete[]tree;

}

################################################

堆排序(HeapSort)

利用堆及其运算,可以很容易地实现选择排序的思路。

堆排序分为两个步骤:

第一步,根据初始输入数据,利用堆的调整算法FilterDown()形成初始堆,第二步,通过一系列的对象交换和重新调整堆进行排序。

基于初始堆进行堆排序:

最大堆的第一个对象V[0]具有最大的关键码,将V[0]与V[n]对调,把具有最大关键码的对象交换到最后,再对前面的n-1个对象,使用堆的调整算法FilterDown(0,n-1),重新建立最大堆。

结果具有次最大关键码的对象又上浮到堆顶,即V[0]位置。

再对调V[0]和V[n-1],调用FilterDown(0,n-2),对前n-2个对象重新调整,…。

如此反复执行,最后得到全部排序好的对象序列。

这个算法即堆排序算法,其细节在下面的程序中给出。

时间复杂性为O(nlog2n)。

是一个不稳定的排序方法。

voidFilterDown(KeyTypear[],constintstart,constintHeadOfEnd)

{

inti=start,j=2*i;

ar[0]=ar[i];

while(j<=HeadOfEnd)

{

if(jar[j])++j;

if(ar[0]>=ar[j])break;

ar[i]=ar[j];

i=j;

j=2*i;

}

ar[i]=ar[0];

}

voidHeapSort(KeyTypear[],intn)

{

intpos=n/2;

while(pos>0)

{

FilterDown(ar,pos,n);

--pos;

}

inti=n;

while(i>1)

{

Swap(ar[1],ar[i]);

--i;

FilterDown(ar,1,i);

}

}

################################################

归并排序(MergeSort)

归并,是将两个或两个以上的有序表合并成一个新的有序表。

对象序列initList中有两个有序表V[l]…V[m]和V[m+1]…V[n]。

它们可归并成一个有序表,存于另一对象序列mergedList的V[l]…V[n]中。

这种归并方法称为两路归并(2-waymerging)。

其基本思想是:

设两个有序表A和B的对象个数(表长)分别为al和bl,变量i和j分别是表A和表B的当前检测指针。

设表C是归并后的新有序表,变量k是它的当前存放指针。

当i和j都在两个表的表长内变化时,根据A[i]与B[j]的关键码的大小,依次把关键码小的对象排放到新表C[k]中;

当i与j中有一个已经超出表长时,将另一个表中的剩余部分照抄到新表C[k]中。

时间复杂度为O(nlog2n)。

是一个稳定的排序方法。

归并排序占用附加存储较多,需要另外一个与原待排序对象数组同样大小的辅助数组。

这是这个算法的缺点。

voidMerge(KeyTypear[],KeyTypebr[],constintleft,constintm,constintright)

{

inti=left,j=m+1;

intk=left;

while(i<=m&&j<=right)

{

br[k++]=ar[i]

ar[i++]:

ar[j++];

}

while(i<=m)

{

br[k++]=ar[i++];

}

while(j<=right)

{

br[k++]=ar[j++];

}

for(k=left,i=left;i<=right;++k,++i)

{

ar[i]=br[k];

}

}

voidMergeSort(KeyTypear[],KeyTypebr[],constintleft,constintright)

{

if(left

{

intmid=(right-left)/2+left;

MergeSort(ar,br,left,mid);

MergeSort(ar,br,mid+1,right);

Merge(ar,br,left,mid,right);

}

}

voidMergeSort(KeyTypear[],intn)

{

KeyType*br=newKeyType[n+1];

MergeSort(ar,br,1,n);

delete[]br;

}

################################################

基数排序(RadixSort)

基数排序是采用“分配”与“收集”的办法,用对多关键码进行排序的思想实现对单关键码进行排序的方法

//基数排序(RadixSort)

#defineNUM10

voidRadixSort(KeyTypeArray[],intn,intD)

{

inti,j,k,l=1,d=0;

//分配中间存储空间

int**ppArr=newint*[NUM];

for(i=0;i

{

ppArr[i]=newint[n];

}

intpNum[NUM];

//分趟分配收集

while(d

{

for(i=0;i

{

pNum[i]=-1;

}

for(i=0;i

{

j=(Array[i]/l)%NUM;

k=++pNum[j];

ppArr[j][k]=Array[i];

}

for(k=0,i=0;i

{

for(j=0;j<=pNum[i];j++)

{

Array[k++]=ppArr[i][j];

}

}

d++;

l*=10;

}

}

voidRadixSort(KeyTypear[],intn)

{

RadixSort(ar,n,0);

}

不稳定排序:

快速排序;堆排序;简单选择排序。

 

排序方法

比较次数

移动次数

稳定性

附加存储

最好

最差

最好

最差

最好

最差

直接插入排序

n

n2

0

n2

1

折半插入排序

nlog2n

0

n2

1

起泡排序

n

n2

0

n2

1

快速排序

nlog2n

n2

nlog2n

n2

log2n

n2

简单选择排序

n2

0

n

1

锦标赛排序

nlog2n

nlog2n

n

堆排序

nlog2n

nlog2n

1

归并排序

nlog2n

nlog2n

n

希尔排序

n2

 

************************

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 互联网

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1