这几天好好学习了一下排序算法 查看了各种书籍和网络资源 挑着简单易懂的教程好好学习了一下 基本上算是过了一遍 之后几天 对排序算法好好地总结一下 整理一下,先把要整理的算法列举一下:
1,选择排序
对于一个a[0,n]的数组,依次遍历数组,每次选出最大或最小的一个数
- void selectSort(int *a,int size)
- {
- int min;
- for(int i=0;i<size;i++)
- {
- min=i; //将当前下标定义为最小值下标
- for(int j=i+1;j<size;j++)
- if(a[min]>a[j])
- min=j; // 记录当前最小下标
- if(i!=min)
- swap(a[i],a[min]); // 如果i不是最小下标 则交换
- }
- print(a,size);
- }
void selectSort(int *a,int size)
{
int min;
for(int i=0;i<size;i++)
{
min=i; //将当前下标定义为最小值下标
for(int j=i+1;j<size;j++)
if(a[min]>a[j])
min=j; // 记录当前最小下标
if(i!=min)
swap(a[i],a[min]); // 如果i不是最小下标 则交换
}
print(a,size);
}
2,冒泡排序
依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。
- void BubbleSort(int *a,int size)
- {
- for(int i=0;i<size-1;i++)
- for(int j=0;j<size-1-i;j++)
- {
- if(a[j]>a[j+1])
- swap(a[j],a[j+1]);
- }
- print(a,size);
- }
void BubbleSort(int *a,int size)
{
for(int i=0;i<size-1;i++)
for(int j=0;j<size-1-i;j++)
{
if(a[j]>a[j+1])
swap(a[j],a[j+1]);
}
print(a,size);
}
优化:使用标志的冒泡排序, 因为当一次遍历时 没有发生任何的交换 事实上证明数组排序已经完成 函数可以退出
- void BubbleSortWithFlag(int *a,int size)
- {
- bool flag;
- for(int i=0;i<size-1;i++)
- {
- flag=true;
- for(int j=0;j<size-1-i;j++)
- {
- if(a[j]>a[j+1])
- {
- swap(a[j],a[j+1]);
- flag=false;
- }
- }
- if(flag==true)
- {
- print(a,size);
- return;
- }
- }
- }
void BubbleSortWithFlag(int *a,int size)
{
bool flag;
for(int i=0;i<size-1;i++)
{
flag=true;
for(int j=0;j<size-1-i;j++)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
flag=false;
}
}
if(flag==true)
{
print(a,size);
return;
}
}
}
鸡尾酒排序 :冒泡排序的变形 (转)鸡尾酒排序等于冒泡排序的轻微变形,不同的地方在于从低到高然后从高到低,而冒泡排序则仅从低到高去比较序列里的每个元素。他可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只从一个方向进行比对(由低到高),每次循环只移动一个项目。以序列(2,3,4,5,1)为例,鸡尾酒排序只需要访问两次(升序降序各一次 )次序列就可以完成排序,但如果使用冒泡排序则需要四次。
(1)先对数组从左到右进行冒泡排序(升序),则最大的元素去到最右端;
(2)再对数组从右到左进行冒泡排序(降序),则最小的元素去到最左端。以此类推,依次改变冒泡的方向,并不断缩小未排序元素的范围。
- void CockSort(int *a,int size)
- {
- int low=0;
- int up=size-1;
- int index=0;
- while(low<up)
- {
- for(int i=low;i<up;i++)
- if(a[i]>a[i+1])
- {
- swap(a[i],a[i+1]);
- index=i;
- }
- up=index;
- for(int i=up;i>low;i--)
- if(a[i]<a[i-1])
- {
- swap(a[i],a[i-1]);
- index=i;
- }
- low=index;
- }
- print(a,size);
- }
void CockSort(int *a,int size)
{
int low=0;
int up=size-1;
int index=0;
while(low<up)
{
for(int i=low;i<up;i++)
if(a[i]>a[i+1])
{
swap(a[i],a[i+1]);
index=i;
}
up=index;
for(int i=up;i>low;i--)
if(a[i]<a[i-1])
{
swap(a[i],a[i-1]);
index=i;
}
low=index;
}
print(a,size);
}
3,插入排序 (直接,折半,路插入,表插入)
依次取出便利每一项 将每一项temp=a[j]和其之前的数进行比较,如果发现了比自己大的数 就将其放在当前j的位置 同时j--,继续用temp和之前的数进行比较,直到没有比自己大的数时结束。
- //直接插入排序
- void insertSort(int *a,int size)
- {
- if(size<2)
- return;
- int temp;
- int j;
- for(int i=1;i<size;i++)
- {
- temp=a[i];
- for( j=i;j>0&&temp<a[j-1];j--)
- {
- a[j]=a[j-1];
- }
- a[j]=temp;
- }
- print(a,size);
- }
//直接插入排序
void insertSort(int *a,int size)
{
if(size<2)
return;
int temp;
int j;
for(int i=1;i<size;i++)
{
temp=a[i];
for( j=i;j>0&&temp<a[j-1];j--)
{
a[j]=a[j-1];
}
a[j]=temp;
}
print(a,size);
}
折半插入排序:
折半插入排序(binary insertion sort)是对插入排序算法的一种改进,由于排序算法过程中,就是不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,这样我们不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
折半插入排序算法的具体操作为:在将一个新元素插入已排好序的数组的过程中,寻找插入点时,将待插入区域的首元素设置为a[low],末元素设置为a[high],则轮比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素小,则选择a[low]到a[m-1]为新的插入区域(即high=m-1),否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),如此直至low<=high不成立,即将此位置之后所有元素后移一位,并将新元素插入a[high+1]。
额 网上的方法 不是从数组a[1]开始 就是结果不正确 试了老半天 总算对了
- void binaryInsertSort(int *a,int size)
- {
- int low,high,m,temp,j;
- for (int i=1;i<size;++i){
- temp=a[i];
- low=0;
- high=i-1;
- /* if(a[i]>a[i-1]) //这句话可以稍微优化一下下速度 不影响结果
- continue;*/
- while (low<=high){
- m=(low+high)/2;
- if (temp<=a[m])
- high=m-1; //当程序跳出时 high指向的其实并不是 >=temp的值的位置 而是>=temp的值的左边的位置 所以....
- else
- low=m+1;
- }
- for( j=i;j>high+1;--j) //所以 这里的high要加一哇
- a[j]=a[j-1];
- a[j]=temp;
- }
- print(a,size);
- }
void binaryInsertSort(int *a,int size)
{
int low,high,m,temp,j;
for (int i=1;i<size;++i){
temp=a[i];
low=0;
high=i-1;
/* if(a[i]>a[i-1]) //这句话可以稍微优化一下下速度 不影响结果
continue;*/
while (low<=high){
m=(low+high)/2;
if (temp<=a[m])
high=m-1; //当程序跳出时 high指向的其实并不是 >=temp的值的位置 而是>=temp的值的左边的位置 所以....
else
low=m+1;
}
for( j=i;j>high+1;--j) //所以 这里的high要加一哇
a[j]=a[j-1];
a[j]=temp;
}
print(a,size);
}
路插入 和 表插入 过几天再说.......
4,希尔排序
希尔算法思想:将整个无序序列分割成若干小的子序列分别进行插入排序。
如 一个长度为13的数组
81 94 11 96 12 35 17 95 28 58 41 75 15
先以13/2=5为gap进行比较 即对(81 35 41)(94 17 75)(11 95 15)分别进行排序 即对数组进行一次间距为5的插入排序
之后以3 和 1为间距 对数组进行插入排序
- void shellSort(int *a,int size) // 代码取自 数据结构于问题求解(c++版)
- {
- for(int gap=size/2;gap>0;gap=gap==2?1:static_cast<int>(gap/2.2)) // 这里计算出当前的 间距
- {
- for(int i=gap;i<size;i++) // 这里跟插入排序的代码一样 不过不在是每次与前一位比较 而是与前gap位进行比较
- {
- int temp=a[i];
- int j;
- for(j=i;j>=gap&&temp<a[j-1];j-=gap)
- {
- a[j]=a[j-gap];
- }
- a[j]=temp;
- }
- }
- print(a,size);
- }
void shellSort(int *a,int size) // 代码取自 数据结构于问题求解(c++版)
{
for(int gap=size/2;gap>0;gap=gap==2?1:static_cast<int>(gap/2.2)) // 这里计算出当前的 间距
{
for(int i=gap;i<size;i++) // 这里跟插入排序的代码一样 不过不在是每次与前一位比较 而是与前gap位进行比较
{
int temp=a[i];
int j;
for(j=i;j>=gap&&temp<a[j-1];j-=gap)
{
a[j]=a[j-gap];
}
a[j]=temp;
}
}
print(a,size);
}
5,归并排序
归并操作(merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作。归并排序算法依赖归并操作。
归并操作的过程如下:
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针达到序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
- void mergeSort(int* a,int size,int* temp,int left,int right)
- {
- if(left<right)
- {
- int mid=(left+right)/2;
- mergeSort(a,size,temp,left,mid);
- mergeSort(a,size,temp,mid+1,right);
- merge(a,size,temp,left,mid+1,right);
- }
- }
- void merge(int *a,int size,int *temp,int leftPos ,int rightPos,int rightEnd)
- {
- int leftEnd=rightPos-1;
- int tempPos=leftPos;
- int num=rightEnd-leftPos+1;
- while(leftPos<=leftEnd && rightPos<=rightEnd)
- if(a[leftPos]<=a[rightPos])
- temp[tempPos++]=a[leftPos++];
- else
- temp[tempPos++]=a[rightPos++];
- while(leftPos<=leftEnd)
- {
- temp[tempPos++]=a[leftPos++];
- }
- while(rightPos<=rightEnd)
- {
- temp[tempPos++]=a[rightPos++];
- }
- for(int i=0;i<num;i++,rightEnd--)
- {
- a[rightEnd]=temp[rightEnd];
- }
- }
void mergeSort(int* a,int size,int* temp,int left,int right)
{
if(left<right)
{
int mid=(left+right)/2;
mergeSort(a,size,temp,left,mid);
mergeSort(a,size,temp,mid+1,right);
merge(a,size,temp,left,mid+1,right);
}
}
void merge(int *a,int size,int *temp,int leftPos ,int rightPos,int rightEnd)
{
int leftEnd=rightPos-1;
int tempPos=leftPos;
int num=rightEnd-leftPos+1;
while(leftPos<=leftEnd && rightPos<=rightEnd)
if(a[leftPos]<=a[rightPos])
temp[tempPos++]=a[leftPos++];
else
temp[tempPos++]=a[rightPos++];
while(leftPos<=leftEnd)
{
temp[tempPos++]=a[leftPos++];
}
while(rightPos<=rightEnd)
{
temp[tempPos++]=a[rightPos++];
}
for(int i=0;i<num;i++,rightEnd--)
{
a[rightEnd]=temp[rightEnd];
}
}
6,快速排序
一趟快速排序的算法是:
1)设置两个变量I、J,排序开始的时候:I=0,J=N-1; 2)以第一个数组元素作为关键数据,赋值给key,即 key=A[0]; 3)从J开始向前搜索,即由后开始向前搜索(J=J-1即J--),找到第一个小于key的值A[j],A[j]与A[i]交换; 4)从I开始向后搜索,即由前开始向后搜索(I=I+1即I++),找到第一个大于key的A[i],A[i]与A[j]交换;5)重复第3、4、5步,直到 I=J; (3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。找到并交换的时候i, j指针位置不
变。另外当i=j这过程一定正好是i+或j-完成的最后另循环结束。)
- int partition(int *a,int low,int high)
- <//这里从两端开始 没有考虑抽取支点的过程 支点可以选取第一个 中间点 和最后一个点 选取中间大的值 交换到数组的最后面
- {
- int pivot=a[high];
- int i,j;
- for( i=low-1,j=high;;){
- while(a[++i]<pivot &&i<high){}; //从前往后 找大于支点的
- while(a[--j]>pivot &&j>low){}; //从前往前 找小于支点的
- if(i<j){
- swap(a[i],a[j]); //若找到 则交换
- }
- else
- break;
- }
- swap(a[i],a[high]); // 将支点交换到小于与大于的分解处
- return i;
- }
- void qucikSort(int*a,int low,int high)
- {
- if(low<high)
- {
- int mid=partition(a,low,high);
- qucikSort(a,low,mid-1); //递归进行快排
- qucikSort(a,mid+1,high);
- }
- }
int partition(int *a,int low,int high)
<//这里从两端开始 没有考虑抽取支点的过程 支点可以选取第一个 中间点 和最后一个点 选取中间大的值 交换到数组的最后面
{
int pivot=a[high];
int i,j;
for( i=low-1,j=high;;){
while(a[++i]<pivot &&i<high){}; //从前往后 找大于支点的
while(a[--j]>pivot &&j>low){}; //从前往前 找小于支点的
if(i<j){
swap(a[i],a[j]); //若找到 则交换
}
else
break;
}
swap(a[i],a[high]); // 将支点交换到小于与大于的分解处
return i;
}
void qucikSort(int*a,int low,int high)
{
if(low<high)
{
int mid=partition(a,low,high);
qucikSort(a,low,mid-1); //递归进行快排
qucikSort(a,mid+1,high);
}
}
7,堆排序
取自算法导论
- int Left(int i) // 这里取左右和父节点 是以 顶节点index为0来考虑的
- {
- return i*2+1;
- }
- int Right(int i)
- {
- return i*2+2;
- }
- int Parent(int i)
- {
- return (i-1)/2;
- }
- void max_heapify(int *a,int heapSize,int i)
- // 是对最大堆进行操作的重要子程序 用于保持堆的性质
- {
- int left=Left(i);
- int right=Right(i);
- int largest;
- if(left<heapSize&&a[left]>a[i])
- largest=left;
- else
- largest=i;
- if(right<heapSize&&a[right]>a[largest])
- largest=right;
- if(largest!=i) //如果该父节点不是最大
- {
- swap(a[i],a[largest]); // 则将较大的子节点 与父节点交换 因为交换可能破坏之后的结构
- max_heapify(a,heapSize,largest); // 故 继续对交换的那个子节点做一次最大堆操作
- }
- }
- void build_max_heap(int *a,int size) //构建最大堆 (堆的大小 小于等于 数组的大小 )
- {
- int heapSize=size;
- for(int i=size/2-1;i>=0;i--)
- {
- max_heapify(a,heapSize,i);
- }
- }
- void heapSort(int* a,int size)
- {
- build_max_heap(a,size);
- int heapSize=size;
- for(int i=size-1;i>=1;i--)
- {
- swap(a[0],a[i]); // 讲顶节点与最后一个交换 最后一个节点即存的最大值
- heapSize--; //最大堆的节点个数减一 不考虑 最后点
- max_heapify(a,heapSize,0); // 交换后 重新保持最大堆的性质
- }
- }
int Left(int i) // 这里取左右和父节点 是以 顶节点index为0来考虑的
{
return i*2+1;
}
int Right(int i)
{
return i*2+2;
}
int Parent(int i)
{
return (i-1)/2;
}
void max_heapify(int *a,int heapSize,int i)
// 是对最大堆进行操作的重要子程序 用于保持堆的性质
{
int left=Left(i);
int right=Right(i);
int largest;
if(left<heapSize&&a[left]>a[i])
largest=left;
else
largest=i;
if(right<heapSize&&a[right]>a[largest])
largest=right;
if(largest!=i) //如果该父节点不是最大
{
swap(a[i],a[largest]); // 则将较大的子节点 与父节点交换 因为交换可能破坏之后的结构
max_heapify(a,heapSize,largest); // 故 继续对交换的那个子节点做一次最大堆操作
}
}
void build_max_heap(int *a,int size) //构建最大堆 (堆的大小 小于等于 数组的大小 )
{
int heapSize=size;
for(int i=size/2-1;i>=0;i--)
{
max_heapify(a,heapSize,i);
}
}
void heapSort(int* a,int size)
{
build_max_heap(a,size);
int heapSize=size;
for(int i=size-1;i>=1;i--)
{
swap(a[0],a[i]); // 讲顶节点与最后一个交换 最后一个节点即存的最大值
heapSize--; //最大堆的节点个数减一 不考虑 最后点
max_heapify(a,heapSize,0); // 交换后 重新保持最大堆的性质
}
}
8,计数排序
- void countingSort(int *a,int size,int k)
- {
- int *c=new int[k+1];
- int *b=new int[size];
- for(int i=0;i<=k;i++)
- {
- c[i]=0;
- }
- for(int j=0;j<size;j++)
- {
- b[j]=0;
- c[a[j]]++;
- }
- for(int t=1;t<k+1;t++)
- {
- c[t]=c[t]+c[t-1];
- }
- for(int t=size-1;t>=0;t--)
- {
- b[c[a[t]]]=a[t];
- c[a[t]]--;
- }
- //int pos=0; // 上面是算法导论的标准方法 下面的方式我觉得直观而且快一些
- //for(int i=0;i<=k;i++)
- //{
- // for(int t=0;t<c[i];t++)
- // b[pos++]=i;
- //
- //}
- print(b,size);
- }
void countingSort(int *a,int size,int k)
{
int *c=new int[k+1];
int *b=new int[size];
for(int i=0;i<=k;i++)
{
c[i]=0;
}
for(int j=0;j<size;j++)
{
b[j]=0;
c[a[j]]++;
}
for(int t=1;t<k+1;t++)
{
c[t]=c[t]+c[t-1];
}
for(int t=size-1;t>=0;t--)
{
b[c[a[t]]]=a[t];
c[a[t]]--;
}
//int pos=0; // 上面是算法导论的标准方法 下面的方式我觉得直观而且快一些
//for(int i=0;i<=k;i++)
//{
// for(int t=0;t<c[i];t++)
// b[pos++]=i;
//
//}
print(b,size);
}
9,桶排序
- class Node{
- public: int key;
- public: Node* next;
- };
- void bucketSort(int a[],int size,int bucketSize)
- {
- //Node **bucketNode1=(Node**)malloc(bucketSize*sizeof(Node *));
- Node ** bucketTable=new Node*[bucketSize];
- for(int i=0;i<bucketSize;i++)
- {
- //bucketNode1[i]=(Node *)malloc(sizeof(Node));
- Node* node=new Node();
- node->key=0;
- node->next=NULL;
- bucketTable[i]=node;
- }
- for(int j=0;j<size;j++)
- {
- Node* node=new Node();
- node->key=a[j];
- node->next=NULL;
- int index=a[j]/10;
- Node *buketNode=bucketTable[index]; // 找到自己应当所在的桶
- if(buketNode->key==0)
- {
- buketNode->next=node;
- bucketTable[index]->key++;
- }else{
- while(buketNode->next!=NULL && buketNode->next->key<=node->key) // 在该桶中的链表中寻找自己的位置
- buketNode=buketNode->next;
- node->next=buketNode->next; // 链表的插入操作
- buketNode->next=node;
- bucketTable[index]->key++;
- }
- int pos=0;
- for(int t=0;t<bucketSize;t++)
- {
- for(Node *p=bucketTable[t]->next;p!=NULL;p=p->next)
- {
- a[pos++]=p->key;
- }
- }
- }
- }
class Node{
public: int key;
public: Node* next;
};
void bucketSort(int a[],int size,int bucketSize)
{
//Node **bucketNode1=(Node**)malloc(bucketSize*sizeof(Node *));
Node ** bucketTable=new Node*[bucketSize];
for(int i=0;i<bucketSize;i++)
{
//bucketNode1[i]=(Node *)malloc(sizeof(Node));
Node* node=new Node();
node->key=0;
node->next=NULL;
bucketTable[i]=node;
}
for(int j=0;j<size;j++)
{
Node* node=new Node();
node->key=a[j];
node->next=NULL;
int index=a[j]/10;
Node *buketNode=bucketTable[index]; // 找到自己应当所在的桶
if(buketNode->key==0)
{
buketNode->next=node;
bucketTable[index]->key++;
}else{
while(buketNode->next!=NULL && buketNode->next->key<=node->key) // 在该桶中的链表中寻找自己的位置
buketNode=buketNode->next;
node->next=buketNode->next; // 链表的插入操作
buketNode->next=node;
bucketTable[index]->key++;
}
int pos=0;
for(int t=0;t<bucketSize;t++)
{
for(Node *p=bucketTable[t]->next;p!=NULL;p=p->next)
{
a[pos++]=p->key;
}
}
}
}
10,基数排序
11,位图排序
今后几天 会详细总结。。。。。