数据结构 学习笔记02——线性表

线性表的定义:具有相同特性的数据元素的一个有限序列。该序列中所含元素的个数叫做线性表长度。
定义:L=(a1,a2,a3....an)
其中为a1表头元素,为an表尾元素
线性表的顺序存储结构
其直接将线性表的逻辑结构映射到存储结构上

***********************************************

例:线性表La,Lb分别表示集合A,B,求A = AUB。

void Union(List &La, List Lb) {  // 算法2.1
  // 将所有在线性表Lb中但不在La中的数据元素插入到La中
  int La_len,Lb_len,i;
  ElemType e;
  La_len = ListLength(La);          // 求线性表的长度  
  Lb_len = ListLength(Lb);
  for (i=1; i<=Lb_len; i++) {
    GetElem(Lb, i, e);              // 取Lb中第i个数据元素赋给e
    if (!LocateElem(La, e, equal))  // La中不存在和e相同的数据元素
      ListInsert(La, ++La_len, e);  // 插入
  }
} // union
View Code

例:

void MergeList(List La, List Lb, List &Lc) {  // 算法2.2
  // 已知线性表La和Lb中的元素按值非递减排列。
  // 归并La和Lb得到新的线性表Lc,Lc的元素也按值非递减排列。
  int La_len, Lb_len;
  ElemType ai, bj;      
  int i=1, j=1, k=0;
  InitList(Lc);
  La_len = ListLength(La);    
  Lb_len = ListLength(Lb);
  while ((i <= La_len) && (j <= Lb_len)) {  // La和Lb均非空
    GetElem(La, i, ai);
    GetElem(Lb, j, bj);
    if (ai <= bj) {
      ListInsert(Lc, ++k, ai);
      ++i;
    } else { 
      ListInsert(Lc, ++k, bj);
      ++j;
    }
  }
  while (i <= La_len) {
    GetElem(La, i++, ai);  ListInsert(Lc, ++k, ai);
  }
  while (j <= Lb_len) {
    GetElem(Lb, j++, bj);  ListInsert(Lc, ++k, bj);
  }
} // MergeList
View Code

***********************************************

线性表的顺序表示和实现


//---------------------线性表的顺序存储类型描述------------------------

#define MAXSIZE 50
typedef struct
{
   ElemType date[MAXSIZE];
   int length;
}SqList;

//---------------------线性表的的动态分配顺序存储结构--------------------

#define LIST_INIT_SIZE  100  //线性表存储空间的初始分配量
#define LISTINCREMENT  10   //线性表存储空间的分配增量
typedef struct{
         ElemType  * elem ;    //存储空间基址
         int            length ;     //当前长度
         int            listsize ;    //当前分配存储容量(以sizeof(ElemType)为单位)
}SqList;

//-------------------构造一个空的线性表L(以动态的方式)-------------------

Status InitList_Sq(SqList &L) {  // 算法2.3
  // 构造一个空的线性表L。
  L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
  if (!L.elem) return OK;        // 存储分配失败
  L.length = 0;                  // 空表长度为0
  L.listsize = LIST_INIT_SIZE;   // 初始存储容量
  return OK;
} // InitList_Sq

常用基本运算集合
      初始化
      创建
      销毁
      是否为空
      求线性表的长度
      输出线性表
      求线性表中某个元素的值
      按元素值查找
      插入运算(一般是前插)

顺序表位序从1开始,因此要注意将逻辑位序转化为物理位序

线性表插入、删除算法时间复杂度为O(n) [注:一般实现]
----------------------------------------------------------------------------------------------------------------
例:有一个顺序表A。设计一个算法,删除所有元素值在[x,y]之间的所有元素,要求算法时间复杂度为O(n),空间复杂度为O(1)
实现:以A表为基础重新构建一个表。

