排序和查找算法实现
前面转载了一篇讲排序算法的文章,这几天将排序和查找算法进行了实现,在这里贴出代码来。
1. 插入排序
插入排序——直接插入排序:将一个记录插入到已排序好的有序表中,就像打扑克牌揭到牌后插入在特定位置。
#include<iostream>
using namespace std;
void sort(int a[],int n) //插入排序算法
{
inti,j,temp; //定义循环变量i,j以及临时变量temp
for(i=1;i<n;i++) //依次将数组中每一个a[i]插入到适当位置
{
j=i-1;
temp=a[i];
while(temp<a[j])
{
a[j+1]=a[j]; //交换a[j]往后移动
j--;
}
a[j+1]=temp;
/* for(int i=0;i<n;i++) //这里为了便于理解,打印出了每次for循环后的结果
{
cout<<a[i]<<"";
}
cout<<endl;
*/
}
}
void print(int *a, int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<"";
}
cout<<endl;
}
int main()
{
inta[]={43,1,9,54,32,17,88,24,72,48};
print(a,10);
sort(a,10);
print(a,10);
return 0;
}
下面这个冒泡排序代码和插入排序很相似
#include<iostream>
using namespace std;
void sort(int a[],int n) //冒泡排序算法
{
inti,j,temp; //定义循环变量i,j以及用于交换的临时变量temp
for(i=1;i<n;i++) //依次将数组中每一个a[i]插入到适当位置
{
for(j=0;j<i;j++)
{
if(a[j]>a[i])
{
temp=a[j]; //交换a[j]与a[i]
a[j]=a[i];
a[i]=temp;
}
}
/* for(inti=0;i<n;i++) //这里为了便于理解,打印出了每次for循环后的结果
{
cout<<a[i]<<"";
}
cout<<endl;
*/
}
}
void print(int *a, int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<"";
}
cout<<endl;
}
int main()
{
inta[]={43,1,9,54,32,17,88,24,72,48};
print(a,10);
sort(a,10);
print(a,10);
return 0;
}
2. 插入排序——希尔排序
插入排序——希尔排序:将一个序列分成多次进行直接插入排序,当步长为1的时候,就是直接插入排序。
#include<iostream>
using namespace std;
void sort(int a[],int n) //希尔排序算法
{
inti,j,k,h,temp; //定义循环变量i,j和数组下标变量k以及用于交换的临时变量temp,h为步长
for(h=n/2;h>0;h=h/2) //h为序列分组步长,下一次步长是上一次的一半
{
for(i=0;i<n/h;i++) //依次插入数组中每一个数a[i],步长为h,循环n/h次就将数组遍历完了
{
k=i; //每次开始时,记录下标到k
for(j=i;j<n;j=j+h) //j每次增加步长h,即序列中间隔步长比较
{
if(a[k]>a[j]) //寻找它后面的数中最小的数
k=j; //交换下标,k记录了最小的数的下标
}
temp=a[k]; //交换a[i]与a[i]后面最小的数的位置
a[k]=a[i];
a[i]=temp;
}
/* for(int i=0;i<n;i++) //这里为了便于理解,打印出了每次for循环后的结果
{
cout<<a[i]<<"";
}
cout<<endl;
*/
/*
原序列 43 1 9 54 32 17 88 24 72 48
第一次排序: 17 1 9 54 32 43 88 24 72 48
第二次排序: 9 17 32 72 88 --直接插入排序
1 24 43 48 54 --直接插入排序
第三次排序: 1 9 17 24 32 43 48 54 72 88
*/
}
}
void print(int *a, int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<"";
}
cout<<endl;
}
int main()
{
inta[]={43,1,9,54,32,17,88,24,72,48};
print(a,10);
sort(a,10);
print(a,10);
return0;
}
3. 冒泡排序
冒泡排序:让较大的数往下沉,较小的往上冒。
#include<iostream>
using namespace std;
void sort(int a[],int n) //冒泡排序算法
{
inti,j,temp; //定义循环变量i,j用于交换的临时变量temp
for(i=0;i<n;i++) //依次比较数组中每一个数a[i]
{
for(j=i+1;j<n;j++)//将a[i]后的每一个a[j]与其进行比较
{
if(a[i]>a[j]) //如果a[j]比a[i]小,交换a[i]与a[j],使a[j]往上冒泡
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
/* for(int i=0;i<n;i++) //这里为了便于理解,打印出了每次for循环后的结果
{
cout<<a[i]<<"";
}
cout<<endl;
*/
}
}
void print(int *a, int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<"";
}
cout<<endl;
}
int main()
{
inta[]={43,1,9,54,32,17,88,24,72,48};
print(a,10);
sort(a,10);
print(a,10);
return0;
}
4. 快速排序
快速排序:首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。然后递归调用此函数
#include<iostream>
using namespace std;
void print(int *a, int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
void sort(int a[], int left, int right)
{
if(left >= right)
{
return;
}
int i = left;
int j = right;
int key = a[i]; /*用第一个记录作为关键字*/
while(i < j)
{
while(i < j && a[j] >= key) j--;
a[i] = a[j]; /*将比第一个小的移到低端*/
while(i < j && a[i] <= key) i++;
a[j] = a[i]; /*将比第一个大的移到高端*/
}
a[i] = key; /*关键字记录到位*/
//print(a,10);
sort(a, left, i-1);
sort(a, i+1, right);
}
int main()
{
int a[]={43,1,9,54,32,17,77,24,72,48};
print(a,10);
sort(a,0,9); //注意:这里参数传递的是数组的下标,所以最大到9
print(a,10);
return 0;
}
5. 选择排序——简单选择排序
选择排序——简单选择排序:在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换;依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
#include<iostream>
using namespace std;
void sort(int a[],int n) //简单排序算法
{
inti,j,k,temp; //定义循环变量i,j和数组下标变量k以及用于交换的临时变量temp
for(i=0;i<n-1;i++) //依次插入数组中每一个数a[i]
{
k=i; //每次开始时,记录下标到k
for(j=i+1;j<n;j++)
{
if(a[k]>a[j]) //寻找它后面的数中最小的数
k=j; //交换下标,k记录了最小的数的下标
}
temp=a[k]; //交换a[i]与a[i]后面最小的数的位置
a[k]=a[i];
a[i]=temp;
/* for(int i=0;i<n;i++) //这里为了便于理解,打印出了每次for循环后的结果
{
cout<<a[i]<<"";
}
cout<<endl;
*/
}
}
void print(int *a, int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<"";
}
cout<<endl;
}
int main()
{
inta[]={43,1,9,54,32,17,88,24,72,48};
print(a,10);
sort(a,10);
print(a,10);
return0;
}
6. 归并排序
归并排序:归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
#include<iostream>
using namespace std;
void print(int *a, int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<"";
}
cout<<endl;
}
//将a[i…m]和a[m +1 …n]归并到辅助数组b[i…n]
void merge(int *a,int *b, int i, int m, intn)
{
int j,k;
for(k=i,j=m+1; i<=m && j <=n ; k++)
{
if(a[j] < a[i])
b[k]= a[j++];
else
b[k]= a[i++];
}
//如果a[i…m]和a[m +1 …n]的长度不一样,在上面的for循环中有一个提前终止,则用下面的while循环继续移动
while(i <= m) b[k++] =a[i++];
while(j <= n) b[k++] =a[j++];
print(b,n+1); //代码测试,输出结果
}
void sort(int *a, int *b, int lenght)
{
int len = 1;
int *temp ;
while(len < lenght)
{
int s = len;
len = 2 * s ;
int i = 0;
while(i+ len <lenght)
{
merge(a, b, i, i+ s-1, i+ len-1); //对等长的两个子表合并
i = i+ len;
}
//按照上面等长合并后,序列最后的几个数可能不能按照等长合并,则将最后几个数和其前面一组等长合并的子序列统一合并
merge(a, b, i, i+ s-1, lenght-1); //对不等长的两个子表合并,此时合并到了序列最末端
temp = a; //交换a,b,以保证下一趟归并时,仍从a归并到b
a= b;
b= temp;
}
}
int main()
{
inta[]={43,1,9,54,32,17,88,24,72,48};
int b[10];
print(a,10);
sort(a,b,10);
print(a,10);
return0;
}
7. 基数排序
基数排序:简单来说,就是把数据分组,放在一个个的桶中,然后对每个桶里面的在进行排序。然后收集数据,再放入桶中,循环此操作。
例如,在整理扑克牌顺序时,先按红、黑、方、花的顺序分成4摞(分配),再按此顺序再叠放在一起(收集);然后按面值的顺序分成13摞(分配),再按此顺序叠放在一起(收集),如此进行二次分配和收集即可将扑克牌排列有序。
#include<iostream>
using namespace std;
void print(int *a, int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<"";
}
cout<<endl;
}
int maxbit(int a[], int n) //辅助函数,求数据的最大位数,即后面最外层循环的次数
{
int d = 1; //保存最大的位数
int p = 10;
for(int i = 0; i < n; ++i)
{
while(a[i] >= p)
{
p *= 10;
d++;
}
}
return d;
}
void sort(int a[], int n) //基数排序
{
int d = maxbit(a, n);
int *box= new int[n]; //箱子,桶
int *count = new int[10]; //计数器
int i, j, k;
int radix = 1; //倍率
for(i=0; i<d; i++) //进行d次排序
{
for(j = 0; j < 10; j++) //每次分配前清空计数器
count[j] = 0;
for(j = 0; j < n; j++) //统计每个桶中的记录数
{
k = (a[j] / radix) % 10;
count[k]++;
}
for(j = 0; j < 10; j++) //代码测试,观看每个桶中数的个数count[j]
cout<< count[j] <<" ";
cout<<endl;
for(j= 1; j < 10; j++) //将box中的位置依次分配给每个桶
count[j] = count[j - 1] + count[j];
for(j = 0; j < 10; j++) //代码测试
cout<< count[j] <<" ";
cout<<endl;
for(j = n - 1; j >= 0; j--) //将所有记录依次放到桶中
{
k = (a[j] / radix) % 10;
box[count[k] - 1] = a[j];
count[k]--;
}
for(j = 0; j < 10; j++) //代码测试
cout<< box[j] <<" ";
cout<<endl;
//将已分配好的桶中数据再倒出来(收集数据),此时已是对应当前位数有序的表
for(j = 0; j < n; j++) //将box复制到a中,为下一次分入不同桶做准备
a[j] = box[j];
radix = radix * 10;
print(a,10);
}
delete[]box;
delete[]count;
}
int main()
{
inta[]={43,1,9,54,32,17,88,24,72,48};
print(a,10);
sort(a,10);
print(a,10);
return0;
}
8. 堆排序
此程序来自百科百度,因为写的相对比较简练,所以拿过来了。
大根堆:所有子节点都小于父节点。
小根堆:所有子节点都大于父节点。
堆排序:将a[n]看作一棵完全二叉树的存储结构,先将a[n]建成一个大堆,此时是无序的,再将a[1]和无序区的最后一个元素a[n]交换,得到新无序区a[1...n-1]和有序区a[n],调整无序区a[1...n-1]为大根队,与无序区的最后一个元素a[n-1]交换;重复上述操作。
#include <iostream>
using namespace std;
//交换函数,参数传入为地址
void swap(int *a,int *b)
{
inttemp;
temp=*a;
*a=*b;
*b=temp;
}
//本函数功能是:根据数组array构建大根堆
void HeapAdjust(int array[],int i,intnLength) //array是待调整的堆数组,i是待调整的数组元素的位置,nlength是数组的长度
{
int nChild;
for(;2*i+1<nLength;i=nChild)
{
nChild=2*i+1; //子结点的位置=2*(父结点位置)+1
if(nChild<nLength-1 && array[nChild+1]>array[nChild])
++nChild; //得到子结点中较大的结点
if(array[i]<array[nChild]) //如果子结点大于父结点那么交换子结点和它的父结点
swap(array[i],array[nChild]);
else
break; //否则退出循环
}
}
//堆排序算法
void HeapSort(int array[],int length)
{
int i;
for(i=length/2-1;i>=0;--i) //调整序列的前半部分元素,调整完之后第一个元素是序列的最大的元素 length/2-1是最后一个非叶节点,此处"/"为整除
HeapAdjust(array,i,length);
for(i=length-1;i>0;--i) //从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
{
swap(array[i],array[0]); //把第一个元素和当前的最后一个元素交换,
HeapAdjust(array,0,i); //不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值
}
}
int main()
{
int i;
int num[]={9,3,0,2,5,4,8,6,1,7};
HeapSort(num,sizeof(num)/sizeof(int));
for(i=0;i<sizeof(num)/sizeof(int);i++)
cout<<num[i]<<" ";
return 0;
}
9. 二叉树排序
二叉树排序:将一个无序记录插入到建立的二叉树中,二叉树采用左低右高形式,然后用中序遍历二叉树排序。
#include<iostream>
using namespace std;
class node //树节点类
{
public:
intdata; //数据
node*parent; //根指针
node*left; //左子树指针
node*right; //右子树指针
public:
node(intnum):data(num),parent(NULL),left(NULL),right(NULL) {}; //构造函数,初始化数据成员
};
class tree //树类
{
public:
tree(intnum[],int len); //构造函数
voidinsertNode(int data); //插入结点
voidinOrderTree(); //中序遍历
private:
voidinsertNode(node *current,int data); //插入结点的递归函数
voidinOrderTree(node *current); //中序遍历递归函数
node*root; //树根
};
tree::tree(int num[],int len)
{
root=newnode(num[0]); //构造函数中初始化树根
for(int i=1;i<len;i++) //循环插入树节点
insertNode(num[i]);
}
void tree::insertNode(int data) //插入结点时,调用私有的插入函数
{
if(root!=NULL)
insertNode(root,data);
}
void tree::insertNode(node *current,intdata)
{
if(data< current->data)
{
if(current->left== NULL)
{
current->left=new node(data);
current->left->parent=current;
}
else
insertNode(current->left,data);
}
elseif(data > current->data)
{
if(current->right== NULL)
{
current->right=new node(data);
current->right->parent=current;
}
else
insertNode(current->right,data);
}
return;
}
void tree::inOrderTree() //中序遍历,调用私有中序遍历函数
{
if(root==NULL)
return;
inOrderTree(root);
}
void tree::inOrderTree(node *current)
{
if(current!=NULL)
{
inOrderTree(current->left);
cout<<current->data<<" ";
inOrderTree(current->right);
}
}
int main()
{
inta[8]={5,3,7,2,4,6,8,1};
treet(a,8); //利用构造函数建立树
t.inOrderTree(); //中序遍历
return0;
}
10. 顺序查找
顺序查找(简单查找):在一组无序数列中,查找特定某个数值,并返回其位置pos。
#include<iostream>
using namespace std;
#define MAX 20 //定义数组元素的个数
void randarray(int num[]) //随机产生数组元素并输出
{
for(int i=0; i<MAX; i++)
cout<<(num[i]=rand()%100)<<" ";
}
int find(int num[], int x) //从数组开头依次查找,如果找到返回查找到的位置
{
for(int i=0; i<MAX; i++)
if(x == num[i])
return i;
return 0;
}
void main()
{
int x, pos, num[MAX];
randarray(num);
cout<<endl<<"Enterfind num: ";
cin>>x;
pos=find(num, x);
if(pos)
cout<<"OK! "<<x<<" is found in pos:"<<pos<<endl;
else
cout<<"Sorry! "<<x<<" is not found inthe array"<<endl;
}
11. 折半查找
折半查找(二分查找):二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x。
#include<iostream>
using namespace std;
#define MAX 10 //定义数组元素的个数
void randarray(int a[],int n) //随机产生数组元素并输出
{
for(int i=0; i<n; i++)
a[i]=rand()%100;
}
void print(int a[], int n) //数组输出函数
{
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
}
void sort(int a[], int low, int high) //快速排序算法
{
int i,j,pos;
if(low< high)
{
pos=a[low];
i=low;
j=high;
while(i<j)
{
while(i<j&& a[j]>pos) j--; //查找比pos小的数a[j],往后放
a[i]=a[j];
while(i<j&& a[i]<pos) i++; //查找比pos大的数a[i],往前放
a[j]=a[i];
}
a[i]=pos;
sort(a,low,i-1); //注意,这里是i-1
sort(a,i+1,high);
}
}
int find(int a[], int n,int x) //二分查找,如果找到返回查找到的位置
{
int low=0,high=n;
int mid;
while(low<=high)
{
mid=(low+high)/2;
if(a[mid]>x)
high=mid-1;
else if(a[mid]<x)
low=mid+1;
else
{
return mid; //这里有一个bug,如果找的数位于a[0],则找到后,mid=0,return 0后会返回没找到的假象
break;
<span style="white-space:pre"> </span> }
}
return 0;
}
void main()
{
int x, pos, a[MAX];
randarray(a,MAX);
print(a,MAX);
sort(a,0,MAX-1);
print(a,MAX);
cout<<endl<<"Enterfind num: ";
cin>>x;
pos=find(a,MAX, x);
if(pos)
cout<<"OK! "<<x<<" is found in pos after sorted: "<<pos<<endl;
else
cout<<"Sorry! "<<x<<" is not found inthe array"<<endl;
}