排序算法编辑
所谓
排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视,尤其是在大量数据的处理方面。一个优秀的算法可以节省大量的资源。在各个领域中考虑到数据的各种限制和规范,要得到一个符合实际的优秀算法,得经过大量的推理和分析。
目录
1分类编辑
稳定度(稳定性)
一个
排序算法是
稳定的,就是当有两个相等记录的关键字
R和
S,且在原本的列表中
R出现在
S之前,在排序过的列表中
R也将会是在
S之前。
(4,1)(3,1)(3,7)(5,6)在这个状况下,有可能产生两种不同的结果,一个是依照相等的键值维持相对的次序,而另外一个则没有:
(3,1)(3,7)(4,1)(5,6) (维持次序)
(3,7)(3,1)(4,1)(5,6) (次序被改变)
不稳定
排序算法可能会在相等的键值中改变纪录的相对次序,但是稳定排序算法从来不会如此。不稳定
排序算法可以被特别地实现为稳定。作这件事情的一个方式是人工扩充键值的比较,如此在其他方面相同键值的两个对象间之比较,就会被决定使用在原先数据次序中的条目,当作一个同分决赛。然而,要记住这种次序通常牵涉到额外的空间负担。
一般而言,好的性能是 O(
nlog
n),且坏的性能是 O(
n^2)。对于一个
排序理想的性能是 O(
n)。
(c)稳定度:
稳定的
排序算法会依照相等的关键(换言之就是值)维持纪录的相对次序。
2C++算法编辑
C++自带的algorithm库函数中提供了排序算法。
自带排序算法的一般形式为:
sort(arr+m,arr+n);//将数组arr的下标为m的元素到下标为n-1的元素进行从小到大排序
sort(arr+m,arr+n,comp);//与sort(arr+m,arr+n)相比,这个写法可以自己定义排序的规则,其中,comp为自定义的函数
对于sort(arr+m,arr+n)我们举个简单的例子,这个程序实现从键盘读入10个数,然后从小到大输出的功能:
1
2
3
4
5
6
7
8
9
10
11
12
|
#include<algorithm>
#include<iostream>
usingnamespacestd;
main()
{
inta[10],i;
for
(i=0;i<10;i++)
cin>>a[i];
sort(a,a+10);
for
(i=0;i<10;i++)
cout<<a[i]<<
''
;
}
|
当然,有时我们需要从大到小的进行排序。那么我们可以用sort(arr+m,arr+n,comp)进行排序。
不过,在调用sort(arr+m,arr+n,comp)之前我们需要自己写个comp函数。
从大到小排序的comp函数可以这样写:
1
2
3
4
|
intcomp(inta,intb)
{
returna>b;
//在两元素相同时一定要返回0或者false
}
|
下面是10个数从大到小排序的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#include<algorithm>
#include<iostream>
usingnamespacestd;
intcomp(inta,intb)
{
returna>b;
//如果a>b则返回1,否则返回0
}
main()
{
inta[10],i;
for
(i=0;i<10;i++)
cin>>a[i];
sort(a,a+10,comp);
for
(i=0;i<10;i++)
cout<<a[i]<<
''
;
}
|
在更多情况下,我们不仅对一个特征进行排序,而是多个特征。例如将学生的成绩进行排序,当然用上面的做法是行不通的。这是,我们就想到了结构体这种数据类型。当我们采用sort()函数的默认规则排序结构体时,sort()默认结构体中的第一个成员为第一关键字,第二个成员为第二关键字,……,第N个元素为第N关键字,然后从小到大排序。
例如我们要将学生的成绩从大到小排序,当成绩相同时,根据姓名字典序小的优先规则进行排序。显然我们无法采用默认规则进行排序。
这时我们可以定义这样的comp:
1
2
3
4
5
6
7
8
9
10
|
intcomp(studenta,studentb)
{
if
(a.score>b.score)
return1;
if
(a.score<b.score)
return0;
if
(a.name<b.name)
return1;
return0;
}
|
3算法列表编辑
稳定的
冒泡排序(bubble sort) — O(n^2)
插入排序(insertion sort)— O(
n^2)
桶排序(bucket sort)— O(
n); 需要 O(
k) 额外空间
计数排序(counting sort) — O(
n+
k); 需要 O(
n+
k) 额外空间
合并排序(merge sort)— O(
nlog
n); 需要 O(
n) 额外空间
原地
合并排序— O(
n^2)
二叉排序树排序 (Binary tree sort) — O(
nlog
n)期望时间; O(
n^2)最坏时间; 需要 O(
n) 额外空间
鸽巢排序(Pigeonhole sort) — O(
n+
k); 需要 O(
k) 额外空间
基数排序(radix sort)— O(
n·
k); 需要 O(
n) 额外空间
Gnome 排序— O(
n^2)
图书馆排序— O(
nlog
n) with high probability,需要 (1+ε)
n额外空间
不稳定的
选择排序(selection sort)— O(
n^2)
希尔排序(shell sort)— O(
nlog
n) 如果使用最佳的现在版本
组合排序— O(
nlog
n)
堆排序(heapsort)— O(
nlog
n)
平滑排序— O(
nlog
n)
快速排序(quicksort)— O(
nlog
n) 期望时间,O(
n^2) 最坏情况; 对于大的、乱数列表一般相信是最快的已知排序
Introsort— O(
nlog
n)
Patience sorting— O(
nlog
n+
k) 最坏情况时间,需要 额外的 O(
n+
k) 空间,也需要找到最长的递增子串行(longest increasing subsequence)
不实用的
Bogo排序— O(
n×
n!) 期望时间,无穷的最坏情况。
Stupid sort— O(
n^3); 递归版本需要 O(
n^2) 额外
存储器
珠排序(Bead sort) — O(
n) or O(√
n),但需要特别的硬件
Pancake sorting— O(
n),但需要特别的硬件
stooge sort——O(n^2.7)很漂亮但是很耗时
4排序算法编辑
排序的算法有很多,对空间的要求及其时间效率也不尽相同。下面列出了一些常见的
排序算法。这里面
插入排序和
冒泡排序又被称作
简单排序,他们对空间的要求不高,但是时间效率却不稳定;而后面三种排序相对于简单排序对空间的要求稍高一点,但时间效率却能稳定在很高的水平。
基数排序是针对
关键字在一个较小范围内的排序算法。
插入排序
插入排序是这样实现的:
1、首先新建一个空列表,用于保存已
排序的有序数列(我们称之为"有序列表")。
2、从原数列中取出一个数,将其插入"有序列表"中,使其仍旧保持有序状态。
3、重复2号步骤,直至原数列为空。
冒泡排序
冒泡排序是这样实现的:
1、从列表的第一个数字到倒数第二个数字,逐个检查:若某一位上的数字大于他的下一位,则将它与它的下一位交换。
2、重复1号步骤,直至再也不能交换。
选择排序
选择排序是这样实现的:
1、设
数组内存放了n个待排数字,数组下标从1开始,到n结束。
2、初始化i=1
3、从
数组的第i个元素开始到第n个元素,寻找最小的元素。
4、将上一步找到的最小元素和第i位元素交换。
5、i++,直到i=n-1算法结束,否则回到第3步
举例:
564
第一步:从第一位开始找最小的元素,564中4最小,与第一位交换。结果为465
第二步:从第二位开始找最小的元素,465中5最小,与第二位交换。结果为456
第三步:i=2,n=3,此时i=n-1,算法结束
完成
快速排序
现在开始,我们要接触高效
排序算法了。实践证明,
快速排序是所有排序算法中最高效的一种。它采用了分治的思想:先保证列表的前半部分都小于后半部分,然后分别对前半部分和后半部分
排序,这样整个列表就有序了。这是一种先进的思想,也是它高效的原因。因为在
排序算法中,算法的高效与否与列表中数字间的比较次数有直接的关系,而"保证列表的前半部分都小于后半部分"就使得前半部分的任何一个数从此以后都不再跟后半部分的数进行比较了,大大减少了数字间不必要的比较。但查找数据得另当别论了。
时间复杂度
平均
时间复杂度
插入排序 O(n^2)
冒泡排序 O(n^2)
选择排序 O(n^2)
快速排序 O(n log n)
堆排序 O(n log n)
归并排序 O(n log n)
基数排序 O(n)
希尔排序 O(n^1.25)
5复杂度编辑
简单排序算法
由于程序比较简单,所以没有加什么注释。所有的程序都给出了完整的运行代码,并在我的VC环境
下运行通过。因为没有涉及MFC和WINDOWS的内容,所以在BORLAND C++的平台上应该也不会有什么
问题的。在代码的后面给出了运行过程示意,希望对理解有帮助。
冒泡法
这是最原始,也是众所周知的最慢的算法了。他的名字的由来因为它的工作看来象是冒泡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
#include<iostream>
usingnamespacestd;
voidBubbleSort(
int
*pData,intCount)
{
intiTemp;
for
(inti=0;i<Count;i++)
{
for
(intj=Count-1;j>i;j--)
{
if
(pData[j]<pData[j-1])
{
iTemp=pData[j-1];
pData[j-1]=pData[j];
pData[j]=iTemp;
}
}
}
}
voidmain()
{
intdata[7]={10,9,8,7,6,5,4};
BubbleSort(data,7);
for
(inti=0;i<7;i++)
{
cout<<data[i]<<
""
;
}
cout<<endl;
system
(
"PAUSE"
);
}
|
倒序(最糟情况)
第一轮:10,9,8,7->10,9,7,8->10,7,9,8->7,10,9,8(交换3次)
第二轮:7,10,9,8->7,10,8,9->7,8,10,9(交换2次)
第一轮:7,8,10,9->7,8,9,10(交换1次)
循环次数:6次
交换次数:6次
其他:
第一轮:8,10,7,9->8,10,7,9->8,7,10,9->7,8,10,9(交换2次)
第二轮:7,8,10,9->7,8,9,10->7,8,10,9(交换1次)
(这是原撰写人的--7,8,10,9->7,8,10,9->7,8,10,9(交换0次),第二轮应该是这样的)
第三轮:7,8,9,10->7,8,9,10(交换1次)
循环次数:6次
交换次数:3次
上面我们给出了
程序段,现在我们分析它:这里,影响我们算法性能的主要部分是循环和交换,
显然,次数越多,性能就越差。从上面的程序我们可以看出循环的次数是固定的,为1+2+...+n-1。
写成公式就是1/2*(n-1)*n。
现在注意,我们给出O方法的定义:
若存在一常量K和起点n0,使当n>=n0时,有f(n)<=K*g(n),则f(n) = O(g(n))。(呵呵,不要说没学好数学呀,对于编程数学是非常重要的!!!)
现在我们来看1/2*(n-1)*n,当K=1/2,n0=1,g(n)=n*n时,1/2*(n-1)*n<=1/2*n*n=K*g(n)。所以f(n)
=O(g(n))=O(n*n)。所以我们程序循环的
复杂度为O(n*n)。
再看交换。从程序后面所跟的表可以看到,两种情况的循环相同,交换不同。其实交换本身同数据源的
有序程度有极大的关系,当数据处于倒序的情况时,交换次数同循环一样(每次循环判断都会交换),
原因,我们通常都是通过循环次数来对比算法。
交换法
交换法的程序最清晰简单,每次用当前的元素一一的同其后的元素比较并交换。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#include<iostream.h>
voidExchangeSort(
int
*pData,intCount)
{
intiTemp;
for
(inti=0;i<Count-1;i++)
{
//共(count-1)轮,每轮得到一个最小值
for
(intj=i+1;j<Count;j++)
{
//每次从剩下的数字中寻找最小值,于当前最小值相比,如果小则交换
if
(pData[j]<pData[i])
{
iTemp=pData[i];
pData[i]=pData[j];
pData[j]=iTemp;
}
}
}
}
voidmain()
{
intdata[]={10,9,8,7,6,5,4};
ExchangeSort(data,
sizeof
(data)/
sizeof
(
int
));
for
(inti=0;i<
sizeof
(data)/
sizeof
(
int
);i++)
{
cout<<data[i]<<
""
;
}
cout<<endl;
system
(
"PAUSE"
);
}
|
第二轮:7,10,9,8->7,9,10,8->7,8,10,9(交换2次)
第一轮:7,8,10,9->7,8,9,10(交换1次)
循环次数:6次
交换次数:6次
其他:
第一轮:8,10,7,9->8,10,7,9->7,10,8,9->7,10,8,9(交换1次)
第二轮:7,10,8,9->7,8,10,9->7,8,10,9(交换1次)
第一轮:7,8,10,9->7,8,9,10(交换1次)
循环次数:6次
交换次数:3次
从运行的
表格来看,交换几乎和冒泡一样糟。事实确实如此。循环次数和冒泡一样
也是1/2*(n-1)*n,所以算法的
复杂度仍然是O(n*n)。由于我们无法给出所有的情况,所以
只能直接告诉大家他们在交换上面也是一样的糟糕(在某些情况下稍好,在某些情况下稍差)。
选择法
现在我们终于可以看到一点希望:选择法,这种方法提高了一点性能(某些情况下)
这种方法类似我们人为的
排序习惯:从数据中选择最小的同第一个值交换,在从剩下的部分中
选择最小的与第二个交换,这样往复下去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#include<iostream.h>
voidSelectSort(
int
*pData,intCount)
{
intiTemp;
intiPos;
for
(inti=0;i<Count-1;i++)
{
iTemp=pData[i];
iPos=i;
for
(intj=i+1;j<Count;j++)
{
if
(pData[j]<iTemp)
{
iTemp=pData[j];
iPos=j;
}
}
pData[iPos]=pData[i];
pData[i]=iTemp;
}
}
voidmain()
{
intdata[]={10,9,8,7,6,5,4};
SelectSort(data,7);
for
(inti=0;i<7;i++)
cout<<data[i]<<
""
;
cout<<
"\n"
;
}
|
倒序(最糟情况)
第一轮:10,9,8,7->(iTemp=9)10,9,8,7->(iTemp=8)10,9,8,7->(iTemp=7)7,9,8,10(交换1次)
第二轮:7,9,8,10->7,9,8,10(iTemp=8)->(iTemp=8)7,8,9,10(交换1次)
第一轮:7,8,9,10->(iTemp=9)7,8,9,10(交换0次)
循环次数:6次
交换次数:2次
其他:
第一轮:8,10,7,9->(iTemp=8)8,10,7,9->(iTemp=7)8,10,7,9->(iTemp=7)7,10,8,9(交换1次)
第二轮:7,10,8,9->(iTemp=8)7,10,8,9->(iTemp=8)7,8,10,9(交换1次)
第一轮:7,8,10,9->(iTemp=9)7,8,9,10(交换1次)
循环次数:6次
交换次数:3次
遗憾的是算法需要的循环次数依然是1/2*(n-1)*n。所以
算法复杂度为O(n*n)。
我们来看他的交换。由于每次外层循环只产生一次交换(只有一个最小值)。所以f(n)<=n
所以我们有f(n)=O(n)。所以,在数据较乱的时候,可以减少一定的交换次数。
插入法
插入法较为复杂,它的基本工作原理是抽出牌,在前面的牌中寻找相应的位置插入,然后继续下一张
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include<iostream.h>
voidInsertSort(
int
*pData,intCount)
{
intiTemp;
intiPos;
for
(inti=1;i<Count;i++)
{
iTemp=pData[i];
//保存要插入的数
iPos=i-1;
//被插入的数组数字个数
while
((iPos>=0)&&(iTemp<pData[iPos]))
{
//从最后一个(最大数字)开始对比,大于它的数字往后移位
pData[iPos+1]=pData[iPos];
iPos--;
}
pData[iPos+1]=iTemp;
//插入数字的位置
}
}
voidmain(){
intdata[]={10,9,8,7,6,5,4};
InsertSort(data,7);
for
(inti=0;i<7;i++)
cout<<data<<
""
;
cout<<
"\n"
;
}
|
其他:
第一轮:8,10,7,9->8,10,7,9(交换0次)(循环1次)
第二轮:9,10,8,7->8,9,10,7(交换1次)(循环2次)
第一轮:8,9,10,7->7,8,9,10(交换1次)(循环3次)
循环次数:6次
交换次数:3次
其他:
第一轮:8,10,7,9->8,10,7,9(交换0次)(循环1次)
第二轮:8,10,7,9->7,8,10,9(交换1次)(循环2次)
第一轮:7,8,10,9->7,8,9,10(交换1次)(循环1次)
循环次数:4次
交换次数:2次
上面结尾的行为分析事实上造成了一种假象,让我们认为这种算法是简单算法中
最好的,其实不是,
因为其循环次数虽然并不固定,我们仍可以使用O方法。从上面的结果可以看出,循环的次数f(n)<=
1/2*n*(n-1)<=1/2*n*n。所以其
复杂度仍为O(n*n)(这里说明一下,其实如果不是为了展示这些简单
排序的不同,交换次数仍然可以这样推导)。现在看交换,从外观上看,交换次数是O(n)(推导类似
选择法),但我们每次要进行与内层循环相同次数的‘=’操作。正常的一次交换我们需要三次‘=’
而这里显然多了一些,所以我们浪费了时间。
高级排序算法
高级
排序算法中我们将只介绍这一种,同时也是目前我所知道(我看过的资料中)的最快的。
把比它小的放在左边,大的放在右边(具体的实现是从两边找,找到一对后交换)。然后对两边分别使
用这个过程(最容易的方法——
递归)。
1.
快速排序://这段代码编译可以通过,一运行就出错,内部的细节有些问题,我还没找到解决方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
#include<iostream.h>
voidrun(
int
*pData,intleft,intright)
{
inti,j;
intmiddle,iTemp;
i=left;
j=right;
middle=pData[left];
do
{
while
((pData[i]<middle)&&(i<right))
//从左扫描大于中值的数
i++;
while
((pData[j]>middle)&&(j>left))
//从右扫描大于中值的数
j--;
if
(i<=j)
//找到了一对值
{
//交换
iTemp=pData[i];
pData[i]=pData[j];
pData[j]=iTemp;
i++;
j--;
}
}
while
(i<=j);
//如果两边扫描的下标交错,就停止(完成一次)
//当左边部分有值(left<j),递归左半边
if
(left<j)
run(pData,left,j);
//当右边部分有值(right>i),递归右半边
if
(right>i)
run(pData,i,right);
}
voidQuickSort(
int
*pData,intCount)
{
run(pData,0,Count-1);
}
voidmain()
{
intdata[]={10,9,8,7,6,5,4};
QuickSort(data,7);
for
(inti=0;i<7;i++)
cout<<data[i]<<
""
;
//原作者此处代码有误,输出因为date[i],date数组名输出的是地址
cout<<
"\n"
;
}
|
这里我没有给出行为的分析,因为这个很简单,我们直接来分析算法:首先我们考虑最理想的情况
1.
数组的大小是2的幂,这样分下去始终可以被2整除。假设为2的k次方,即k=log2(n)。
2.每次我们选择的值刚好是中间值,这样,
数组才可以被等分。
第一层递归,循环n次,第二层循环2*(n/2)......
所以共有n+2(n/2)+4(n/4)+...+n*(n/n) = n+n+n+...+n=k*n=log2(n)*n
所以
算法复杂度为O(log2(n)*n)
其他的情况只会比这种情况差,最差的情况是每次选择到的middle都是最小值或最大值,那么他将变
成交换法(由于使用了
递归,情况更糟)。但是你认为这种情况发生的几率有多大??呵呵,你完全
如果你担心这个问题,你可以使用
堆排序,这是一种稳定的O(log2(n)*n)算法,但是通常情况下速度要慢
于
快速排序(因为要重组堆)。
其他排序
双向冒泡
通常的冒泡是单向的,而这里是双向的,也就是说还要进行反向的工作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#include<iostream.h>
inlinevoidexchange(
int
*a,
int
*b)
{
inttemp;
temp=*a;
*a=*b;
*b=temp;
}
voidbubblesort(
int
*array,intnum)
{
inti,j,k,flag=0;
for
(i=0;i<num;i++){
printf
(
"%d"
,array[i]);
}
printf
(
"\n"
);
for
(i=0;i<num;i++){
//所有数的个数为num个
flag=0;
for
(j=i;j<num-i-1;j++){
//每循环一次最底端的数的顺序都会排好,所以初始时j=i;
if
(array[j]>array[j+1]){
exchange(&array[j],&array[j+1]);
flag=1;
}
}
for
(k=num-1-i-1;k>i;k--){
//每循环一次最顶端的数据的顺序也会排好,所以初始时k=num-i-2
if
(array[k]<array[k-1]){
exchange(&array[k],&array[k-1]);
flag=1;
}
}
if
(flag==0){
//如果flag未发生改变则说明未发生数据交换,则排序完成
return
;
}
}
}
voidmain()
{
intdata[]={10,9,8,7,6,5,4,3,2,1,-10,-1};
bubblesort(data,12);
for
(inti=0;i<12;i++)
cout<<data<<
""
;
cout<<
"\n"
;
}
|
通用排序
这个程序我想就没有分析的必要了,大家看一下就可以了。不明白可以在论坛上问。
MyData.h文件
///
class CMyData
{
public:
CMyData(int Index,char* strData);
CMyData();
virtual ~CMyData();
int m_iIndex;
int GetDataSize(){ return m_iDataSize; };
const char* GetData(){ return m_strDatamember; };
//这里重载了操作符:
CMyData& operator =(CMyData &SrcData);
bool operator <(CMyData& data );
bool operator >(CMyData& data );
private:
char* m_strDatamember;
int m_iDataSize;
};
MyData.cpp文件
CMyData::CMyData():
m_iIndex(0),
m_iDataSize(0),
m_strDatamember(NULL)
{
}
CMyData::~CMyData()
{
if(m_strDatamember != NULL)
delete[] m_strDatamember;
m_strDatamember = NULL;
}
CMyData::CMyData(int Index,char* strData):
m_iIndex(Index),
m_iDataSize(0),
m_strDatamember(NULL)
{
m_iDataSize = strlen(strData);
m_strDatamember = new char[m_iDataSize+1];
strcpy(m_strDatamember,strData);
}
CMyData& CMyData::operator =(CMyData &SrcData)
{
m_iIndex = SrcData.m_iIndex;
m_iDataSize = SrcData.GetDataSize();
m_strDatamember = new char[m_iDataSize+1];
strcpy(m_strDatamember,SrcData.GetData());
return *this;
}
bool CMyData::operator <(CMyData& data )
{
return m_iIndex<data.m_iIndex;
}
bool CMyData::operator >(CMyData& data )
{
return m_iIndex>data.m_iIndex;
}
///
//
//主程序部分
#include <iostream.h>
#include "MyData.h"
template <class T>
void run(T* pData,int left,int right)
{
int i,j;
T middle,iTemp;
i = left;
j = right;
//下面的比较都调用我们
重载的操作符函数
middle = pData[(left+right)/2]; //求中间值
do{
while((pData<middle) && (i<right))//从左扫描大于中值的数
i++;
while((pData[j]>middle) && (j>left))//从右扫描大于中值的数
j--;
if(i<=j)//找到了一对值
{
//交换
iTemp = pData;
pData = pData[j];
pData[j] = iTemp;
i++;
j--;
}
}while(i<=j);//如果两边扫描的下标交错,就停止(完成一次)
//当左边部分有值(left<j),递归左半边
if(left<j)
run(pData,left,j);
//当右边部分有值(right>i),递归右半边
if(right>i)
run(pData,i,right);
}
template <class T>
void QuickSort(T* pData,int Count)
{
run(pData,0,Count-1);
}
void main()
{
CMyData data[] = {
CMyData(8,"xulion"),
CMyData(7,"sanzoo"),
CMyData(6,"wangjun"),
CMyData(5,"VCKBASE"),
CMyData(4,"jacky2000"),
CMyData(3,"cwally"),
CMyData(2,"VCUSER"),
CMyData(1,"isdong")
};
QuickSort(data,8);
for (int i=0;i<8;i++)
cout<<data.m_iIndex<<" "<<data.GetData()<<"\n";
cout<<"\n";