例:有一个顺序表L,假设元素类型ElemType为整型,并且所有元素均不相等。设计一个算法,以第一个元素为分界线,将所有小于它的元素移到该元素前面,将所有大于它的元素移到该元素的后面。
实现1:从两边向中间交替查找不满要求的元素进行交换
实现2:保留第一个元素的值,然后从右边前左边查到不满要求的元素,并将其设置到第一个元素位置 ... ...(变化基准位置(原来第一个元素的位置),从而将缺省出的基准位用于存放找到的数值)

//---------------------在顺序线性表L的第i个元素之前插入新的元素e-------------------------

Status ListInsert_Sq(SqList &L, int i, ElemType e) {  // 算法2.4
  // 在顺序线性表L的第i个元素之前插入新的元素e,
  // i的合法值为1≤i≤ListLength_Sq(L)+1
  ElemType *p;
  if (i < 1 || i > L.length+1) return ERROR;  // i值不合法
  if (L.length >= L.listsize) {   // 当前存储空间已满,增加容量
    ElemType *newbase = (ElemType *)realloc(L.elem,
                  (L.listsize+LISTINCREMENT)*sizeof (ElemType));
    if (!newbase) return ERROR;   // 存储分配失败
    L.elem = newbase;             // 新基址
    L.listsize += LISTINCREMENT;  // 增加存储容量
  }
  ElemType *q = &(L.elem[i-1]);   // q为插入位置
  for (p = &(L.elem[L.length-1]); p>=q; --p) *(p+1) = *p;
                                  // 插入位置及之后的元素右移
  *q = e;       // 插入e
  ++L.length;   // 表长增1
  return OK;
} // ListInsert_Sq
View Code

//--------------------在顺序线性表L中删除第i个元素,并用e返回其值-------------------------

Status ListDelete_Sq(SqList &L, int i, ElemType &e) {  // 算法2.5
  // 在顺序线性表L中删除第i个元素,并用e返回其值。
  // i的合法值为1≤i≤ListLength_Sq(L)。
  ElemType *p, *q;
  if (i<1 || i>L.length) return ERROR;  // i值不合法
  p = &(L.elem[i-1]);                   // p为被删除元素的位置
  e = *p;                               // 被删除元素的值赋给e
  q = L.elem+L.length-1;                // 表尾元素的位置
  for (++p; p<=q; ++p) *(p-1) = *p;     // 被删除元素之后的元素左移
  --L.length;                           // 表长减1
  return OK;
} // ListDelete_Sq
View Code

//--------------------在顺序线性表L中查找第1个值与e满足compare()的元素的位序------------

int LocateElem_Sq(SqList L, ElemType e,
        Status (*compare)(ElemType, ElemType)) {  // 算法2.6
  // 在顺序线性表L中查找第1个值与e满足compare()的元素的位序。
  // 若找到,则返回其在L中的位序,否则返回0。
  int i;
  ElemType *p;
  i = 1;        // i的初值为第1个元素的位序
  p = L.elem;   // p的初值为第1个元素的存储位置
  while (i <= L.length && !(*compare)(*p++, e)) 
    ++i;
  if (i <= L.length) return i;
  else return 0;
} // LocateElem_Sq
View Code

//--------------------已知顺序线性表La和Lb的元素按值非递减排列---------------------------

void MergeList_Sq(SqList La, SqList Lb, SqList &Lc) {  // 算法2.7
  // 已知顺序线性表La和Lb的元素按值非递减排列。
  // 归并La和Lb得到新的顺序线性表Lc,Lc的元素也按值非递减排列。
  ElemType *pa,*pb,*pc,*pa_last,*pb_last;
  pa = La.elem;  pb = Lb.elem;
  Lc.listsize = Lc.length = La.length+Lb.length;
  pc = Lc.elem = (ElemType *)malloc(Lc.listsize*sizeof(ElemType));
  if (!Lc.elem)
    exit(OVERFLOW);   // 存储分配失败
  pa_last = La.elem+La.length-1;
  pb_last = Lb.elem+Lb.length-1;
  while (pa <= pa_last && pb <= pb_last) {  // 归并
    if (*pa <= *pb) *pc++ = *pa++;
    else *pc++ = *pb++;
  }
  while (pa <= pa_last) *pc++ = *pa++;      // 插入La的剩余元素
  while (pb <= pb_last) *pc++ = *pb++;      // 插入Lb的剩余元素
} // MergeList
View Code

