线性表学习

1.线性表的定义
线性表是具有相同数据结构类型的n(n>=0)个数据元素的有限序列。其中n为表长,当n=0时为空表。其一般的表示方法为:
                         L=(a
1 ,a 2 ,a 3 ......,a i ,a i+1 ,....a n )
除了第一个元素之外,每个元素有且只有一个直接前驱。除最后一个元素外,每个元素有且只有一个直接后继。
2.线性表的特点:
     表中元素的个数有限
     表中元素具有逻辑上的顺序性,在序列中各元素排序由先后次序
     表中数据元素类型相同
     表中数据具有抽象性
线性表是一种逻辑结构,表示元素的一对一的相邻关系。顺序表和链表是指存储结构。
3.线性表的相关操作:
     InitList(&L):初始化表。构造一个空的线性表
     Length(L):求表长
     GetElem(L,i,&e):用e返回L中的第i个数据元素的值
     LocateElem(L,e,compare( )):按值查找操作。在表L中查找具有给定关键字值得元素与e相同的元素的位序。
     ListInsert(&L,i,e):在L中第i个元素之前插入元素e,表长加1。
     ListDelete(&L,i,&e):删除L中第i个数据元素,并用e返回其值,L的长度减1。
4.线性表的存储类型(顺序存储、动态存储)
  
顺序存储
            #define  MaxSize 50
           typedef  struct{
                  ElemType  data[
MaxSize];
                  int length;
              }SqList; 

  动态存储
           #define InitSize 100
           typedef struct {
                 ElemType *data;
                 int   MaxSize,length;
              }SqList;
动态分配的语句(C && C++)
     C语言:   L.data=(  Elem Type*)malloc(sizeof( Elem Type)*InitSize);
     C++:      L.data=new   Elem Type[ InitSize];
顺序表的特点:
        随机访问、存储密度高、逻辑上相邻物理上元素相邻、插入删除操作需要移动大量元素。
5.顺序表操作
        插入操作:采用的思路是首先先判断i的输入是否合法,如果不合法,则返回false,表示插入失败。否则,将第i个元素及之后的元素进行后移一位,插入需要插入的元素e,顺序表长加1,插入成功返回true。
      bool ListInsert(SqList &L,int i,ElemType e) {
           if(i<1|| i<L.length +1)
              return false;
           if(L.length  >=MaxSize)
                return false;
           for(int j=L.length;j>=i;j--)
                L.data[j]=L.data[j-1];
           L.data[i-1]=e;
           L.length++;
           return ture;
         }
采用动态存储结构进行插入操作:
           思路:对要进行插入的操作进行判断,判断插入的i值是否合法,如果不合法,则返回error。对存储空间进行判断,如果满了的话,则增加分配。如果分配失败,则返回溢出。建立新的地址,增加存储容量。同时找到插入的位置,对其后的元素进行后移。
              status  ListInsert_Sq(SqList &L,int i,ElemType e) {
              if(i<1||
i<L.length +1)  return error;
              
//对于存储容量不够进行动态分配。如果失败,建立新的基址,增加容量。
              if(L.length>=L.listsize) {
                 newbase=  (  Elem Type*)realloc(L.elem,L.listsize+LISTINCREMENT)*sizeof( Elem Type);
               if(!newbase) exit (overflow)
               L.elem=newbase;
               L.listsize+=  LISTINCREMENT;
               }
              
              
 //找到插入的位置q,同时求线性表长度p,对于大于q的元素向后移一位。同时表长加1。
              q=&(L.elem[i-1]);
               for(p=&(L.elem[L.length-1]);p>=q;- -p) *(p+1)=*p;      
               
               *q=e;
                ++L.length;
                return ok;
               } //List
Insert_Sq
      
 删除操作:
            思路:删除顺序表中第i个元素,成功时返回ture,并将删除元素用变量e返回,否则返回false。先判断i值是否合法,然后对删除的前部分,位序不变,而后面的元素进行地址减1,同时线性表的长度减1。
            bool  ListDelete(SqList &L,int i,int &e) {
                 if(i<1||i>L.length)
                        return false;
                 e=L.data[i-1];
                 for(int j=i;j<L.length;j++)
                       L.data[j-1]=L.data[j];
                    L.length- -;
                    return ture;
                }
或者:
             status 
