数据结构单链表排序及通用排序模板.docx

上传人:b****6 文档编号:8157148 上传时间:2023-01-29 格式:DOCX 页数:18 大小:22.44KB
下载 相关 举报
数据结构单链表排序及通用排序模板.docx_第1页
第1页 / 共18页
数据结构单链表排序及通用排序模板.docx_第2页
第2页 / 共18页
数据结构单链表排序及通用排序模板.docx_第3页
第3页 / 共18页
数据结构单链表排序及通用排序模板.docx_第4页
第4页 / 共18页
数据结构单链表排序及通用排序模板.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

数据结构单链表排序及通用排序模板.docx

《数据结构单链表排序及通用排序模板.docx》由会员分享,可在线阅读,更多相关《数据结构单链表排序及通用排序模板.docx(18页珍藏版)》请在冰豆网上搜索。

数据结构单链表排序及通用排序模板.docx

数据结构单链表排序及通用排序模板

数据结构——单链表排序

昨天晚上写了个单链表排序功能的函数,没想到数据结构课只是过了一学期,写单链表数据结构的函数就遇到太多问题。

唉,老师,我对不起你啊。

我所要写的函数的程序是以单链表结构进行组织,无空头节点。

要求可以按节点里的某个属性作为key大小排序。

最开始,我并没回想到这个单链表交换位置,需要以指针进行移动。

事实上,潜意识认为,只要将指针的值进行交换,即可(完全忘了单链表的知识了)。

因为很自然的想成,链表是通过指针进行寻找节点的,交换了指针,就相当于交换节点顺序。

貌似没有问题,所以我编写了如下函数(为了卖弄下,我还挑了个麻烦的快速排序方法,而不是后来简单的冒泡排序):

voidQuickSort(structbook*head_book,intlow,inthigh)

