华电北风吹
天津大学认知计算与应用重点实验室
最后修改日期:2015/8/22
声明:本文涉及的所有排序算法定义功能对输入进行从小到大排序
符号解释:
n:输入数据个数
Θ(n):n的同阶无穷大
Part I Array Sort
一、选择排序
def SelectSort(a):
for i in range(0,len(a)-1):
minIndex=i
for j in range(i+1,len(a)):
if a[j]<a[minIndex]:
minIndex=j
if minIndex !=i:
temp=a[minIndex]
a[minIndex]=a[i]
a[i]=temp
return a
a=[2,5,3,8,6,1,4,9]
SelectSort (a)
print(a)
从前往后,依次选择当前位置以后最小的数与当前位置交换
计算复杂度theta(n^2)
二、冒泡排序
def BubbleSort (a):
k=len(a)
for i in range(0,k-1):
for j in range(k-1,i,-1):
if a[j]<a[j-1]:
a[j-1],a[j]=a[j],a[j-1]
return a
a=[2,5,3,8,6,7,1,4,9]
BubbleSort (a)
print(a)
从前往后,反复交换相邻的未按次序排列的元素
计算复杂度theta(n^2)
三、插入排序
def InsertSort(a):
for j in range(1,len(a)):
key=a[j]
i=j-1
while(i>=0 and a[i]>key):
a[i+1]=a[i]
i=i-1
a[i+1]=key
a=[2,5,3,8,6,1,4,9]
InsertSort (a)
print(a)
从前往后,讲下一个数据插入到前面已经排好序的数组里面
最好的情况:已经从小到大排好序,计算复杂度theta(n)
最坏的情况:输入顺序为从大到小,计算复杂度theta(n^2)
当数据量很大的时候,不必要一个一个往前找,可以根据二分发,减少计算量
四、归并排序
def MergeSort(a):
n=len(a)
if n==1:
return a
mid=(n+1)//2
b=MergeSort(a[0:mid])
c=MergeSort(a[mid:n])
i=0
j=0
b.append(float("inf"))
c.append(float("inf"))
for k in range(0,n):
if b[i]<c[j]:
a[k]=b[i]
i+=1
else:
a[k]=c[j]
j+=1
return a
a=[2,5,3,8,6,7,1,4,9]
MergeSort (a)
print(a)
分治策略,先划分子序列,后归并排序
计算复杂度theta(nlog(n))
注意:非原址运算
五、堆排序
def HeapAdjust(lst,k,n):
while(2*k+1<n):
j=2*k+1
if j+1<n and lst[j]<lst[j+1]:
j=j+1
if lst[j]>lst[k]:
lst[k],lst[j]=lst[j],lst[k]
k=j
else:
break
return lst
def HeapSort(lst):
n=len(lst)
for i in range(n//2-1,-1,-1):
lst=HeapAdjust(lst,i,n)
for i in range(n-1,0,-1):
lst[0],lst[i]=lst[i],lst[0]
lst=HeapAdjust(lst,0,i)
return lst
a=[1,5,2,8,3,4,6,9,7]
HeapSort(a)
print(a)
代码注释:http://blog.csdn.net/zhangzhengyi03539/article/details/44889951
构建大根堆,然后堆顶元素与序列最后一个元素交换,序列长度减一,对堆顶元素构建大根堆
计算复杂度theta(nlogn)
我觉得这个算法还有可能改进的地方,因为每次堆顶元素与最后一个元素交换,而最后一个元素是大根堆叶子上的元素,也就是在这条支路中最小的元素,这样在重新对堆顶元素构建大根队的过程中需要迭代好多步骤。
六、快速排序
例子一:
def QuickSort(a,start,end):
key=a[start]
i=start+1
j=end
while i<j:
while a[i]<=key and i<j:
i+=1
while a[j]>key and j>i-1:
j-=1
if i<j:
a[i],a[j]=a[j],a[i]
a[start],a[j]=a[j],a[start]
if j-1>start:
QuickSort(a,start,j-1)
if j+1<end:
QuickSort(a,j+1,end)
return a
a=[1,5,2,8,3,4,6,9,7]
QuickSort(a,0,len(a)-1)
print(a)
例子二:
def QuickSort(a,start,end):
key=a[end]
i=start-1
for j in range(start,end):
if a[j]<key:
i+=1
a[i],a[j]=a[j],a[i]
a[i+1],a[end]=a[end],a[i+1]
if i>start:
QuickSort(a,start,i)
if i+2<end:
QuickSort(a,i+2,end)
return a
a=[1,5,2,8,3,4,6,9,7]
QuickSort(a,0,len(a)-1)
print(a)
分治策略,最好的情况当然是每次都是二分了
平均情况/期望情况:计算复杂度theta(nlogn)
最坏的情况:计算复杂度theta(n^2)
对于例子二,考虑这样一种情况,输入序列最后一个是最大的,然后对j循环的时候每次都要执行交换操作。还有就是快速排序的随机化版本,每次从输入中随机挑选一个数与key所在的数交换,然后执行快速排序。
Part II List Struct Sort
#include <iostream>
using namespace std;
struct Node
{
int val;
Node * Next;
};
Node* MergeList(Node* root1, Node* root2)
{
Node* root = new Node;
Node*p = root, *p1 = root1, *p2 = root2;
while ((p1!=NULL)&&(p2!=NULL))
{
if (p1->val <= p2->val)
{
p->Next = p1;
p = p->Next;
p1 = p1->Next;
}
else
{
p->Next = p2;
p = p->Next;
p2 = p2->Next;
}
}
if (p1 != NULL)
p->Next = p1;
else
p->Next = p2;
p = root->Next;
delete root;
return p;
}
Node* MergeSort(Node* root)
{
if ((root == NULL) || (root->Next == NULL))
return root;
int length = 0;
Node*p = root;
while (p!=NULL)
{
length++;
p = p->Next;
}
p = root;
Node *root2;
for (int i = 0; i < length / 2-1; i++)
{
p = p->Next;
}
root2 = p->Next;
p->Next = NULL;
root = MergeSort(root);
root2 = MergeSort(root2);
root = MergeList(root, root2);
return root;
}
int main()
{
Node *p1 = new Node{ 6,NULL };
Node *p2 = new Node{ 3,NULL };
Node *p3 = new Node{ 9,NULL };
Node *p4 = new Node{ 7,NULL };
Node *p5 = new Node{ 1,NULL };
Node *p6 = new Node{ 2,NULL };
Node *p7 = new Node{ 4,NULL };
p1->Next = p2;
p2->Next = p3;
p3->Next = p4;
p4->Next = p5;
p5->Next = p6;
p6->Next = p7;
Node*p = p1;
while (p != NULL)
{
cout << p->val << " ";
p = p->Next;
}
cout << endl;
p1 = MergeSort(p1);
p = p1;
while (p!=NULL)
{
cout << p->val << " ";
p = p->Next;
}
cout << endl;
return 0;
}