zoukankan      html  css  js  c++  java
  • 数据结构课堂笔记

    template<class T>
    void SeqList<T>::reSize(int newsize)
    {
        if(newSize!=maxSize)
        {
            T *newarray=new T[newSize];
           /*
            开辟大小为newSize的内存空间
            数据类型为T        
            */
           if(newarray==NULL)
           {
            cerr<<"分配存储失败!"<<endl;
            exit(1); 
           }
        }
        int n=last+1;
        T *scrptr=data;
        T *destptr=newarray;
        while(n--) *destptr++=*srcptr++;
        delete []data;
        data=newarray;
        maxSize=newSize; 
    }
    
    
    template<class T>
    int SeqList<T>::search(T &x) const
    {
        for(int i=0;i<=last;i++)
        {
            if(data[i]==x) return i+1;
        }
    }
    
    /*
    在第i个位置插入x 
    插入前:a1,....,ai-1,ai,...,an
    插入后:a1,...,ai-1,x,ai,...,an
    ai-1和ai之间的逻辑发生了变化
    表满:last>=MaxSize-1
    last是最后一个元素数组下标
    1<=i<=last+2
    插入元素时移动的越少效率越高
    移动元素的个数不仅和表长有关而且与插入位置有关 
    最好情况(i=n+1)基本语句执行0次,时间复杂度O(1) 
    */
    
    /*
    顺序表的实现——删除
    每个往前移一位 相当于覆盖掉了
    首先要判断删除位置是否合法 
    1<=i<=last+1 
    */
    template<class T>
    bool SeqList<T>::Remove(int i,T &x)
    {
        if(last==-1||i<1||i>last+1) return false;
        x=data[i-1];//第i个元素数组下标是i-1
        for(int j=i;j<=last;j++)
        {
            data[j-1]=data[j];//后面覆盖前面 
        }
        last--; //表长-1 
    } 
    
    
    //顺序表的输入算法
    template<class T>
    void SeqList<T>::input()
    {
        cout<<"输入元素个数";
        while(1)
        {
            cin>>last;
            if(last<=maxSize-1) break;
            cout<<"个数输入有误"; 
        }
        for(int i=0;i<=last;i++)
        {
            cin>data[i];
            cout<<i+1<<endl; 
        } 
    }
     
    //顺序表的输出算法
    template<class T>
    void SeqList<T>::output()
    {
        cout<<"当前元素的最后位置为"<<last<<endl;
        for(int i=0;i<=last;i++)
        {
            cout<<"#"<<i+1<<":"<<data[i]<<endl;
        }
    }
    
    //顺序表的应用
    
    //并运算 
    void Union(SeqList<int>&A,SeqList<int>& B)
    {
        int n=A.length(),x;
        int m=B.length();
        for(int i=1;i<=m;i++)
        {
            B.getData(i,x);//在B中取一个元素 
            int k=A.Search(x);//在A中搜索它 
            if(k==0)     //若未找到插入到A的最后 把并的结果放入A中(若重新开空间则浪费) 
            {A.Insert(n,x);n++;} 
        }
    } 
    
    //交运算
    void Intersection(SeqList<int>&A,SeqList<int>&B)
    {
        int n=A.Length();
        int m=B.Length();int i=1,x;
        while(i<=n)
        {
            A.getData(i,x);
            int k=B.search(x);
            if(k==0) A.Remove(i,x),n--;
            else i++;
        }
    } 
    
    //顺序表的优点:
    /*
    无需为表示表中元素之间的逻辑关系而增加额外的存储空间
    随机存取 可以快速地存取表中任一位置的元素
    顺序表的缺点:
    (1)插入和删除操作需要移动大量元素
    (2)表的容量难以确定,表的容量难以扩充
    (3)造成存储空间的碎片
    
    链表非常适合频繁地插入或删除、存储空间需求变化很大地情形 
    */ 
    
    
    /*
    单链表是最简单地链表,也叫线性链表,它用指针表示节点间地逻辑关系
    Node 存有数据域和指针域
    线性结构first为头指针
    结点可以连续可以不连续存储  99.99%不连续存储 
    节点的逻辑顺序和物理顺序可以不一致
    表扩充很方便 
    */ 
    
    /*
    顺序表 容量是固定
    单链表  不固定  
    */ 
    
    /*
    多个类表达一个概念(单链表)
    链表节点(ListNode)类 
    链表(List)类 
    */ 
    
    // 1.复合类1 
    class List;//链表类定义(复合方式)
    class LinkNode
    {
        friend class List;//链表类为其友元类
        private:
            int data;
            LinkNode *link; 
    };
    class List
    {
        private:
            LinNode *first;
    };
    //友元类不具有对称性??
    //复合类2:用struct定义linkNode类
    struct LinkNode
    {
        int data:
        LinkNode *link;
    };
    class List
    {
        private:
            LinkNode *first;
        public:
    };
    /*
    虽然结构使List失去了封装性
    但是所有属于LIst对象地LinkNode结点只能用first进行访问。 
    */ 
    //2、嵌套类
    class List
    {
        
    }  
     
     //3、继承方式  
    class LinkNode
    {
         protected:
             int data;
             LinkNode *link;
    };
    class List
    {
        
    }
    //写不完了  自己去看PPT吧。 
    1
    /*
    单链表的链接存储结构及实现
    单链表:
    头指针:指向第一个结点的地址
    尾标志:终端节点的指针域为空
    空表:first=NULL
    非空表:构造一个头结点
    
    插入:
    (1)第一个结点前插入:
    newnode->link=first;
    first=newnode;
    (2)在中间插入:
    用p代表ai 
    先修改后继指针 newnode->link=p->link
    p->link=newnode 
    (3)在链表末尾插入:
    newnode->link=p->link
    p->link=newnode
    
    删除:
    (1)删除表中第一个元素 
    del=first; first=first->link;delete del ;
    (2)在单链表中或表尾
    用p指向被删结点的前一个结点
    del指向被删结点
    p->link=del->link
    delete del; 
     
    头结点:为了统一操作,在表最前端设置附加头结点,
    本身不带数据,仅标纸为表头 
    */
    
    //附加头节点的单链表类
    
    template<class T>
    struct LinkNode
    {
        T data;
        LinkNode<T> *link;
        LinkNode(LinkNode<T>*ptr=NULL)
        {
            link=ptr;
        }//构造函数
        LinkNode(const T& item,LinkNode<T>*ptr)
        {
            //
        } 
    } 
    
    template<class T>//链表类 
    class List:public LinearList<T>
    {
        protected:
            LinkNode<T>*first;//头指针
        public:
        List(){first=new LinkNode<T>;}
        List(const T&x)
        {
            first=new LinkNode<T>(x);
         } 
         List(List<T>&L);
         ~List(){makeEmpty();}
         void MakeEmpty();
         //???????
    } 
    
    
    LinkNode<T>*getHead()const{return first;}
    LinkNode<T>*Search(T x);//返回LinkNode型指针 
    //搜索含数据x的元素
    LinkNode<T>*Locate(int i);
    //搜索第i个元素的地址
    bool GetData(int i,T&x);
    //取出第i个元素的值
    bool Insert(int i,T &x);
    //将x插在第i个元素后
    bool Remove(int i,T &x);
    //删除第i个元素,x返回该元素的值。
    bool IsEmpty()const
    {return first->link==NULL?true:false;}
    bool IsFull()const{return false;}
    //链表不会满的
    void Sort();
    void input();
    void output();
    List<T>& operator=(List<T>& L);
    //链表赋值直接用等号
    
    template<class T>
    List<T>::List(List<T>&L) //复制构造函数 
    {
        T value;
        LinkNode<T>*srcptr=L.getHead();
        LinkNode<T>*destptr=first=new LinkNode<T>;
        while(srcptr->link!=NULL)
        {
            value=srcptr->link->data;
            destptr->link=new LinkNode<T>(value);
            destptr=destptr->link;
            srcptr=strptr->link; 
        } 
        destptr->link=NULL;
    }//????/
    
    template<class T>9
    void List<T>::MakeEmpty
    {
        //删去除附加头节点外的所有其他结点 
        LinkNode<T>*q;
        while(first->link!=NULL)
        {
            q=first->link;
            first->link=q->link;
            //将表头结点后第一个结点q从
            //链中摘下 
            delete q;//释放它 
         } 
    } 
     
     
    template<class T>
    int List<T>::Length()const
    {
        LinkNode<T>*p=first->link;
        int count=0;
        while(p!=NULL)
        {
            p=p->link;
            count++;
        }
        return count;
     } 
     
    template<class T>
    LinkNode<T>*List<T>::Locate(int i)
    {
        //定位函数 返回第i个元素的地址
        if(i<0) return NULL;
        LinkNode<T>*p=first;
        int k=0;
        while(p!=NULL&&k<i)
        {
            p=p->link;k++;//k为计数器 
        }
        return p; 
     } 
     //-----------------------------
     //插入 先修改后继 
     s=new Node<T>;
     s->data=x;
     s->link=p->link;
     p->link=s; 
     
     /*
     有了表头
     每个结点都有了前驱结点
     直接插 
     
     插入伪代码“
     1、工作指针p初始化
     2、找到第i-1个结点并使工作指针p指向该结点
     3、若查找不成功,则插入位置不合理, 
     ... 
     */ 
     
     template<class T>
    bool LinkList<T>::Insert(int i,T &x)
    {
        //在第i个位置后插入元素x 
         //?????????????
         //i到底是数组下标还是第i个数据 
         LinkNode<T> *p=Locate(i-1);
         if(p==NULL) return false;
         else
         {
             s=new LinkNode<T>(x);
             s->link=p->link;
            p->link=s;
            return true;  
        }
    } 
     
    //删除是直接删除第i个元素
    //用临时变量保存被删结点、
    //取值,摘链 
    //删除不能删最后一个元素
    /*
    表尾的特殊情况:
    虽然被删结点不存在
    但其前驱结点却存在 
    最后一个结点虽然有前驱 但是不存在 
    */ 
    bool List<T>::Remove(int i,T &x)
    {
        /*
          q=p->link;
          x=q->data;
          p->link=q->link;
          delete q;
        */
    } 
    
    /*
     1、初始化p
     2查找第i-1个结点并使p指向该结点
     3.若p不存在或p不存在后继结点,则不可删/
     3.1暂存被删元素
     3.2摘链
     3.3释放被删结点
     3.4返回被删元素值 
    */ 
    
    //删除代码
    template<class T>
    bool List<T>::Remove(int i,T &x)
    {
        LinkNode<T>*p=Locate(i-1);
        if(p==NULL||p->link==NULL) return dalse;
        LinkNode<T>*q=p->link;
        x=q->data;
        p->link=q->link;
        delete q;
        return true;
    } 
    
    //两个链表直接重载赋值
    template<class T>
    List<T>&List<T>::Operator=(List<T>&L)
    {
        T value;
        LinkNode<T> *srcptr=L.getHead();
        LinkNode<T> *destptr=first=new LinkNode<T>;
        while(srcptr->link!=NULL)
        {
            value=srcptr->link->data;
            destptr->link=new LinkNode<T>(value);
            destptr=destptr->link;
            srcptr=strptr->link;
        }
        destptr->link=NULL;
        return *this;
    } 
    
    //输入链表
    //前插法  物理顺序和逻辑顺序相反 
    template<class T>
    void List<T>::inputFront(T endTag)
    {
        LinkNode<T>*newNode;T val;
        makeEmpty();cin>>val;
        while(val!=endTag)
        {
            newNode=new LinkNode<T>(val);
            //new 可能申请不成功 所以下面要判断 
            if(newNode==NULL)
            {
                cerr<<"error"<<endl;
                exit(1);
            }
            newNode->link=first->link;
            first->link=newNode;
            cin>>val;
        }
     } 
    //后插法 
    template<class T>
    void List<T>::inputRear(T endTag)
    {
        LinkNode<T>*newNode,*last,T val;
        makeEmpty();cin>>Val;last=first;
        while(val!=endTag)
        {
            newNode=new LinkNode<T>(val);
            if(newNode==NULL)
            {
                cerr<<"error"<<endl;
                exit(1);
            }
            last->link=newNode;
            last=newNode;
            cin>>val; 
        }
     } 
     
     /*
     算法设计的一般步骤
     1.确定入口(已知条件) 出口(结果)
     2.画示意图
     3.
     (1)正向思维: 选定一个思考问题的起点 提出问题 解决问题
     (2)逆向思维:从结论出发
     (3)正逆结合
    4.写出顶层较为抽象算法,分析边界情况
    5.验证第四步的算法
    6.写出具体的算法
    7.进一步验证 手工运行 
    
    */
    /* 
    单链表中:
    (1)除非已知first否则无法找到其他所有节点
    (2)单链表里 找后继容易 找前驱难
    为了解决:
    1.单向循环链表   循环链表 
    首尾相连 最后一个结点的后继为第一个结点
    空表:first->link=first
    开始节点:first->link;
    终端节点:将单链表扫一遍 O(n)
    p!=NULL // p!=first(循环链)
    p->link!=NULL//p->link!=first
    带尾指针的循环链表:
    开始结点: last->link->link
    终端节点:last 
    
    */
    
    template<class T>
    class CircList:public LinearList<T>
    {
        private:
            CircListNode<T>*first,*last;
        public:
            CircList(const T&x);
            CircList(CircList)<T>
            //--------------
    } 
     
     //循环链表插入
    bool CircList<T>::Insert(int i,T x)
    {
         p=first;count=0;
         while(p!=first&&count<i-1)
         {
             p=p->next;
             count++;
         }
         if(p==NULL) return false;
         else
         {
             s=new CircLinkNode<T>;
             s->data=x;
             s->link=p->link;
             p->link=s;
         }    
    } 
    2.双向循环链表 
     
    2
    /*
    2、从被调用函数返回调用函数之前,应该完成“
    1)保存被调用函数的计算结果
    2)释放被调用函数的数据区
    3)依照被调用函数保存的返回地址将控制转移到调用函数 
    当多个函数嵌套调用时,由于函数运行的规则是:后调用先返回,
    因此各个函数的存储管理应实行"栈式管理“ 
    
    总之:函数调用后调用先返回,实行栈式管理。 
    
    */ 
    
    int main()
    {
        A(5,6);
        return 0;
    } 
    
    void A(int a,int b)
    {
        B();
    }
    
    void B()
    {
        
    }
    /* 
    下面是一个栈:
     
    函数B占有存储区 ----栈顶 
    函数A占有存储区 
    主函数占有存储区 ---栈顶 
    */
    /* 
    2.1递归算法
    递归:直接或间接调用自身的算法。
    递归函数:如 N!,Fibonacci,Ackerman函数
    递归数据结构:单链表,二叉树,图等。
    递归时,问题的本质没有发生变化,变化的是问题的规模。
    递归的分类:
    (1)直接调用自身
    A()
    {A()}
    (2)间接调用自身
     B()
     {C()}
    递归的优缺点:
    (1)优点:算法简明,正确性易证明,是分析、设计的有利工具。
    (2)缺点:执行效率不高,堆栈空间耗费。
    原因:参数、局部量、返回点的保存。大量的重复计算。
     
    例一:阶乘函数:
    n!=1    n(n-1)!
    
    int f(int n)
    {
        sum=1;
        for(int i=1;i<=n;i++) sum=sum*i;
        return sum;
    } 
    
    int f(int n)
    {
        if(n==0) return 1;
        return n*f(n-1); 
    } 
    
    
    
    递归算法的设计
    
    对原问题f(s)进行分解,给出合理的较小问题f(s');
    假设f(s')是可解的,给出f(s)与f(s')之间的关系。
    
    确定一个特定情况的解,由此作为递归出口。
    含一个递归调用的递归过程的一般形式 
    递归定义包括两项:
    */
    
    /*
    栈的应用:递归
    1、函数是递归定义的
    
    阶乘函数
    long Factorial(long n)
    {
        if(n==0)return 1;
        else return n*Factorial(n-1);
    } 
    
    递归调用 回归求值 
    2、数据结构是递归的--单链表
    搜索链表最后一个结点并打印其数值
    
    template<class T>
    void Print(ListNode<T>*f)
    {
        if(f->link==NULL)
         cour<<f->data<<endl;
        else Print(f->link);
    } 
    
    3、问题的解法是递归的
    
    汉诺塔解法:
    如果n=1,则将这一个盘子直接从A柱移到C柱上。
    否则,执行以下三步:
    ①:用C柱做过渡,将A柱上的(n-1)个盘子移到B柱上。
    ②:将A柱上最后一个盘子直接移到C柱上
    ③:用A柱做过渡,将B柱上的(n-1)个盘子移到C柱上。
    A(n)--> C--> B
    A(1) B(N-1)  C
    A  B(n-1) C(1)
    B(n-1)-->A-->C(1)
    B  A  C(n) 
    
    递归:自顶向下,逐步分解的策略。 
    */ 
    
    /*
    递归过程改为非递归过程
    递归过程简洁、易懂、易编 
    
    计算斐波那契额数列。
    Fib(n)=n   Fib(n-1)+Fib(n-2),
     
    */
    
    /*
    递归与回溯 
    
    对一个包含有许多结点,且每个结点有多个分支的问题,可以先选择一个分支进行搜,
    当搜素到某一结点,发现无法再继续搜索下去时,可以沿搜索路径回退
    到前一结点,沿另一分支继续搜索。
    如果回退之后没有其他选择,再沿搜索路径回退到更前结点。
    依次执行,直到搜索到问题的解。
    回溯算法是一种深度算法。 
    
    */ 
    
    /*
    3.迷宫问题(穷举法)
    寻找一条从入口到出口的通路。
    
    4、N皇后问题。
    n个皇后不能在同一行,同一列,同一对角线上。 
    
    */ 
    3
  • 相关阅读:
    学员操作——隔行变色
    jQuery基础及选择器(1)
    学员操作——组合继承
    JavaScript面向对象
    学员操作——创建继承person的student子类
    学员操作——flower函数
    JavaScript操作DOM(2)
    JavaScript操作DOM(1)
    学员操作——制作秒表定时器
    学员操作——制作5s关闭广告
  • 原文地址:https://www.cnblogs.com/zzyh/p/12761342.html
Copyright © 2011-2022 走看看