线性表介绍

来源:互联网 发布:淘宝店标制作网站 编辑:程序博客网 时间:2024/06/03 20:09

线性表是一种常用的数据结构。在实际应用中,线性表都是以栈、队列、字符串、数组等特殊线性表的形式来使用的。由于这些特殊线性表都具有各自的特性,因此,掌握这些特殊线性表的特性,对于数据运算的可靠性和提高操作效率都是至关重要的。 

线性表是一个线性结构,它是一个含有n≥0个结点的有限序列,对于其中的结点,有且仅有一个开始结点没有前驱但有一个后继结点,有且仅有一个终端结点没有后继但有一个前驱结点,其它的结点都有且仅有一个前驱和一个后继结点

线性表分为顺序存储和链式存储。

这里主要简单介绍一下顺序存储,其特点是可以随机地访问元素,缺点是在进行插入和删除操作时需要移动大量的元素。

C语言实现代码:

/*Introduction:easy data structure of listDate:2017-03-26 */ #include <stdio.h>  #include <stdlib.h>  //宏定义  #define TRUE   1  #define FALSE   0  #define OK    1  #define ERROR   0  #define INFEASIBLE -1  //infeasible意为不可执行的 #define OVERFLOW -2   //代表溢出       #define LIST_INIT_SIZE 100 //线性表初始空间分配量  #define LISTINCREMENT   10 //线性表空间分配的增量  typedef int Status;  typedef int ElemType;  typedef struct LNode{      ElemType  *elem;        //存储空间的基地址      int      length;        //当前的长度      int      listsize;      //当前分配的存储容量  }SqList;  /**  *构造空的线性表  */  Status initList(SqList &L, int size){      if (size == 0) size = LIST_INIT_SIZE;      L.elem = (ElemType *)malloc(size * sizeof(ElemType));      if(!L.elem) exit(OVERFLOW);  //分配存储空间失败      L.length = 0;                //初始空表长度为0      L.listsize = size ;//初始存储容量为100      return OK;  }  /************************************************************************/  /* 在第i位置插入e */  /************************************************************************/  Status insertList(SqList &L, ElemType e, int i){      ElemType *p,  *q;      if(i<0 ||i > L.length) return ERROR;  //i值不合法      if (L.length >= L.listsize) {          ElemType *newbase = (ElemType *)realloc(L.elem ,(L.listsize +LISTINCREMENT)*sizeof(ElemType));          if(!newbase) return OVERFLOW;   //存储分配失败            L.elem = newbase;               //新基值          L.listsize += LISTINCREMENT;    //增加存储容量      }      q = &L.elem[i];                     //q为插入的位置      for (p = &L.elem[L.length]; p>=q; --p) {          *p = *(p-1);                    //i元素之后的元素往后移动      }      *q = e;                             //插入e      L.length +=1;      return OK;  }  /************************************************************************/  /* 删除第i位置元素,并用e返回其值                                                                     */  /************************************************************************/  Status deleteListElem(SqList &L, int i, ElemType &e){      int *p,  *q;      if(i<0 ||i > L.length) return ERROR;  //i值不合法      q = &L.elem[i];                       //被删除元素的位置为i,L.elem就是数组名,      e = *q;                               //被删除元素的值赋值给e      for (p = q; p< (L.elem + L.length); p++){ //元素左移          *p = *(p+1);      }      --L.length;      return OK;  }  /************************************************************************/  /*  快速排序 */  /************************************************************************/  int partition(SqList &L, ElemType low, ElemType high){      ElemType pivotkey = L.elem[low];               //枢轴记录关键字      while (low < high) {                  //从表的两端向中间扫描          while (low < high &&  L.elem[high] >= pivotkey ) --high;//高端位置扫描          L.elem[low] = L.elem[high];     //交换数据,小于pivotkey移到低端          L.elem[high] = pivotkey;          while (low < high && L.elem[low] <= pivotkey ) ++low;     //低端扫描          L.elem[high] = L.elem[low];               //交换数据 大于pivotkey移到高端          L.elem[low] = pivotkey;                                       }      return low;  }  void quickSort(SqList &L, ElemType low, ElemType high){      int pivot;      if(low < high) {                                                  pivot =  partition(L,  low,  high);               quickSort(L,  low,  pivot -1);          //低端子表排序          quickSort(L,  pivot +1, high);          //高端子表排序      }  }  /************************************************************************/  /*  合并两个线性表 */  /************************************************************************/  void mergeList(SqList La, SqList Lb,  SqList &Lc){      ElemType *pa, *pb, *pc;      Lc.listsize =  La.length + Lb.length;      initList(Lc, Lc.listsize);          //初始化LC\pc = Lc.elem;      Lc.length = Lc.listsize;      pc = Lc.elem;      pa = La.elem;      pb = Lb.elem;      while (pa <= &La.elem[La.length -1] && pb <= &Lb.elem[Lb.length -1]){          if (*pa <= *pb) *pc++ = *pa++;          else *pc++ = *pb++;      }      while(pa <= &La.elem[La.length -1]) *pc++ = *pa++; //插入La的剩余元素      while(pb <= &Lb.elem[Lb.length -1]) *pc++ = *pb++; //插入Lb的剩余元素  }  /************************************************************************/  /* 打印list */  /************************************************************************/  void printList(SqList L){      printf("当前值:");       for (int i =0; i<L.length;i++) {          printf("%d ", *(L.elem+i)); // L.elem为首地址      }       printf("\n");   }  int main()  {      SqList La,Lb,Lc;      ElemType e;      int init,i;      init = initList(La, LIST_INIT_SIZE);      int data[6] = {5,3,6,2,7,4};      for (i=0; i<6;i++) {          insertList(La,  data[i],  i);      }      printf("LA:\n");       printList(La);      //测试删除     deleteListElem(La, 3, e );      printList(La);     //测试插入     insertList(La,  e,  3);      printList(La);      //实现快速排序并将结果打印     quickSort(La,0, La.length-1);      printList(La);      printf("LB:\n");       initList(Lb, LIST_INIT_SIZE);      int Bdata[5] = {1,3,2,4,6};      for (i=0; i<5;i++) {          insertList(Lb,  Bdata[i],  i);      }      //实现快速排序并将结果打印      quickSort(Lb,0, Lb.length-1);      printList(Lb);      //测试合并     mergeList(La, Lb,  Lc);      printf("合并之后:\n");    printList(Lc);      return 0;  } 

