一、归并排序
// C语言版
//一趟归并
static void Merge(int *arr,int len,int gap)
{
int low1 = 0;//第一个归并的的起始下标
int high1 = gap-1;//第一个归并段的结尾下标
int low2 = high1+1;//第二个归并段的起始下标
int high2 = low2+gap-1<len-1 ? low2+gap-1 : len-1;//第二个归并段的结尾下标
int *brr = (int *)malloc(sizeof(int)*len);//存放归并好的数据
int i = 0;//brr下标
//有两个归并段
while(low2 <= high2)
{
//两个归并段都还有数据
while(low1<=high1 && low2<=high2)
{
if(arr[low1] <= arr[low2])
{
brr[i++] = arr[low1++];
}
else
{
brr[i++] = arr[low2++];
}
}
//一个段数据归并完成,另一个还有数据
while(low1 <= high1)
{
brr[i++] = arr[low1++];
}
while(low2 <= high2)
{
brr[i++] = arr[low2++];
}
low1 = high2+1;
high1 = low1+gap-1;
low2 = high1+1;
high2 = low2+gap-1<len-1 ? low2+gap-1 : len-1;
}
//不足两个归并段
while(low1 < len)
{
brr[i++] = arr[low1++];
}
for(i=0;i<len;i++)
{
arr[i] = brr[i];
}
free(brr);
}
void MergeSort(int *arr,int len)//O(nlogn),O(n),稳定
{
for(int i=1;i<len;i*=2)//归并段的长度
{
Merge(arr,len,i);
}
}
int main()
{
int arr[] = {4,9,0,12,34,67,8,91,32,54,66,88,2};
//SelectSort(arr,sizeof(arr)/sizeof(arr[0]));
//HeapSort(arr,sizeof(arr)/sizeof(arr[0]));
MergeSort(arr,sizeof(arr)/sizeof(arr[0]));
Show(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
template<class Type>
void PrintArray(Type *ar,int n) //打印数组
{
for(int i = 0;i<n;++i)
{
cout<<ar[i]<<" ";
}
cout<<endl;
}
template<class Type> //数组拷贝 di<---si
void CopyArray(Type *di,Type *si,int left,int right) // di<---si
{
for(int i = left; i<=right; ++i)
{
di[i] = si[i];
}
}
template<class Type>
void Merge(Type *di,Type *si,int left, int m,int right)
{
int i = left, j = m+1;
int k = i;
while(i <= m && j <= right)
{
di[k++] = si[i] < si[j] ? si[i++]:si[j++];
}
while(i <= m)
{
di[k++] = si[i++];
}
while(j <= right)
{
di[k++] = si[j++];
}
}
template<class Type>
void PassMerge(Type *br,Type *ar,int left,int right)
{
if(left < right) // left = 1 right = 2
{
int mid = (right - left)/2 + left;
PassMerge(br,ar,left,mid);// 1,1
PassMerge(br,ar,mid+1,right);//2,2
Merge(br,ar,left,mid,right);
CopyArray(ar,br,left,right);
}
}
template<class Type>
void MergeSort(Type *ar,int n)
{
assert(ar != NULL && n >0);
Type *br = new Type[n];
PassMerge(br,ar,0,n-1);
delete []br;
}
//非递归 归并排序
template<class Type>
void NicePassMerge(Type *di,Type *si,int n,int s)
{
int i = 0;
cout<<s<<endl;
for(i = 0; i+2*s-1 <= n-1 ;i+=2*s)
{
Merge(di,si,i,i+s-1,i+2*s-1);
cout<<i<<" "<<i+s-1<<" "<<i+2*s-1<<endl;
}
if(n-1 > i+s-1)
{
Merge(di,si,i,i+s-1,n-1);
cout<<i<<" "<<i+s-1<<" "<<n-1<<endl;
}
else
{
for(int j = i;j<n;++j)
{
di[j] = si[j];
}
}
}
template<class Type>
void NiceMergeSort(Type *ar,int n)
{
assert(ar != NULL && n >0);
Type *br = new Type[n];
int s = 1;
while(s < n)
{
NicePassMerge(br,ar,n,s); // 1
s+=s;
NicePassMerge(ar,br,n,s);
s+=s;
}
delete []br;
}
int main()
{
int ar[]={56,67,12,23,90,85,45,78,34,100,20};
int n = sizeof(ar)/sizeof(ar[0]);
PrintArray(ar,n);
NiceMergeSort(ar,n);
PrintArray(ar,n);
return 0;
}
二、树的概念
概念:
-
节点的度:一个节点含有的子树的个数称为该节点的度
-
树的度:一棵树中,最大的节点的度称为树的度(上图B节点 3个度 最大);
-
叶节点或终端节点:度为零的节点
-
父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点
-
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
-
兄弟节点:具有相同父节点的节点互称为兄弟节点;
-
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
-
树的高度或深度 :树中节点的最大层次(上图为5层);
-
堂兄弟节点:父节点在同一层的节点互为堂兄弟
-
森林:由m(m>=0)棵互不相交的树的集合称为森林;
种类: -
无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树;
-
有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;
-
二叉树:每个节点最多含有两个子树的树称为二叉树;
-
完全二叉树:对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;
-
满二叉树:所有叶节点都在最底层的完全二叉树;
-
平衡二叉树:当且仅当任何节点的两棵子树的高度差不大于1的二叉树;
-
排序二叉树(二叉查找树)(英语:Binary Search Tree),也称二叉搜索树、有序二叉树)
二叉树的性质:
- 在二叉树的第i层上至多有2^(i-1)个结点。
- 深度为k的二叉树之多有(2^k)-1个结点。
- 对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点树为n2,则n0=n2+1
- 具有n个结点的完全二叉树的深度为(logn)+1
- 如果对一棵有n个结点的完全二叉树的结点按层序号遍历,对任意结点i有:
如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点i/2。
如果2i>n,则结点i无左孩子;否则其左孩子是结点2i。
如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1.