zoukankan      html  css  js  c++  java
  • 2_线性表之链式存储

    存储结构

    通过“链”建立数据元素间的逻辑关系,使物理位置上不相邻的元素逻辑上也能相邻,操作不需要移动元素,只需修改指针。

    1.单链

                                        

     表示方法

    typedef struct LNode{
            ElemType data;   //数据域
            struct LNode *next;   //指针域
    } LNode,*LinkList

    基本操作1:建立

    头插法

    实现步骤:从创建头结点开始,生成新结点,将读取到的数据放到新结点的数据域中,然后将新结点插入到头结点之后,读取顺序与生成顺序相反

           

    { s = (LNode*)malloc(sizeof(LNode));
       s—>data=x;
       s—>next=L—>next;     //将L—>next(初值Null)所指赋给s—>next
       L—>next = s; 
       scanf("%d",&x); }

    *指针所代表的是指向

    尾插法

    生成顺序与读取顺序相同

          

    s—>data=x;
    r—>next=s;      //r所指向
    r = s;

    基本操作2:查找

    按位

    LNode *GetElem(LinkList L,int i){
             int j=1;     //计数,初始为1
             LNode *p=L—>Next;
             if(i==0)     //若i等于0,返回头结点
                  return L;
             if(i<1)       //若i无效,返回Null
                  return Null;
             while(p&&j<i){
                    p=p—>next;
                    j++; }
             return p; }

    *单链表长度不包含头结点

    按值

    LNode *LocateElem(LinkList L,ElemType e){
             LNode *p=L—>Next;
             while(p!=Null&&p—>data!=e){
                    p=p—>Next;
             return p; }

    *操作时先检验操作合法性,再执行操作

    基本操作3:插入

           

    1.p=GetElem(L,i-1);   //查找插入位置前驱结点
    2.s—>next=p—>next;    //步骤1
    3.p—>next=s;          //步骤2

    基本操作4:删除

    按位  

    实现步骤:将单链表第i个结点删除,先检查合法性,然后找出第i-1它的前驱结点,便可删除i结点,复杂度O(n)

             

    p=GetElem(L,i-1);         //查找删除位置的前驱结点
    q=p—>next;                 //令q指向被删除结点
    p—>next=q—>next;    //断开
    free(q);

    删给定结点*p

    实现步骤:将其后继结点赋予给定结点,再删除后继,复杂度O(1)

    q=p—>next;               
    p—>next=q—>next—>data;     //和后继结点交换数据域 
    p—>next=q—>next;
    free(q);

    2.双链表

    双链表节点中有两个指针prior和next,查找与单链表相同,插入和删除有较大不同

            

    表示方法:

    typedef struct DNode{
                 ElemType data;                        //数据域
                 struct DNode *prior,*next;      //前驱、后驱指针
    }DNode,*DLinkList

    基本操作1:插入

          

    1.s—>next=p—>next;     //建立后继与s联系
    2.p—>next—>prior=s;    //P的下个结点的前驱指向
    3.s—>prior=p;                //建立与前驱结点联系
    4.p—>next=s;                //P的上个结点的后继指向

    *方法不唯一,但1.2.必须在4.前面

    基本操作2:删除

           

    p—>next=q—>next;    //步骤1.
    q—>next—>prior=p;    //步骤2.
    free(q);

    3.循环链表

    只需在终端结点和头结点建立联系即可,判断P走到表尾的条件是P—>next=head

    算法1:递归删除无头结点单链表所有某值

    void Del_x_3(LinkList,&L,ElemType x){
           LNode *p;                        //p指向待删除结点
           if(L==NULL)                      //递归终止条件
                return;                         
           if(L—>data==x){                  //若L所指结点值为x,删除*L指向
                p=L;                           
                L—>next;                    //并让L指向下一结点
                free(p);
                Del_x_3(L,x); }             //跳回函数本体
           else 
                 Del_x_3(L—>data,x) }

    算法2:删除带头结点单链表所有某值

    void Del_x_4(LinkList &L,ElemType x){
           LNode *p=L—>next,*pre=L,*q;   //置*P和*pre初始值
           while(p!=NULL){
                  if(p—>data==x){
                       q=p;         //q指向该结点
                       p=p—>next;   //通过操作删除该结点
                       pre—>next=p;
                       free(q); }
                  else{             //不等,pre和p同时后移
                       pre=p;
                       p=p—>next; }}}

    算法3:从尾到头递归遍历带头结点单链表

    用栈的思想递归实现,也可以逆置改变方向后从头到尾遍历

    void Reverse_Print(LinkList L){
           if(L—>next!=NULL){
               Reverse_Print(L—>next); }     //递归
           print(L—>next); }             //整体输出函数

    算法4:删除带头结点单链表最值

    void Del_Min(LinkList &L){
           LNode *pre=L,*p=pre—>next;  //p为扫描指针,pre为p的前驱
           LNode *minpre=pre,*minp=p;   //边扫描边比较,将较小者存入minp和premin,将前驱考虑进来是为了便于删除一个结点
           while(p!=NULL) {
                  if(p—>data<minp—>data){
                        minp=p;
                        minpre=pre; }
                  p=p—>next;  //继续扫描下一个结点
                  pre=p; }
                  minpre—>next=minp—>next;   //删除最小值
                  free(minp);
                  return L; }

    算法5:带头结点单链表就地逆置

    LinkList Reverse_1(LinkList &L){
           LNode *p,*r;       //p是扫描指针,r暂存p后继
           p=L—>next;         //从头结点开始
           L—>next=NULL;      //先将头结点指针域置NULL
           while(p!=NULL){
                  r=p—>next;  // 暂存p的后继防止断链
                  p—>next=L—>next;    //以下循环头插法,这里是插入后继
                  L—>next=p;          //插入前驱
                  p=r; }              //扫描下一个
           return L; }

    算法6:无序——>有序

    使带头结点的单链表有序递增

    void Sort(LinkList &L){
           LNode *p=L—>next,*pre;
           LNode *r=p—>next;      //r防止断链
           
  • 相关阅读:
    声明函数的是方式
    数组的相关属性和函数
    JS选择结构
    JS数据类型
    JS 运算符
    JS 变量
    响应式布局
    css的flex属性
    CSS中的度量单位
    BFC 规则
  • 原文地址:https://www.cnblogs.com/Real-Ying/p/7350826.html
Copyright © 2011-2022 走看看