数据结构和算法

1、 概论
级数

算数级数:与末项平方同阶

T(n)=1+2+.....+n=n(n+1)/2=O(n^2)

幂方级数:比幂次高出一阶

T2(n)=1^2+2^2+......+n^2=O(n^3)

几何级数:与末项同阶

Ta(n)=a^0+a^1+a^3+.....+a^n=O(a……n)

收敛级数:O(1)

1/3+1/7+1/8+.....+....=1=O(1)

未必收敛,但是长度有限

调和级数:h(n)=1+1/2+1/3+......+1/n=O(logn)
对数级数:log1+log2+log3+.....+logn=log(n!)=O(nlogn)
迭代和递归
减而治之
分而治之
(f)动态规划
2、向量vector
(a)接口和实现
size()   //返回元素总数
get(r)    //获取标号为r的元素
put(r,e)    //用e替代标号为r的数值
insert(r,e)   //在r位置插入元素e,原后续元素后移
remove(r)    //删除r位置的元素,返回该元素存放的对象
disordered()  //判断所有元素是否按照非降序排列
sort()         //非降序排序
find(e)         //寻找目标元素e
search(e)
dedupicate()
uniquify()
traverse()
typedef 数据类型 新的名称
#define 新的名称 具体内容
vector模板类
typedef int Rank;  //秩
#define DEFAULT_CAPACITY 3   //默认初始容量(实际可以设置较大)
template <typename T> class Vector{//向量模板类
    private:Rank_size;int_capacity;T*_elem;
    protected:
		//内部函数
    public:
    	//构造函数
    	//析构函数
    	//只读接口
    	//可写接口
    	//遍历函数
};
析构
typedef int Rank;  //秩
#define DEFAULT_CAPACITY 3   //默认初始容量(实际可以设置较大)
template <typename T> class Vector{//向量模板类
    private:Rank_size;int_capacity;T*_elem;
    protected:
		//内部函数
    public:
    	//构造函数
    	//析构函数
    	//只读接口
    	//可写接口
    	//遍历函数
};
析构和构造
Vector(int c=DEFAULT_CAPACITY)    //默认
{
    _elem=new T[_capacity=c];
    _size=0;
}
Vector(T const *A,Rank lo,Rank hi)  //数组区间复制
{
    copyFrom(A,lo,hi);
}
Vector(Vector<T> const& V,Rank lo,Rank hi)//向量区间复制
{
    copyFrom(V._elem,lo,hi);
}
Vector(Vector<T> const& V)  //向量整体复制
{
    copyFrom(V._elem,0,V.size())
}
~Vector(){delete[]_elem;}  //释放内部空间
基于复制的构造
template <typename T>//T为基本类型
void Vector<T>::copyFrom(T* const A,Rank lo,Rank hi){
    _elem=new T[_capacity=2*(hi-lo)];  //分配空间,两倍是预留空间,实际只用了一倍
    _size=0;  //规模清零
    while(lo<hi)   
        _elem[_size++]=A[lo++];
}
(b)可扩充向量

_capacity:总容量

_size:当前的实际规模

若采用静态空间管理策略,容量_capacity固定,则有明显的不足

1、上溢

2、下溢

扩充算法实现
template <typename T>
void vector<T>::expand(){//向量空间不足扩充
    if(_size<_capacity) reurn;
    _capacity=max(_capacity,DEFAULT_CAPACITY);//不低于最小容量
    T* oldElem=_elem;_elem=new T[_capacity<<=1];  //  _capacity<<=1容量加倍
    for(int i=0;i<_size();i++)  //复制内容
    {
        _elem[i]=oldElem[i];  //T为基本类型,或已经重载操作符'='
    }
    delete [] oldElem;   //释放原空间

}
扩充策略对比:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P1AOYowZ-1606376285860)(C:\Users\DELL\Desktop\01.PNG)]