线性表的链式表示和实现


//--------------线性表的单链表存储结构---------------------

typedef struct  LNode{
        ElemType      data;
        struct LNode  *next;
}LNode, *LinkList;

对于带头节点的单链表而言
插入结点:s->next = p->next;
(插入S,先找到前一个节点p)
               p->next = s;

删除结点: p->next = p->next->next;(先找到前一个节点p)
--------------------------------------------------------------
例:有一个带头结点的单链表L={a1,b1,a2,b2,a3,b3,...,an,bn},设计一个算法将其拆分成两个带头结点的单链表L1和L2,L1={a1,a2,a3...an},L2={bn,bn-1,...b1}.要求L1使用L的头结点
注:链表的插入分头插和尾插
例:有一个带头结点的单链表L,设计一个算法使其元素递增有序。
问:带头结点的单链表与不带头结点的单链表有何区别?
答:带头结点单链表可以在头节点中加入一些附加信息,并且有利于实现各种运算(删除和插入)。

//----------------------取第i个值-----------------------------------------

Status GetElem_L(LinkList &L,int i, ElemType &e) {  // 算法2.8
  // L为带头结点的单链表的头指针。
  // 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
  LinkList p;
  p = L->next;   
  int j = 1;           // 初始化,p指向第一个结点,j为计数器
  while (p && j<i) {   // 顺指针向后查找,直到p指向第i个元素或p为空
    p = p->next;  ++j;
  }
  if ( !p || j>i ) return ERROR;  // 第i个元素不存在
  e = p->data;   // 取第i个元素
  return OK;
} // GetElem_L
View Code

//----------------在带头结点的单链线性表L的第i个元素之前插入元素e--------

Status ListInsert_L(LinkList &L, int i, ElemType e) {  // 算法2.9
  // 在带头结点的单链线性表L的第i个元素之前插入元素e
  LinkList p,s;
  p = L;   
  int j = 0;
  while (p && j < i-1) {  // 寻找第i-1个结点
    p = p->next;
    ++j;
  } 
  if (!p || j > i-1) return ERROR;      // i小于1或者大于表长
  s = (LinkList)malloc(sizeof(LNode));  // 生成新结点
  s->data = e;  s->next = p->next;      // 插入L中
  p->next = s;
  return OK;
} // LinstInsert_L
View Code

//---------在带头结点的单链线性表L中,删除第i个元素,并由e返回其值--------

Status ListDelete_L(LinkList &L, int i, ElemType &e) {  // 算法2.10
  // 在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
  LinkList p,q;
  p = L;
  int j = 0;
  while (p->next && j < i-1) {  // 寻找第i个结点,并令p指向其前趋
    p = p->next;
    ++j;
  }
  if (!(p->next) || j > i-1) return ERROR;  // 删除位置不合理
  q = p->next;
  p->next = q->next;           // 删除并释放结点
  e = q->data;
  free(q);
  return OK;
} // ListDelete_L
View Code

//------逆位序输入(随机产生)n个元素的值,建立带表头结点的单链线性表L-----

void CreateList_L(LinkList &L, int n) {  // 算法2.11
  // 逆位序输入(随机产生)n个元素的值,建立带表头结点的单链线性表L 
  LinkList p;
  int i;
  L = (LinkList)malloc(sizeof(LNode));
  L->next = NULL;              // 先建立一个带头结点的单链表
  for (i=n; i>0; --i) {
    p = (LinkList)malloc(sizeof(LNode));  // 生成新结点
    p->data = random(200);     // 改为一个随机生成的数字(200以内)
    p->next = L->next;    L->next = p;    // 插入到表头
  }
} // CreateList_L
View Code

//-----------------有序合并链表----------------------------------------

