template<class T>
int SequentialSearch(T a[], const T& x, int n)
{
int i;
for(int i=0; i<n; i++)
if(i == n) return -1;
return i;
}
template<class T>
int BinarySearch(T a[], const T& x, int n)
{
int left=0, right=n-1;
while(left <=right)
{
int middle = (left+right)/2;
if(a[middle] == x) return middle;
if(x>a[middle]) left = middle+1;
else right = middle-1;
}
return -1;
}
排序方法 | 计数排序 | 选择排序 | 冒泡排序 | 插入排序 |
---|---|---|---|---|
元素交换次数 | 2n | 3n-1 | 0~n-1 | 0~n-1 |
元素比较次数 | (n-1)n/2 | (n-1)n/2 | (n-1)n/2 | (n-1)n/2 |
- 计数排序
template<class T>
void Rearrenge(T a[], int n, int r[]) //r[]为排名
{
T *u = new T[n+1];
for(int i=1; i<n; i++)
u[r[i]] = a[i];
for(int i=1; i<n; i++)
a[i] = u[i];
delete [] u;
}
template<class T>
void SelectSort(T a[], int n)
{
for(int size=n; size>1; size--)
{
int j = Max(a,size);
Swap(a[j], a[size-1]);
}
}
template<class T>
void Bubble(T a[], int n)
{
for(int i=0; i<n; i++)
if(a[i]>a[j+1]) Swap(a[i],a[i+1]);
}
void BubbleSort(T a[],int n)
{
for(int i=n; i>1; i--)
Bubble(a,i);
}
template<class T>
void Insert(T a[], int n, const T&x)
{
int i;
for(i=n-1; i>1&&x<a[i]; i--)
a[i+1] = a[i];
a[i+1] = x;
}
void InsertSort(T a[], int n)
{
for(int i=1; i<n; i++)
{
T t = a[i];
Insert(a,i,t);
}
}
描述方法 | 公式化描述 | 链表描述 | 间接寻址 |
---|---|---|---|
查找第k个元素 | ⊖(1) | O(k) | ⊖(1) |
删除第k个元素 | O((n-k)s) | O(k) | O(n-k) |
在第k个元素后插入 | O((n-k)s) | O(k+s) | O(n-k) |
s和n分别表示sizeOf(T)和链表长度
在箱子排序过程中,节点首先被放入箱子之中,具有相同分数的节点都放在同一个箱子中,然后通过把箱子链接起来就可以创建一个有序的链表
4 0 0 0 0
0 2 0 0 0
0 0 7 0 0
0 0 0 3 0
0 0 0 0 2
由于一个对角矩阵最多包含n个非0元素,可以采用一维数组来描述:
T d[n]
2 1 0 0
3 1 3 0
0 5 2 7
0 0 9 0
在一个n*n三对角矩阵T中,非0元素排列在三条对角线上:
1. 主对角线 —— i=j
2. 低对角线 —— i-j=1
3. 高对角线 —— i-j=-1
元素总数:3n-2
2 1 3 0 2 0 0 0
0 1 3 8 4 1 0 0
0 0 1 6 6 9 4 0
0 0 0 0 0 5 7 0
上三角矩阵 下三角矩阵
元素个数:n(n+1)/2
只存储上三角或下三角即可
堆栈是一个线性表,是一个后进先出的数据结构(LIFO)
插入和删除操作都在表的同一端进行,一端称为栈顶top,另一端称为栈底bottom
在这个问题中将要一个字符串的左、右括号:
思路:
在从左到右扫描字符串的过程中,每当遇到左括号就将其放于堆栈中,每当遇到右括号时就从栈顶删除一个左括号
bool IsFull() const
{
return (((rear+1)%MaxSize==front)?1:0);
}
//如果队列满会报错
template<class T>
bool LinkedQueue<T>::IsFull() const
{
Node<T> *p;
try
{
p = new Node<T>;
delete p;
return false;
}catch(NoMem)
{
return true;
}
}
字典是一些元素的集合,每个元素有一个称作key的域,不同元素的key各不相同
级的分配
1.假设一随机数产生器产生随机数0~RAND_MAX,则下次产生的随机数小于等于CutOff=p*RAND_MAX的概率为p
2.级MaxLevel的最大值为⌈log(1/p) N⌉-1
在跳表中搜索
template<class E, class K>
bool SkipList<E,k>::Search(const K& k, E& e)
{
if(k>=TailKey) return false;
SkipNode<E,K> *p = head;
for(int i=Levels; i>=0; i--)
while(p->link[i]->data<k)
p = p->link[i];
e = e->link[0]->data;
return (e==k);
}
是用一个散列函数把关键字映射到散列表中的特定的位置,如果元素e的关键字为k,散列函数为f,那么e在散列表中的位置为f(k)
方法
除法散列函数:f(k) = k % D
插入
如果发生了碰撞(溢出),将插入到起始桶后面的空桶中;
在寻找下一个可用桶的过程中,表被视为环形的
搜索
首先搜索起始桶,会发生下面情况:
1.存有关键词K的桶找到
2.到达空桶
3.回到f(k)
若发生2.3,则说明表中没有关键字为K的元素
删除(会带来多个元素的移动)
1.一种策略:
从欲删除的元素开始逐个检查每个桶,以确定要移动的元素
2.另一种:
为每个桶增加NeverUsed域
包含n个元素的二叉树的边数为n-1
若二叉树的高度为h,则元素最少为h,最多为2^h - 1
当缺少很多元素时,很浪费空间,一个有n个元素的二叉树可能最多需要2^n - 1个空间
前序遍历:先访问根节点,然后访问左子树、右子树
中序遍历:先访问左子树,然后访问根节点、右子树
后序遍历:先访问左子树、右子树,然后访问根节点
template<class T>
MaxHeap<T>& MaxHeap<T>::Insert(const T& x)
{
if(CurrentSize == MaxSize)
throw NoMem();
int i = ++CurrentSize;
while(i!=1 && x>heap[i/2])
{
heap[i] = heap[i/2];
i /= 2;
}
heap[i] = x;
return *this;
}
从最大堆中删除一个元素时,删除根部元素
时间复杂性为O(height) = O(log2 n)
template<class T>
MaxHeap<T>& MaxHeap<T>::Delete(T &x)
{
if(Current == 0)
throw OutOfBounds();
x = heap[1];
T y = heap[CurrentSize-];
int i = 1, ci = 2;
while(ci<=CurrentSize)
{
//heap[ci]应该为较大的孩子
if(ci<Currentsize && heap[ci]<heap[ci+1])
ci++;
if(y>heap[ci]) break; //能把y放入heap[i]
//不能
heap[i] = heap[ci];
i = ci;
ci *= 2;
}
heap[i] = y;
return *this;
}
为了将完全二叉树转化为最大堆,从第一个具有孩子的节点开始,位置为i=[n/2],如果以这个元素为根的子树已是最大堆,此时不需调整,否则需要调整使之称为堆,随后继续检查i-1,i-2等节点,直至检查至根节点
时间复杂性O(nlongn)
template<class T>
void MaxHeap<T>::Initialize(T a[], int size, int ArraySize)
{
delete heap;
heap = a;
CurrentSize = size;
MaxSize = ArraySize;
for(int i=CurrentSize/2; i>=1; i--)
{
T y = heap[i];
int c = 2*i;
while(c<=CurrentSize)
{
if(c<CurrentSize && heap[c]<heap[c+1])
c++;
if(y>=heap[c]) break;
heap[c/2] = heap[c];
c *= 2;
}
heap[c/2] = y;
}
}
首先将一个数组初始化为一个最大堆,然后从堆中依次删除元素,然后各元素就以递减的顺序排好序了,时间复杂度为O(nlogn)
为了构造霍夫曼树,首先从仅含一个外部节点的二叉树集合开始,每个外部节点代表字符串中一个不同的字符,其权重等于盖子负的频率,此后不断地从集合中选择两棵具有最小权重的二叉树,并合并为一棵二叉树,合并方法是把这两棵二叉树分别作为左右子树然后增加一个新的根节点,新二叉树权重为两子树之和,该过程持续至只剩一棵树
搜索
假设需要寻找关键值为K的元素,如果根为空,失败;如果K小于根节点关键值,那么在左子树中搜索;反之,在右子树中搜索
时间复杂性:O(nlogn)
插入
若插入元素e,先要验证e的关键值与树中已有关键字是否重合
删除
情况1:
p是树叶,直接丢弃树叶节点
情况2:
p只有一个子树,若p是根节点,则根节点直接指向p的孩子,然后删除p;若p有父节点,则将p父节点指向p的孩子,然后删除p
情况三:
p有左右子树,需要将该元素替换为左子树中最大元素或者右子树的最小元素
搜索(同二叉树)
时间复杂性O(nlogn)
插入
LL、LR、RR、RL型不平衡
删除
R0、R1、R-1;L0、L1、L-1
By Yuanhang, Luo