平均分析 和 平摊分析
©无序向量
元素访问:
template <typename T> //0<= r< _size
T & Vector<T>::operator[](Rank r)
{
    return _elem[r];
}
插入
template <typename T> //e为秩为r的元素插入,0<=r<_size
Rank Vector<T>::insert(Rank r,T const & e)  //O(n-r)
{
	expand();   //若有必要,扩充
    for(int i=_size;i>r;i--)
    {
        _elem[i]=_elem[i-1];
	}
    _elem[r]=e;
    _size++;
    reutrn r;
}
区间删除
template <typename T>  //删除区间[lo,hi),0<=lo<=size
int Vector<T>::remove(Rank lo,Rank hi)
{
    if(lo==hi) return 0;
    while(hi<_size) _elem[lo++]=_elem[hi++];
    _size=lo;  shrink();
    return hi-lo;
}
查找
template <typename T>  //0<= lo< hi<=_size
Rank Vector<T>::find(T & const e,Rank lo,Rank hi) const
{
    while(lo<hi-- && e!=_elem[hi]);  //逆向查找
    return hi;
}
单元素删除

可以视作区间删除操作的体例:[r]=[r,r+1)

template <typename T>
T Vector<T>::remove(r)
{
    T e=_elem[r];   //备份删除的数据
    remove(r,r+1);   //调用区间删除算法
    return e;        //返回删除元素
}
唯一化
template <typename T>   //删除重复元素,返回删除元素的个数
int vector<T>::depulicate(){
    int oldsize=_size;   //保存原大小
    Rank i=1;
    while(i<_size)
    {
        (find(_elem[i],0,i)<0)?i++:remove(i);
    }
    return oldsize-_size;
}
遍历
//利用函数指针,只读和局域性修改
template <typename T>
void Vector<T>::traverse(void (*visit)(T&))  //函数指针
{
    for(int i=0;i<_size;i++)
        visit(_elem[i]);
}
//利用函数对象机制,可全局性修改
template <typename T>  
template <typename VST>
void vector<T>::traverse(VST& visit)  //函数对象
{
    for(int i=0;i<_size;i++)
        visit(_elem[i]);
}
(d1)有序向量:唯一化
有序性及其甄别
template <typename T>
int Vector<T>::disoredered() const
{
    int n=0;   //计数器
    for(int i=1;i<_size();i++)   //逐一检查
        n+=(_elem[i-1]>_elem[i]);
    return n;
}

无序向量经过预处理为有序向量后,相关算法可以优化

唯一化(低效算法)
template <typename T>
int Vector<T>::uniquify()
{
    int oldsize=_size;
    int i=0;
    //若雷同,则删除后者
    while(i<_size-1)
        (_elem[i]==_elem[i+1])?remove(i+1):i++;
    return oldsize-_size;
}
唯一化(高效)
template <typename T>
int Vector<T>::uniquify()
{
    Rank i=0,j=0;
    while(++j<_size)
        if(_elem[i]!=_elem[j])
            _elem[++i]=_elem[j];
    _size=++i;shrik();
    return j-i;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8oxE7VCP-1606376285866)(C:\Users\DELL\Desktop\02.PNG)]

(d2)有序向量:二分查找
template <tyename T>
Rank Vector<T>::(T const & e,Rank lo,Rank hi)const
{
    return (rand()%2==0)?   //随机选50%
        binsearch(_elem,e,lo,hi)    //二分查找
        :fibsearch(_elem,e,lo,hi);  //Fibonacci查找算法
}
版本A:实现
template <typename T>   //在有序向量区间[lo,hi)内查找
static Rank binSearcg(T* A,T const& e,Rank lo,Rank hi){
    while(lo<hi)
        Rank mi=(lo+hi)>>1;  //>>就是除以二
    if(e<A[mi])
        hi=mi;
    else if(A[mi]<)
        lo=mi;
    else
        return mi;
    return -1;
    }
(d3)有序向量:Fibonacci查找

改进思路:判断的时候,往左是一次判断;往右是两次判断;目的是使左右两边的判断次数总和接近。