void MergeList_L(LinkList &La, LinkList &Lb, LinkList &Lc) {
  // 算法2.12
  // 已知单链线性表La和Lb的元素按值非递减排列。
  // 归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列。
  LinkList pa, pb, pc;
  pa = La->next;    pb = Lb->next;
  Lc = pc = La;             // 用La的头结点作为Lc的头结点
  while (pa && pb) {
    if (pa->data <= pb->data) {
      pc->next = pa;   pc = pa;   pa = pa->next;
    }
    else { pc->next = pb;   pc = pb;   pb = pb->next; }
  }
  pc->next = pa ? pa : pb;  // 插入剩余段
  free(Lb);                 // 释放Lb的头结点
} // MergeList_L
View Code

 

//--------------线性表的静态单链表存储结构------------------------

#define MAXSIZE 100
typedef struct
{
   ElemType data; //数据域
   int cur;      //游标域,指示下一个元素在数组中的位置
}component,StaticList[MaxSize];

静态链表是借助一维数组来描述链表。数组中的一个分量表示一个结点,同时使用游标(cur)代替指针以指示结点在数组中的相对位置(游标为-1时表示相对应的结点为空).数组中的0分量可以看成头结点,其指针域指示静态链表的第一个结点,并将最后一个元素的指针域0构成循环结构
这种存储结构需预先分配一个较大空间,但是在进行线性表插入和删除操作时不需移动元素,仅需要修改“指针”,因此仍然具有链式存储结构的主要优点。

对于静态链表的初始化,一定要将其它没有元素的结点的.next设为-1,并将下标为[0].next设为0
对于静态链表可视为一个带头节点的循环链表,_StaticList[0]为其头结点,对于插入操作一般都先查找到前一个结点(前插),另对于新的插入项一定要存在下.next为-1的位置上。
另对于删除时要考虑链表是否为空表,对于插入要考虑是否表满

同样静态也有不带头节点的,类似于不带头节点的循环链表
同样可以构造类似于循环双链表的静态链表  
等等总之灵活多样但一般不存在单链表式的静态链表

 双链表
双链表的创建与单链表相似,只不过每个结点多了个PRIOR指针域

typedef struct  DLNode{
        ElemType      data;
        struct DLNode  *prior;
        struct DLNode  *next;
}DLNode, *DuLinkList;    


双链表亦可分头插和尾插
特点(对称性):
p->next->prior = p;
p->prior->next = p;
//-------------在带头结点的双链循环线性表L的第i个元素之前插入元素e--------------

Status ListInsert_DuL(DuLinkList &L, int i, ElemType e) { //算法2.18
  // 在带头结点的双链循环线性表L的第i个元素之前插入元素e,
  // i的合法值为1≤i≤表长+1。
  DuLinkList p,s;
  if (!(p = GetElemP_DuL(L, i)))  // 在L中确定第i个元素的位置指针p
    return ERROR;                 // p=NULL, 即第i个元素不存在
  if (!(s = (DuLinkList)malloc(sizeof(DuLNode))))
    return ERROR;
  s->data = e;
  s->prior = p->prior;
  p->prior->next = s;
  s->next = p;
  p->prior = s;
  return OK;
} // ListInsert_DuL

//--------------删除带头结点的双链循环线性表L的第i个元素-----------------

Status ListDelete_DuL(DuLinkList &L, int i, ElemType &e) {//算法2.19
  // 删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i≤表长
  DuLinkList p;
  if (!(p = GetElemP_DuL(L, i)))  // 在L中确定第i个元素的位置指针p
    return ERROR;                 // p=NULL, 即第i个元素不存在
  e = p->data;
  p->prior->next = p->next;
  p->next->prior = p->prior;
  free(p);    
  return OK;
} // ListDelete_DuL
View Code


循环链表
分为带头结点的循环单链表和循环双链表。
其判断结尾条件是:p->next == L(头结点)
因此头结点也连在整个循环链表中
针对于其初始化:
L->prior = L;
L->next  = L;
一般为解决特殊问题
还存在不带头结点的循环单链表和循环双链表(如约瑟夫环)
--------------------------------------------------------------------------------


一元多项式的表示及相加