ListDelete_Sq(SqList &L,int i, ElemType &e)
                    if(i<1|| i<L.length +1)  return error;
                   p=&(L.elem[i-1]);
                   e=*p;
                   q=L.elem+L.length-1;    
   //注意:由于地址取数组的元素时是第一个地址,所以这样写是正确的
                   for (++p;p<=q;++p) *(p-1)=*p; 
                    - -   L.length;
                   return ok;
               }//  ListDelete_Sq
按值查找:
                  在线性表中查找与e相同的元素,并返回其位序。
                int   
LocateElem(SqList L,ElemType  e)    {
                   int i;
                  for (i=0;i<L.length;i++)
                     if(L.data[i]==e)
                         return i+1;
                         return 0;
                    }
 
 逆转顺序表中的所有元素:
               思路:采用第一个元素与最后一个元素进行对调的方法,第二个与倒数第二个对调,.......。
             void Reverse(int A[ ], int n)
               {
                   int i,t;
                   for (i=0;i<n/2;i++)
                   {
                          t=A[ i ];
                          A[ i ]=A[n-i-1];
                          
A[n-i-1]=t;
                   }
               } 
 当然还可以进行奇偶个数的分析,进行反转,可采用符号语句来进行。
              void  
Reverse (int A[ ], int n)
               {  
                     int i,t,p;
                     p=(n%2==0)? n/2:n/2+1;
                  {
                    t=a[i];
                    a[i]=a[p+i];
                    a[p+i]=t;
                    } 
                 }
   进一步思考:如果不是全部逆转,而是部分逆转,比如:abcdef——> cdefab,此时上面的程序就不能解决问题了。
   此时需要进行三步反转法:
          即:将ab当做X
                    cdef当做Y
              => 即问题转化为:将XY——>YX的转化。
   void 
ReverseString(char *s,int begin,int end)
    {
          while(begin<end)
          { 
              char t=s[begin];
              s[begin++]=s[end];
              s[end- -]=t;
            }
    }

void LeftRoateString(char *s,int n,int m)
{
    m%=n;
    
ReverseString(s,0,m-1);
    
ReverseString(s,m,n-1);
    
ReverseString(s,0,n-1);
}
思路就是三步反转法,时间复杂度是O(n) 


 6.线性表的链式表示
         线性表的链式存储又称为单链表(非随机存储结构),它是通过一组任意的存储单元来存储线性表中的数据元素。
单链表中的结点类型的描述如下:
          typedef  struct LNode{      //定义单链表的结点类型
              ElemType data;            //数据域
             struct  LNode *next;      //  指针域
           }LNode ,*LinkList;
采用头插法建立单链表:
         从一个空表开始,生成新的结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即结点之后。
          LinkList  CreateList1(LinkList &L) {
               LNode *s;int x;
              L=(LinkList)malloc(sizeof(
 LNode));
              L—>next=NULL;
             scanf("%d",&x);
             while(x!=9999){
                s=( 
LNode*)malloc(sizeof(  LNode));
                s—>data=x;
                s—>next=L 
—>next;
                L—>next=s;
                scanf("%d",&x);
              }
              return L;
         }
 采用尾插法建立单链表:
         将新结点插入到当前链表的表尾上,为此必须增加一个尾指针r,使其始终指向当前链表的尾结点。
    LinkList createList2( 
LinkList &L) {
      int x;
      
L=(LinkList)malloc(sizeof(  LNode));
      LNode *s,*r=L;
      scanf("%d ",&x);
      while(x!=9999) {
             s= 
LNode*)malloc(sizeof(  LNode));
             s—>data=x;
             r—>next=s;
             r=s;
             scanf("%d",&x);
             }
          r—>next=NULL;
          return L;
      }
 按序号查找结点值:
      
 LNode *GetElem( LinkList  L,int i)
         int j=1;
         
LNode   *p=L—>next;
         if(i==0)
             return L;
         if(i<1)
            return NULL;
         while(p&&j<i) {
              p=p—>next;
              j++;
          }
          return p;
      }

按值查找表结点:
        
LNode *GetElem( LinkList  L,     ElemType e)
         { 
               
  ElemType *p=L—>next;
               while(p!=NULL&&p—>data!=e)
                    p=p
—>next;
              return p;
         }
插入操作:
       p=GetElem(L,i-1);
       s—>next=p—>next;
       p—>next=s;
删除操作:
       
 p=GetElem(L,i-1);
        q=p—>next; 
        p —>next=q—>next ;
         free(q);

 


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值