template <typename T>
static Rank fibSearch(T* A,T const& e,Rank lo,Rank hi){
    Fib fib(hi-lo);
    while(lo<hi){
        while(hi-lo<fib.get())  
            fib.prev();
 		Rank mi=lo+fib.get()-1;
    	if(e<A[mi])
            hi=mi;
        else if(A[mi]<e)
       		lo=mi;
    	else
        	return mi;
	}
    return -1
}

总结:两种算法大体是一样的,主要是取mi的不同,二分法是取中间,Fibonacci查找是取黄金分割比。一个是0.5,一个是0.618…

(d4)有序向量:二分查找(改进)

改进思路:每次迭代只做一次的关键码比较

版本B:
template <typename> static binSearch(T*A,T const &e,Rank lo,Rank hi){
    while(1<hi-lo)
    {
        mi=(lo+hi)>>1;
        (e<A[mi])?hi=mi:lo=mi; //[lo,mi)或[mi,hi)
    }
    return (e==A[lo])?lo:-1;
}
版本C:
template <typename> static binSearch(T*A,T const &e,Rank lo,Rank hi){
    while(hi<lo)
    {
        mi=(lo+hi)>>1;
        (e<A[mi])?hi=mi:lo=mi+1;   //[lo,mi)或(mi,hi)
    }
    return --lo;
}
(e)起泡排序
template <typename T> 
void Vector<T>::bubbleSort(Rank lo,Rank hi)
{
    while(!bubble(lo,hi--));
}
改进:
template <typename T> 
bool Vector<T>::bubble(Rank lo,Rank hi)
{
    bool sorted=true;
    while(++lo<hi)
        if(_elem[lo-1]>_elem[lo]){
            sort=false;
            swap(_elem[lo-1],_elem[lo]);
        }
    return sorted;
          
    
}
001
再改进:
template <typename T>
void Vector<T>::bubbleSort(Rank lo,Rank hi)
{
    while (lo<(hi=bubble(lo,hi)));
}
template <typename T>
Rank Vector<T>::bubble(Rank lo,Rank hi)
{
    Rank last=lo;
    while(++lo<hi)
        if(_elem[lo-1]>_elem[lo])
        {
            last=lo;
            swap(_elem[lo-1],_elem[lo]);
        }
    return last;
       
}
002
(f)归并排序
template <typename T>
void Vector<T>::mergeSort(Rank lo,Rank hi){
	if(hi-lo<2) return;
    int mi=(lo+hi)>>1;
    mergeSort(lo,mi);
    mergeSort(mi,hi);
    merge(lo,mi,hi);
}
二路归并:基本实现
template <typename T> 
void Vector<T>::merge(Rank lo,Rank mi,Rank hi)
{
    T*A=_elem+lo;  //位置移动到lo
    int lb=mi-lo;
    T*B=new T[lb];    //复制B的缓存
    for(Rank i=0;i<lb;B[i]=A[i++]);
    int lc=hi-mi;
    T*C=_elem+mi;
    for(Rank i=0,j=0,k=0;(j<lb)||(k<lc);)
    {
        if((j<lb)&&(lc<=k||(B[j]<C[k]))) A[i++]=B[i++];
        if((k<lc)&&(j<=lb||(c[k]<B[j))) A[i++]=C[K++];
    }
    delete []B;
                                 
}
3、列表List
接口与实现
动态与静态

*根据是否修改数据结构,所有操作大致分为两类

1)静态:仅读取,数据结构的内容及组成一般不变:get\search

2)动态:需写入,数据结构的局部或者整体将改变:insert\remove

*与操作方式相对应的,数据元素的存储和组织方式也分两种

1)静态:数据空间整体创建或者销毁

​ 数据元素的物理存储次序与其逻辑次序严格一致

​ 可支持高效的静态操作

​ 比如向量Vector,元素的物理地址与其逻辑次序线性对应

2)动态:为各数据元素动态分地分配和回收的物理空间

​ 逻辑上相邻的元素记录彼此的物理地址,在逻辑上形成一个整体

​ 可支持高效的动态操作