在定义线性表时,我们可以定义一个结构体来标识线性表

typedef struct LNode{      ElemType  *elem;        //存储空间的基地址      int      length;        //当前的长度      int      listsize;      //当前分配的存储容量  }SqList;  

其中,我们必须定义线性表第一个元素的存放位置,即整个线性表的首地址,还要定义线性表的最大容量listsize,最后用一个length来表示当前线性表中元素的数目即线性表的长度


再接着我们介绍一下线性表的链式存储,这样的优点是插入和删除元素时只要改变指针的指向即可,缺点是要访问一个元素时必须进行遍历,不能确切地知道元素的位置。

C语言实现代码:

/*Introduction:easy Data Structure of LinkListDate:2017-03-26 */ #include <stdio.h>  #include "stdlib.h"  #define TRUE   1  #define FALSE   0  #define OK    1  #define ERROR   0  #define OVERFLOW -2  typedef int Status;  typedef int ElemType;  typedef struct LNode{       ElemType  data;     //数据域              struct LNode   *next;  //指向下一个元素的指针域   }LNode, *LinkList;  /************************************************************************/  /* 初始化链表 */  /************************************************************************/  Status initList(LinkList &L){      /*单链表的初始化*/      L = (LinkList)malloc(sizeof(LNode));    //申请一个头节点      if(!L) exit(OVERFLOW);          //申请空间失败        L->next=NULL;                //建立一个带头节点的空链表      return OK;  }  /************************************************************************/  /*      创建链表 */  /************************************************************************/  void createList(LinkList L, int n){      /*单链表的初始化*/      if (!L) {          initList(L);      }      ElemType data;      LinkList p,q = L;      printf("输入节点数据的个数%d:\n", n);      for(int i = 0; i<n; i++) {           scanf("%d",&data);         p = (LinkList) malloc( sizeof(LNode)); //申请一个新节点          q->data = data;          q->next=p;        if(i==n-1){     //当到了最后的一个节点时一定要将其next指针置为NULL            q->next=NULL;break;          }        q=p;    }  }  /************************************************************************/  /* 在第i位置插入e */  /************************************************************************/  Status insertList(LinkList L, ElemType e, int i){      LinkList s, p = L;      int j = 0;      while (p && j<i){                //寻找i节点          p = p->next;          j++;      }      if (!p ||j >i) return ERROR;      s = (LinkList) malloc(sizeof(LNode));       //生成新节点      s->data = e; s->next = p->next;            //插入L中      p->next = s;      return OK;  }  /************************************************************************/  /* 删除第i位置元素,并用e返回其值                   */  /************************************************************************/  Status deleteListElem(LinkList L, int i, ElemType *e){      LinkList p, q;    int j = 0;      p = L;      while (p && j<i){          p = p->next;          ++j;      }      if (!p->next || j>i)  return ERROR;   //删除的位置不对      q  = p->next; p->next = q->next;      *e = q->data; free(q);            //释放节点      return OK;  }  /************************************************************************/    /*  插入排序  */    /************************************************************************/     /* 1、先在原链表中以第一个节点为一个有序链表,其余节点为待定节点。 2、从图12链表中取节点,到图11链表中定位插入。 3、上面图示虽说画了两条链表,其实只有一条链表。在排序中,实质只增加了一个用于指向剩下需要排序节点的头指针first罢了。    这一点请读者务必搞清楚,要不然就可能认为它和上面的选择排序法一样了。 */  LinkList InsertSort(LinkList L)  {      LinkList first; /*为原链表剩下用于直接插入排序的节点头指针*/      LinkList t; /*临时指针变量:插入节点*/      LinkList p; /*临时指针变量*/      LinkList q; /*临时指针变量*/      first = L->next; /*原链表剩下用于直接插入排序的节点链表:可根据图12来理解。*/      L->next = NULL; /*只含有一个节点的链表的有序链表:可根据图11来理解。*/      while (first != NULL) /*遍历剩下无序的链表*/      {          /*注意:这里for语句就是体现直接插入排序思想的地方*/          for (t = first, q = L;q != NULL && q->data < t->data;p = q, q = q->next);         /*无序节点在有序链表中找插入的位置*/      /*退出for循环,就是找到了插入的位置*/      /*注意:按道理来说,这句话可以放到下面注释了的那个位置也应该对的,但是就是不能。原因:你若理解了上面的第3条,就知道了。*/          first = first->next; /*无序链表中的节点离开,以便它插入到有序链表中。*/           if (q == L) /*插在第一个节点之前*/          {              L = t;          }          else /*p是q的前驱*/          {              p->next = t;          }          t->next = q; /*完成插入动作*/          /*first = first->next;*/      }     return L;}  /************************************************************************/  /*  合并两个线性表 */  /************************************************************************/  LinkList mergeList(LinkList  &La, LinkList  &Lb,  LinkList &Lc){     LinkList Test;    Test=La;    while(La->next!=NULL){        La=La->next;    }  //先遍历链表La,使La的尾节点的指针指向Lb的头节点     La->next=Lb;    Lc=Test;    Lc=InsertSort(Lc);    return Lc; }  /************************************************************************/  /* 打印list */  /************************************************************************/  void printList(LinkList  L){      printf("打印链表:");      LinkList p;      p = L;      while(p){          printf("%d ", p->data);           p = p->next;      }      printf("\n");   }  int main()  {      LinkList  La,Lb,Lc;      ElemType *e;      int init,i;      printf("La:\n");        initList(La);      createList(La, 5);    printf("创建La之后的各元素值:\n");    printList(La);      insertList(La, 7,  3);     printf("插入元素之后的各元素值:\n");       printList(La);      deleteListElem(La, 3,  e);     printf("删除的元素为:%d\n",*e);    printf("删除元素之后的各元素值:\n");       printList(La);    //输出插入排序之后的表     La=InsertSort(La);    printf("插入排序之后La的各元素值:\n");     printList(La);      printf("\n\n");    printf("Lb:\n");        initList(Lb);      createList(Lb, 4);     printf("创建Lb之后的");    printList(Lb);    //输出插入排序之后的表     Lb=InsertSort(Lb);    printf("插入排序之后Lb的各元素值:\n");    printList(Lb);      printf("\n\n");    printf("Lc:\n");       initList(Lc); //初始化一个空表     Lc=mergeList(La,Lb,Lc);      printf("合并之后的表:\n");    printList(Lc);      return 0;}

这里主要需要弄清楚插入排序的思想和链式存储指针域的指向问题。


1 0