//-------输入m项的系数和指数,建立表示一元多项式的有序链表P------------

void CreatPolyn(PLinkList &P, int m) {  // 算法2.22
  // 输入m项的系数和指数,建立表示一元多项式的有序链表P
  PLink h, q, s;
  PElemType e;
  int i;
  InitList(P);   h = GetHead(P);
  e.coef = 0.0;  e.expn = -1;
  SetCurElem(h, e);       // 设置头结点
  for (i=1; i<=m; ++i) {  // 依次输入m个非零项
    // scanf ("%f,%d\n",&e.coef, &e.expn);
    e.coef = (float)(random(1, 90) + random(10)/10.0);
    if (random(2)) e.coef = -e.coef;
    e.expn=e.expn+random(1,10); //产生随机的数据,但是expn值是递增的
    if (!LocateElem(P, e, q, cmp)) { // 当前链表中不存在该指数项
      if (MakeNode(s,e)) InsFirst(q, s);  // 生成结点并插入链表
      if(q==P.tail) P.tail=s;
    } else i--;  //  如果没有产生插入,则将i值减1
  }
} // CreatPolyn
View Code

//---------打印输出一元多项式---------------

Status PrintfPoly(PLinkList P) {
  int i=0;
  PLink q=P.head->next;
  while (q) {
    if (fabs(q->data.coef) > 0.005) {
      if (i>0) {
        if (q->data.coef>0.005) printf(" + ");
        else printf(" - ");
        printf("%.2f", fabs(q->data.coef));
      } else printf("%.2f", q->data.coef);
      if (q->data.expn>=1) printf("x");
      if (q->data.expn>1) printf("^%d", q->data.expn);
    }
    q=q->next;
    if (++i % 6 == 0) printf("\n     ");
  }
  printf("\n");
  return OK;
}
View Code

 

//-------------多项式加法-----------------

void AddPolyn(PLinkList &Pa, PLinkList &Pb) {  // 算法2.23
  // 多项式加法:Pa = Pa+Pb,利用两个多项式的结点构成"和多项式"。
  PLink ha,hb,qa,qb;
  PElemType a, b, temp;
  float sum;
  ha = GetHead(Pa);      // ha和hb分别指向Pa和Pb的头结点
  hb = GetHead(Pb);
  qa = NextPos(Pa,ha);   // qa和qb分别指向La和Lb中当前结点
  qb = NextPos(Pb,hb);
  while (qa && qb) {     // Pa和Pb均非空
    a = GetCurElem (qa); // a和b为两表中当前比较元素
    b = GetCurElem (qb);
    switch (Compare(a,b)) {
      case -1:  // 多项式PA中当前结点的指数值小
          ha = qa;
          qa = NextPos (Pa, qa);
          break;  
      case 0:   // 两者的指数值相等
          sum = a.coef + b.coef ;
          if (sum != 0.0) {  // 修改多项式PA中当前结点的系数值
            temp.coef=sum;
            temp.expn=a.expn;
            SetCurElem(qa, temp) ;
            ha = qa;
          } else {  // 删除多项式PA中当前结点
            DelFirst(ha, qa);
            FreeNode(qa);
          }
          DelFirst(hb, qb);
          FreeNode(qb);
          qb = NextPos(Pb, hb);
          qa = NextPos(Pa, ha);
          break;
      case 1:   // 多项式PB中当前结点的指数值小
          DelFirst(hb, qb);
          InsFirst(ha, qb); 
          qb = NextPos(Pb, hb);
          ha = NextPos(Pa, ha);
          break;
    } // switch
  } // while
  if (!Empty(Pb)) Append(Pa, qb);   // 链接Pb中剩余结点
  FreeNode(hb);  // 释放Pb的头结点
} // AddPolyn


 

数据结构实验——线性表,链表

----------------------------

http://pan.baidu.com/share/link?shareid=2216128142&uk=186843953

源文件,实验报告分享。

 



posted @ 2013-11-19 15:52  Hewie_Bai  阅读(736)  评论(0编辑  收藏  举报