列表节点:ADT接口
操作功能
pred()当前节点前驱节点的位置
succ()当前节点后继节点的位置
data()当前节点所存数据对象
insertAsPred(e)插入前驱节点,存入被引用对象e,返回新节点位置
insertAsSucc(e)插入后继节点,存入被引用对象e,返回新节点位置
列表节点:ListNode模板类
#define Posi(T) ListNode<T>*   //列表节点位置
template <typename T>  
struct ListNode{
    T data;  //数值
    Posi(T) pred;   //前缀
    Posi(T) succ;   //后继
    ListNode(){}    //针对header和trailer的构造
    ListNode(T e,Posi(T),Posi(T) s=NULL):data(e),pred(p),succ(s){}
    //默认构造器
    Posi(T) insertAsPred(T const& e);  //前插入
    Posi(T) insertAsSucc(T const& e);  //后插入 
}
列表:ADT接口
操作接口功能适合对象
size()报告列表当前的规模(节点总数)列表
first(),last()返回首、末节点的位置列表
insertAsFirst(e),insertAsLast(e)将e当作首、末节点插入列表
insertBefore(p,e),insertAfter(p,e)将e当作节点p的直接前驱、后继插入列表
remove§删除位置p处的节点,返回其引用列表
disordered()判断所有节点是否已按非降序排列列表
sort()调整各节点的位置,使之按非降序排列列表
find(e)查看目标元素e,失败时返回NULL列表
search(e)查看e,返回不大于e且秩最大的节点有序列表
deduplicate(),uniquify()剔除重复节点列表/有序列表
traverse()遍历列表列表
列表:List模板类
#include "ListNode.h"   //引入列表节点
template <typename T> 
class List{
    private:  
    int _size;   //规模
    Posi(T) header;
    Posi(T) trailer;   //头尾哨兵
    protected:
    public:
}
构造
template <typename T>
void List<T>::init(){   //初始化,创建列表对象时统一调用
    header=new ListNode<T>;   //创建头哨兵节点
    trailer=new ListNode<T>;    //创建尾哨兵节点
    header->succ=trailer; header->pred=NULL;  //互联
    trailer->pred=header; trailer->succ=NULL;  //互联
    _size=0;  //记录规模
}
(b) 无序列表
秩到位置
template <typename T>
T List<T>::operator[](Rank r) const
{
    Posi(T) p=first();  //从首节点出发
    while (0<r--) p=p->succ;  //顺序第r个节点即可
    return p->data;   //目标节点
}
查找
//在节点的n个前驱中,找到等于e的最后者
template <typename T>
Posi(T) List<T>::find(T const & e,int n, Posi(T) p) const
{
    while(0<n--)
        if(e==(p=p->pred)->data) return p;
	return NULL;
}
插入
template <typename T>
Posi(T) List<T>::insertBefore(Posi(T) p,T const & e)
{
    _size++;return p->insertAspred(e);  //e作为p的前驱插入
}
template <typename T>  //前插入算法
Posi(T) ListNode(T)::insertAspred(T const& e)
{
    Posi(T) x=new ListNode(e,pred,this);
    pred->succ=x;
    pred=x;
    return x;
}
删除
template <typename T>   //删除合法位置p处的节点,返回其数值
T List<T>::remove(Posi(T) p)
{
    T e=p->data;
    p->pred->succ=p->succ;
    p->succ->pred=p->pred;
    delete p;
    _size--;
    return e;
}
唯一化
template <typename T>
int List<T>::deduplicate()   
{
    if(_size<2) return 0;
    int oldsize=_size;
    Posi(T) p==first(); Rank r=1;
    while(trailer !=(p=p->succ))
    {
        Posi(T) q=find(p->data,r,p);
        q?remove(q):r++;
}
    return oldsize-_size;
}
©有序列表
唯一化
template <typename T>
int List<T>::uniquify()
{
    if(_size<2) return 0;
    int lodsize=_size;
    ListNodePosi(T) p=first();
    ListNodePosi(T) q;
    while(trailer != (q=p->succ))
        if(p->data!=q->data) p=q;
    	else remove(q);
    return oldsize-_size;
}
查找
template <typename T>
Posi(T) List<T>::search(T const & e,int n,Posi(T) p) const
{
    while(0<=n--)
        if(((p=p->pred)->data)<=e) break;
    return p;
}
(d)选择排序
实现:selectionSort()
template <typename T>
void List<T>::selectionSort(Posi(T)p,int n)
{
	Posi(T) head=p->pred;
    Posi(T) tail=p;
    for(int i=0;i<n;i++) tail=tail->succ;
    while(1<n)
    {
        insertBefore(tail,remove(selectMax(head->succ,n)));
        tail=tail->pred;n--;
}
}

