查找
静态查找:查找时,只查找读取
顺序表上查找
无序表上查找,设置位置0为岗哨,从后往前查找,查找长度为(n+1)/2
有序表上查找,使用二分查找,平均查找长度为 log2(n+1)-1
索引顺序表上查找,索引表将顺序表分别分割为若干块,顺序表按块有序,查找长度为 (n/s+s)/2+1
动态查找
二叉排序树:或为空树或具有下列性质:
1.若左子树不为空,则左子树上的所有结点的键值均小于它的根结点的键值,
2.若右子树不为空,则右子树上的所有结点的键值均小于它的根结点的键值,
3.根的左子树,右子树均为二叉排序树
中序遍历即可得到升序序列
查找长度与树的形态有关,介于O(n)和log2(n)之间
散列表:使数据的存储位置与键值之间建立某件联系,减少比较次数
散列函数:数据元素的键值和存储位置之间建立的对应关系H
散列表,散列地址,
冲突 k1!=k2 H(k1)=H(k2),则称k1,k2是相对H的同义词
堆积:非同义词之间对同一散列地址的争夺现象
常用散列法:数字分析法,保留余数法,平方取中发,基数转换法
解决冲突的方法:线性探测法 (地址+1) ,二次探测法(+-k2),链地址法,多重散列法,公共溢出区法
排序:内部排序,外部排序
内部排序:插入排序,交换排序,选择排序,归并排序
插入排序:直接插入排序 O(n2),折半插入排序,表插入排序,希尔排序 nlog2n n^s
直接插入排序:依次将每个记录插入到一个已排好序的有序表中去,得到一个新的,记录数增加1的有序表
void straightInertSort(List R,int n)
{
int i,j;
for(i=2;i<n;i++)
{
R[0]=R[i];
j=i-1;
while(R[0]<R[j])
{
R[j+1]=R[j];
j--;
}
R[j+1]=R[0];
}
}
希尔排序:以n/2为步长分割List,排序分割的List,再以原步长/2,重复执行,知道步长为0 结束排序。
交换排序:冒泡排序O(n2) ,快速排序 (不稳定,nlog2n n2)
冒泡排序:是一种交换排序方法,首先将第一个记录和第二个记录比较,若为逆序,则将两个记录交换,然后比较第二个和第三个,依次类推,直到完成第n-1和第n个比较交换位置。此为第一趟起泡。结果使键值最大的记录移动到第n个位置上。然后对前n-1个记录进行同样的操作。
void BubbleSort(List R,int n)
{
int i,j,temp,endSort;
for(i=1;i<=n-1;i++)
{
endSort=0;
for(j=1;j<=n-1-i;j++)
{
if(R[j].key>R[j+1].key)
{
temp=R[j];
R[j]=R[j+1];
R[j+1]=temp;
endSort=1;
}
}
if(endSort==0)break;
}
}
快速排序:
void QuickSort(List R,int low,int high)
{
if(low<high)
{
temp=QuickPartition(R,low,high);
QuickSort(R,low,temp-1);
QuickSort(R,temp+1,high);
}
}
int QuickPartition(List R,int low,int high)
{
x=R[low];
while(low<high)
{
while(low<high&&R[high].key>x.key)
{
high--;
}
R[low]=R[high];
while(low<high&&R[low].key<x.key)
{
low++;
}
R[high]=R[low];
}
R[low]=x;
return low;
}
选择排序:直接选择排序(不稳定 O(n^2)),堆排序(不稳定 nlog2n)
直接选择排序:在第i次选择操作中,通过第n-i次键值比较,从n-i+1个记录中,选出最小的键值记录,并和第i个记录交换。
void SelectSort(List R,int n)
{
int min,i,j
for(i=1;i<=n-1;i++)
{
min=i;
for(j=i+1;j<=n;j++)
{
if(R[j].key<R[min].key) min=j;
if(min!=i) swap(R[min],R[i]);
}
}
}
堆排序:最小堆是一颗以k1为根的完全二叉树,任一结点都不大于它的两个孩子的值。
void HeapStort(List R,int n)
{
int i;
for(i=n/2;i>=1;i++)
Shit(R,i,n);
for(i=n;i>=2;i--)
{
Swap(R[1],R[i]);
Shit(R,1,i-1);
}
}
List为完全二叉树 顺序结构存储
K为 根结点序号
m为 顺序存储结构最后一个结点位置
void Shit(List R,int k,int m)
{
int i,j,x;
List t;
i=k;j=i*2;
x=R[k].key;
t=R[k];
while(j<=m)
{
if(j<m)&&R[j].key>R[j+1].key)
{
j++;
}
if(x<R[j].key) break;
else
{
R[i]=R[j];
i=j;
j=2*i;
}
}
}
归并排序:有序序列的归并(不稳定的 nlog2n),二路归并排序(稳定的 nlog2n)
要求待排序序列是有若干有序子序列组成
有序序列的归并: a h m n
二路归并排序:有n个有序的子序列,每个序列的长度为1,首先将相邻的两个记录合并,得到较大的n/2个较大的有序子序列,再将相邻的子序列两两合并,得到[[n/2]/2]个有序的子序列,如此反复,直到得到一个长度为n的有序序列位置。
排序算法中,没有那种是最优的,就时间复杂度而言,比较简单的排序算法,直接插入,直接选择,冒泡排序等,所需时间复杂度为O(n^2).但是在某些情况下,如初始序列已基本有序,直接插入算法和冒泡算法时间复杂度为O(n)。就待排序列的记录数量而言,当记录数较小时,尽量选择简单的排序算法,当n比较大时并且记录无规律可言时,采用快速排序,堆排序,归并排序等时间复杂度较低的算法。快速排序,直接选择排序,堆排序是不稳定的算法。