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
  • 相关阅读:
    从零开始——PowerShell应用入门(全例子入门讲解)
    详解C# Tuple VS ValueTuple(元组类 VS 值元组)
    How To Configure VMware fencing using fence_vmware_soap in RHEL High Availability Add On——RHEL Pacemaker中配置STONITH
    DB太大?一键帮你收缩所有DB文件大小(Shrink Files for All Databases in SQL Server)
    SQL Server on Red Hat Enterprise Linux——RHEL上的SQL Server(全截图)
    SQL Server on Ubuntu——Ubuntu上的SQL Server(全截图)
    微软SQL Server认证最新信息(17年5月22日更新),感兴趣的进来看看哟
    Configure Always On Availability Group for SQL Server on RHEL——Red Hat Enterprise Linux上配置SQL Server Always On Availability Group
    3分钟带你了解PowerShell发展历程——PowerShell各版本资料整理
    由Find All References引发的思考。,
  • 原文地址:https://www.cnblogs.com/zzyh/p/12761342.html
Copyright © 2011-2022 走看看