{

staticintcount=1;

inti=low,j=high;

structbook*temp_ptr_book,*iptr_book,*jptr_book;

temp_ptr_book=GetPtr_book(head_book,low);

iptr_book=GetPtr_book(head_book,i);

jptr_book=GetPtr_book(head_book,j);

if(i

{

while(i

while(i=GetKey(jptr_book))

{jptr_book=GetPtr_book(head_book,j);j--}

if(i

while(i

{iptr_book=GetPtr_book(head_book,i);i++;}

if(i

}

iptr_book=temp_ptr_book;

QuickSort(head_book,low,i-1);

QuickSort(head_book,i+1,high);

}

}

运行结果却发现根本没有排序。

因为上面的想法是大错的,我将指针的值进行交换,并未改变节点的交换。

指针的值是一个地址,交换值,只改变了指针所指向的是那个节点,但节点之间是靠指针联系的,交换指针值,根本没有任何作用。

链表还是那个链表,一点也没有改变。

那么就对节点进行修改就好了。

确实这样做了,写了个类似拷贝构造函数,但是测试还是有问题,为什么?

因为节点本身是有指向下一个节点的指针的,交换后怎么修改指针呢?

顺着想下去,是不是可以这样想,我不改变链表节点的本身的顺序(即指向下一个节点的指针的值不改变),把节点的值进行交换(赋值),这样也是进行排序了。

但是无奈能力太差,不知哪里写的有问题,测试结果出现指针异常。

(即使成功如果节点数据太多,拷贝过去这样的时间代价也是极大的!

最后有解决方法比这样更好,所以就没去再找这个问题的原因,但从似乎逻辑上这样是可行的。

)实在厌烦了,还是先试试简单的冒泡排序吧。

但是没想到冒泡排序也出现了问题。

记得学单链表的时候,交换节点只要一定顺序三次赋值就可以了,但是测试结果,排序结果第一遍就没走完,数据竟然遗失了。

又得仔细找原因,后来才发现,一般冒泡排序,是针对基本数据类型或对象的,指针冒泡有些细节仍然要注意:

每轮冒泡都是从头节点开始的,但是头节点可能会改变呀。

但是我们每次冒泡是都是直接赋值最开始的那个头节点,这无疑会出现问题。

普遍冒泡排序方法如下:

//冒泡排序

template

voidBubbleSort(sortlist&table)

{

inti=1;intfinish=0;

cout<<"冒泡排序结果:

\n";

cout<<"初始序列:

";table.Show();cout<

while(i

finish)

{

finish=1;//交换标志

for(intj=0;j

if(table.Arr[j].GetKey()>table.Arr[j+1].GetKey())

{

table.Swap(table.Arr[j],table.Arr[j+1]);

finish=0;//已交换

}

cout<<"第"<

";

table.Show();cout<

i++;

}

}

for(intj=0;j

那么需要怎么解决?

,显然我们需要增加一个空头节点,这样头节点的交换就没有问题了。

现在给出一般的指针冒泡排序算法(C语言):

//冒泡排序

structbook*BubbleSort(structbook*head_book){

intfinish=0;

intsize_book=sizeof(structbook);

structbook*NullH_book=(structbook*)malloc(size_book);//增加一个空头节点

NullH_book->book_next=head_book;

structbook*tail=NULL;

//structbook*j1_ptr_book=head_book->book_next;

while(NullH_book->book_next!

=tail&&!

finish)

{

finish=1;//交换标志

structbook*pre_book=NullH_book;

structbook*cur_book=pre_book->book_next;

while(cur_book!

=tail&&cur_book->book_next!

=tail){

if(GetKey(cur_book)book_next))

{

pre_book->book_next=cur_book->book_next;

cur_book->book_next=cur_book->book_next->book_next;

pre_book->book_next->book_next=cur_book;

finish=0;//已交换

}

pre_book=pre_book->book_next;

cur_book=pre_book->book_next;

}tail=cur_book;

}

returnNullH_book->book_next;

}

貌似问题解决了,但是这里只给出了冒泡排序,我们知道冒泡排序算法的时间上界为O(n2),即使,我增加了交换标志,可以改进一些,但是我们仍然像可不可以有更好的方法提高排序效率。

你也知道当然存在更好的算法,比如之前的快速排序,此外还有:

直接插入排序,简单选择排序,堆排序,二路归并排序等等。

我们是不是能够也对单链表排序呢?

但是有一个问题,还是指针问题,冒泡是对相邻的节点交换,指针的交换就很麻烦了,还要多设置一个前一个节点的指针。

那么,快速排序呢,是不相邻的节点的赋值(交换),这样的复杂过程,需要设置几个指针,需要怎样移动,要考虑哪些情况。

堆排序情况是怎样的?

归并排序又要怎样写?

也许是有办法的,但想想也很麻烦,单链表操作实在很不好使用这些排序。

是不是真的无法排序呢?

办法还是有的。

能不能利用已经写过的这些函数进行排序?

教材有这些方法的关键代码,课设时也实现过了,但是是对输入的整数,装入一个数组进行排序的,链表节点型的数据怎么排序?

其实,回到最开始的错误想法来看,可以解决这个问题。

如果我存放的是指针数组,每个指针指向链表的一个节点。

可以通过指针找到节点,比较key,再对指针数组进行排序,这样就实现了对节点的排序。

当然只进行这一步,肯定还是错误的,我们还是没对链表进行改变。

所以,最后一步就是,在排好序的基础上,走一轮,将指针的指向的节点看成是独立的节点,修改它的属性中的指向下一节点的指针值为当前数组指针的后一个数组指针。

这样就重新得到了一个单链表。

唉,用进废退,是不变的法则啊,本以为数据结构学的还可以,现在好久不用了就将数据结构的特点给遗忘了。

现在用JAVA,C#,不写C++了指针都用不熟了,经常报错,用C里面的部分方法也出现错误。

花了这么久终于算是解决了。

附:

通用排序模板

#include

#include

usingnamespacestd;

constintMaxSize=100;

template

classelement

{

template

friendclasssortlist;

private:

Typekey;//数据元素关键字

public:

element():

key(0){}//构造函数

TypeGetKey(){returnkey;}//取关键字

voidsetKey(constTypek){key=k;}//修改关键字

element&operator=(element&x){key=x.key;return*this;}//赋值,重载运算符=

};

template

classsortlist{

//templatefriendvoidQuickSort(sortlist&table,intlow,inthigh);也可以

friendvoidInsertionSort(sortlist&table);//直接插入排序

friendvoidBubbleSort(sortlist&table);//冒泡排序

friendvoidSelectSort(sortlist&table);//简单选择排序

friendvoidQuickSort(sortlist&table,intlow,inthigh);//快速排序

template

friendclassMaxHeap;//堆

friendvoidHeapSort(sortlist&table);//堆排序

friendvoidmerge(sortlist&sourceTable,sortlist&mergedTable,

constintleft,constintmid,constintright);//归并

friendvoidMergePass(sortlist&sourceTable,sortlist&mergedTable,

constintlen);//一趟归并

friendvoidMergeSort(sortlist&table);//两路归并

public:

element*Arr;//存储数据元素的向量

intCurrentSize;//数据表中的元素个数

sortlist():

CurrentSize(0){Arr=newelement[MaxSize];}//构造函数

sortlist(constsortlist&sl)//拷贝构造函数

{

Arr=newelement[MaxSize];CurrentSize=sl.CurrentSize;

for(inti=0;i

Arr[i]=sl.Arr[i];

}

~sortlist(){delete[]Arr;}//析构函数

voidSwap(element&x,element&y)//交换x和y

{elementtemp=x;x=y;y=temp;}

voidInsert(constTypek){Arr[CurrentSize].setKey(k);CurrentSize++;}//插入k

voidShow()//显示数据元素

{

for(inti=0;i

cout<

}

};

//直接插入排序---使用监视哨改进需要将第一个空出来,此处不便于其他排序算法的使用,所以不使用

template

voidInsertionSort(sortlist&table)

{

elementtemp;

cout<<"直接插入排序结果:

\n";

cout<<"初始序列:

";table.Show();cout<

intj;

for(inti=1;i

{

temp=table.Arr[i];j=i;

while(j>=0&&temp.GetKey()

{

table.Arr[j]=table.Arr[j-1];

j--;

}

table.Arr[j]=temp;

cout<<"第"<

";

table.Show();cout<

}

}

//冒泡排序

template

voidBubbleSort(sortlist&table)

{

inti=1;intfinish=0;

cout<<"冒泡排序结果:

\n";

cout<<"初始序列:

";table.Show();cout<

while(i

finish)

{

finish=1;//交换标志

for(intj=0;j

if(table.Arr[j].GetKey()>table.Arr[j+1].GetKey())

{

table.Swap(table.Arr[j],table.Arr[j+1]);

finish=0;//已交换

}

cout<<"第"<

";

table.Show();cout<

i++;

}

}

//简单选择排序

template

voidSelectSort(sortlist&table)

{

intk;

cout<<"简单选择排序结果:

\n";

cout<<"初始序列:

";table.Show();cout<

for(inti=0;i

{

k=i;

for(intj=i+1;j

if(table.Arr[j].GetKey()

k=j;//当前最小关键字的位置

if(k!

=i)

table.Swap(table.Arr[i],table.Arr[k]);

cout<<"第"<

";

table.Show();cout<

}

}

//快速排序

template

classQSort

{

public:

voidQuickSort(sortlist&table,intlow,inthigh);

};

template

voidQSort:

:

QuickSort(sortlist&table,intlow,inthigh)

{

staticintcount=1;

if(count==1)

{

cout<<"快速排序结果:

\n";

cout<<"初始序列:

";table.Show();cout<

}

inti=low,j=high;

elementtemp=table.Arr[low];//取区间第一个位置为基准位置

if(i

{

while(i

while(i

if(i

while(i=table.Arr[i].GetKey())i++;

if(i

}

table.Arr[i]=temp;//基准元素归为

cout<<"第"<

";table.Show();cout<

QuickSort(table,low,i-1);//左区间递归快速排序

QuickSort(table,i+1,high);//右区间递归快速排序

}

}

//堆排序

template

classMaxHeap{

public:

MaxHeap(intmaxSize);//构造函数,建立空堆

MaxHeap(Type*a,intn);//构造函数,以数组a[]的值建立堆

~MaxHeap(){delete[]heapArr;

}//析构函数

intInsert(Type&d);//在堆中插入元素d

TypeDeleteTop();//删除堆顶元素

TypeGetTop()const//取得堆顶元素

{returnheapArr[0];}

intIsEmpty()//判断堆是否为空

{returnheapCurrentSize==0;}

intIsFull()const//判断堆是否为满

{returnheapCurrentSize==heapMaxSize;}

voidSetEmpty(){heapCurrentSize=0;}//置堆为空

voidHeapSort();//堆排序

voidShow(intk)

{

for(inti=0;i

cout<

}

private:

intheapMaxSize;//堆中数据元素的最大数目

Type*heapArr;//存放堆中数据元素的数组

intheapCurrentSize;//堆中当前元素数目

voidFilterDown(intp);//向下调整使以结点p为根的子树成为堆

voidFilterUp(intp);//向上调整使以结点p为根的子树成为堆

};

template

intMaxHeap:

:

Insert(Type&d)

{

if(IsFull())

{cout<<"堆已满"<

heapArr[heapCurrentSize]=&d;//在堆尾插入数据元素d

FilterUp(heapCurrentSize);//向上调整为堆

heapCurrentSize++;

return1;

}

template

MaxHeap:

:

MaxHeap(intmaxSize){

//根据maxSize,建立空堆

if(maxSize<=0)

{

cerr<<"堆的大小不能小于1"<

exit

(1);

}

heapMaxSize=maxSize;

heapArr=newType[heapMaxSize];//建立堆空间

heapCurrentSize=0;

}

template

MaxHeap:

:

MaxHeap(Type*a,intn){//根据数组a[]中的数据,建立堆,n为数组的大小

if(n<=0)

{cerr<<"堆的大小不能小于1"<

exit

(1);

}

heapMaxSize=n;//确定堆的最大空间

heapArr=newType[heapMaxSize];//创建堆空间

//heapArr=a;//?

直接赋值?

for(inti=0;i

heapArr[i]=a[i];

heapCurrentSize=n;//当前堆大小

/*inti=(heapCurrentSize-2)/2;//找最后一个分支结点的序号

while(i>=0)

{

FilterDown(i);//从开始到heapCurrentSize-1为止进行调整

i--;

}*/

}

template

voidMaxHeap:

:

FilterDown(constintstart)

{

//向下调整从start开始到heapCurrentSize-1为止的子序列成为最大堆

inti=start,j;

Typetemp=heapArr[i];

if(heapCurrentSize<=2)

{

if(i==0&&heapCurrentSize==2&&heapArr[0].GetKey()

{heapArr[0]=heapArr[1];heapArr[1]=temp;}

}

else{

j=2*i+1;//j为i的左孩子

while(j

if(j

j++;//从左右孩子中选较大者

if(temp.GetKey()>=heapArr[j].G

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

当前位置:首页 > 成人教育 > 电大

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

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