new,delete操作为普通的100倍时间

实现:selectMax()
template <typename T>
Posi(T) List<T>::selectMax(Posi(T) p,int n)
{
    Posi(T) max=p;
    for(Posi(T) cur=p;1<n;n--)
        if(!lt((cur=cur->succ)->data,max->data)) //!lt(,)判断大于等于
            max=cur;
    return max;
}
(e)插入排序
实现
template <typename T>
void List<T>::insertionSort(Posi(T) p,int n)
{
    for(int r=0;r<n;r++)
        insertAfter(search(p->data,r,p),p->data);
    	p=p->succ;remove(p->pred);
}
4、栈与队列
(a)栈接口与实现
5、二叉树
(a)树
(b)树的表示
接口:
节点功能
root()根节点
parent()父节点
firstChild()长子
nextSibling兄弟
insert(i,e)将e作为第i个孩子插入
remove()删除第i个孩子(及其后代)
traverse()遍历
©二叉树概述
(d)二叉树实现
BinNode模板类:
#define BinNodePosi(T) BinNode<T>*  //节点位置
template <typename T>
struct BinNode{
    BinNodePosi(T) parent,lChild,rChild;   //父亲,孩子
    T data;
    int height;   //高度
    int size();   //子树规模
    BinNodePosi(T) insertAsLC( T const &);  //作为左孩子插入新节点
    BinNodePosi(T) insertAsRC( T const &);  //作为右孩子插入新节点
    BinNodePosi(T) succ();  //(中序遍历意义下)当前节点的直接后继
    template <typename VST> void travLevel(VST &);//子树层次遍历
    template <typename VST> void travPre(VST &);//子树先序遍历
    template <typename VST> void travIn(VST &);//子树中序遍历
    template <typename VST> void travPost(VST &);//子树后序遍历
}
BinNode接口实现
template <typename T> 
BinNodePosi(T)::insertAsLC(T const & e)
{
    return lChild=new BinNode(e,this);
}

template <typename T> 
BinNodePosi(T)::insertAsRC(T const & e)
{
    return rChild=new BinNode(e,this);
}

template <typename T>
int BinNode<T>::size(){//后代总数,以此为根的子树规模
    int s=1;//记入本身
    if(lChild) s+=lChild->size(); //递归计入左子树规模
    if(rChild) s+=rChild->size();   //递归计入右子树规模
    return s;
}
BinTree模板类
template <typename T>
class BinTree{
protected:
    int _size();   //规模
    BinNodePosi(T) _root;  //根节点
    virtual int updateHeight(BinNodeposi(T) x); //更新节点x的高度
    void updateHeightAbove(BinNodePosi(T) x);  //更新x及祖先的高度
public:
    int size()  const {return _size;}  //规模
    bool empty()  const {return !_root;}  //判空
    BinNodeposi(T) root()  const {return _root;}  //树根
    /*.......其他接口.......*/
    
}
高度更新
#define stature(p) ((p)?(p)->height:-1)  /节点高度,约定空树高度为-1
template <typename T>  //更新节点X的高度,具体规则因树不同而异
int Bintree<T>::updateHeight(BinNodePosi(T) x){
	return x->height =1+=max(stature(x->lChild),stature(x->rChild));
}

template <typename T>  //更新v以及历代祖先的高度
void BinTree<T>::updateHeightAbove(BinNode(T) x){
	while(x)  
    {updateHeight(x);x=x->parent;}
}
节点插入
template <typename T> 
BinNodePosi(T) BinTree<T>::insertAsRC(BinNodePosi(e),T const & e)
{
    _size++;
    x->insertAsRC(e);  //x的祖先高度可能增加,其余节点必然不变
    updateHeightAbove(x);
    return x->rChild;
}
(e1)先序遍历
遍历:

先序,中序,后序

捕获

先序:递归实现

template <typename T,typename VST>
void traverse(BinNodePosi(T) x,VST & visit){
	if(!x) return;
    visit(x->data);
    traverse(x->lChild,visit);
    traverse(x->rChild,visit);
}//T(n)=O(1)+T(a)+T(n-a-1)=O(n)
迭代1:实现
template <typename T,typename VST>
void travPre_I1(BinNodePosi(T) x,VSY & visit){
	Stack <BinNodePosi(T)> S;
    if(x)  S.push(x);  //根节点
    while(!S.empty()){  //在栈变空之前反复循环
		x=S.pop(); visit(x->data);  //弹出并访问当前节点
        if(HasRChild(*x)) S.push(x->rChild);  //右孩子先入后出
        if(HasLChild(*x)) S.push(x->lChild);
 //左孩子后入先出
    }
}
迭代2:实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zO61PSXW-1606376285869)(E:\360MoveData\Users\Administrator\Desktop\数据结构和算法.assets\捕获1.PNG)]

template <typename T,typename VST>  //分摊O(1)
static void visitAlongLeftBrancg(
	BinNodePosi(T) x,
    VST & visit,
    Stack <BinNodePosi(T) & S)
{
    while(x){  //反复地
        visit(x->data);  //访问当前节点
        S.push(x->rChild);  //右孩子(右子树)入栈(将来逆序出栈)
        x=x->lChild;   //沿左侧链下行
        
	}//只有右孩子、NULL可能入栈---增加判断以删除是否值得
}


template <typename T,typename VST>
void travPre_I2(BinNodePosi(T) x,VST & visit)
{
    Stack <BinNodePosi(T)> S;
    while(true){
        visitAlongLeft(x,visit,S);  //访问子树x的左侧链,右子树入栈缓冲
        if(s.empty()) break;  //栈空即退出
        x=S.pop();  //弹出下一个子树的根
	}
}
(e2)中序遍历
递归实现
template <typename T,typename VST>
void traverse(BinNodePosi(T) x,VST & visit){
	if(!x) return;
    traverse(x->lChild,visit);
    visit(x->data);
    traverse(x->rChild,visit);
}
改进实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qF7Qy1nO-1606376285873)(E:\360MoveData\Users\Administrator\Desktop\数据结构和算法.assets\捕获2.PNG)]

template <typename T>
static void goAlongLeftBranch(BinNodePosi(T) x,Stack <BinNodePosi(T)> & S)
{
    while(x)  {S.push(x);x=x->lChild;}
    //反复地入栈,沿左分支深入
}

template <typename T,typename V>
void travIn_I1(BinNodePosi(T) x,V & visit)
{
    Stack <BinNodePosi(T)> S;
    while(true){
		goAlongLeftBranch(x,S);  //当前节点出发,逐批入栈
        if(S.empty()) break;  //
        x=S.pop(); //x的左子树或为空,或已遍历
        visit(x->data);
        x=x->rChild;  //转向右子树
    }
}
(e4)层次遍历
实现
template <typename T> 
template <typename VST>
void BinNode<T>::travLevel(VST & visit){//二叉树层次遍历
    Queue<BinNodePosi(T)> Q; //引入辅助队列
    Q.enqueue(this);   //根节点入栈
    while(!Q.empty()){   //队列为空之前,反复迭代
		BinNodePosi(T) x=Q.dequeue(); //取出队首节点,并随机
        visit(x->data);  //访问之
        if(HasLChild(*X)) Q.enqueue(x->lChild);  //左孩子入队
        if(HasRChild(*X)) Q.enqueue(x->rChild);  //右孩子入队
    }

}
(e5)

先序+后序(真树)

(先序/后序)+中序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值