zoukankan      html  css  js  c++  java
  • 线性表

    首先,线性表是一种最简单的一种数据结构。嗯,简单的说,一个线性表是n个数据元素的有限序列。(元素:可以是int ,float, double 等)
    线性表的储存结构是这样的:

    在表中a(i - 1)领先于ai ,ai 领先于 a(i+1),则称 a(i-1)是ai的直接前驱元素,a(i+1)是ai的直接后驱元素。对于其中的结点,有且仅有一个开始结点没有前驱但有一个后继结点(a1),有且仅有一个终端结点没有后继但有一个前驱结点(an),其它的结点都有且仅有一个前驱和一个后继结点。

    线性表的顺序是指用连续的存储单元来存储线性表的数据元素。线性表的顺序存储结构是一种随机存取的存储结构。

    其一般有两种顺序存储方式:数组和链表。(分解的用链表,最后附上数组的)

      (1)用数组来存:  优点:可以随机访问元素。  缺点:插入和删除的时候需要移动大量的元素。

      (2)用链表:  优点:对于新增和删除很方便,不需要移动元素。  缺点:不方便随机访问元素,需要一定元素。

      

    1.数组的实现

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 /******* 创建别名 ******/
     5 typedef int Status;
     6 typedef int ElemType;
     7 
     8 /******* 宏定义 *******/
     9 #define TRUE   1  
    10 #define FALSE   0  
    11 #define OK    1  
    12 #define ERROR   0  
    13 #define INFEASIBLE -1  
    14 #define OVERFLOW -2  
    15 
    16 /******* 线性表的动态分配顺序存储结构 *******/
    17 #define LIST_INIT_SIZE 100    //线性表存储空间的初始分配量
    18 #define LISTINCREMENT 10    //线性表存储空间的分配增量
    19 typedef struct{
    20     ElemType *elem;    //存储空间基址
    21     int length;        //当前长度
    22     int listsize;    //当前分配的存储容量
    23 }SqList;
    24 
    25 /******** 构造一个空的线性表 ********/
    26 Status InitList_Sq(SqList &L){
    27     L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
    28     //让电脑分配(ElemType)的字节 * LIST_INIT_SIZE 数量个内存空间,然后地址给L.elem
    29     if (!L.elem)    //存储分配失败
    30         exit(OVERFLOW);    
    31     /*
    32         exit() 是电脑函数
    33         exit()通常是用在子程序中用来终结程序用的,使用后程序自动结束,跳回操作系统。
    34         exit(0)表示正常退出,
    35         exit(x)(x不为0)都表示异常退出
    36     */
    37     L.length = 0;    //空表长度为0
    38     L.listsize = LIST_INIT_SIZE;    //初始存储的容量
    39     return OK;    //构造成功
    40 }

    对线性表的一些基本操作:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 
      4 /******* 创建别名 ******/
      5 typedef int Status;
      6 typedef int ElemType;
      7 
      8 /******* 宏定义 *******/
      9 #define TRUE   1  
     10 #define FALSE   0  
     11 #define OK    1  
     12 #define ERROR   0  
     13 #define INFEASIBLE -1  
     14 #define OVERFLOW -2  
     15 
     16 /******* 线性表的动态分配顺序存储结构 *******/
     17 #define LIST_INIT_SIZE 100    //线性表存储空间的初始分配量
     18 #define LISTINCREMENT 10    //线性表存储空间的分配增量
     19 typedef struct{
     20     ElemType *elem;    //存储空间基址
     21     int length;        //当前长度
     22     int listsize;    //当前分配的存储容量
     23 }SqList;
     24 
     25 /******** 构造一个空的线性表 ********/
     26 Status InitList_Sq(SqList &L){
     27     L.elem = (ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));
     28     //让电脑分配(ElemType)的字节 * LIST_INIT_SIZE 数量个内存空间,然后地址给L.elem
     29     if (!L.elem)    //存储分配失败
     30         exit(OVERFLOW);    
     31     /*
     32         exit() 是电脑函数
     33         exit()通常是用在子程序中用来终结程序用的,使用后程序自动结束,跳回操作系统。
     34         exit(0)表示正常退出,
     35         exit(x)(x不为0)都表示异常退出
     36     */
     37     L.length = 0;    //空表长度为0
     38     L.listsize = LIST_INIT_SIZE;    //初始存储的容量
     39     return OK;    //构造成功
     40 }
     41 
     42 /****** 在L中第i个位置之前插入新的元素e *******/
     43 Status insertList(SqList &L, ElemType e, int i){
     44     ElemType *p, *q;    //申明两个类型为ElemType的指针变量
     45     if (i < 0 || i > L.length + 1)
     46         return ERROR;  //i值不合法(i的合法范围为 1<=i<=L.length+1) 
     47     if (L.length >= L.listsize) {    //当前的存储空间已满,需要增加分配
     48         ElemType *newbase = (ElemType *)realloc(L.elem, (L.listsize + LISTINCREMENT)*sizeof(ElemType));
     49         /*
     50             先判断当前的指针是否有足够的连续空间,如果有,扩大L.elem指向的地址,并且将L.elem返回;
     51             如果空间不够,先按照newsize(L.listsize + LISTINCREMENT)*sizeof(ElemType)指定的大小分配空间,
     52             将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来L.elem所指内存区域
     53             (注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。
     54             如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。
     55         */
     56         if (!newbase)
     57             return OVERFLOW;   //存储分配失败(即newbase 为NULL)  
     58         L.elem = newbase;               //新基值  
     59         L.listsize += LISTINCREMENT;    //增加存储容量  
     60     }
     61     q = &L.elem[i - 1];                     //q为插入的位置  
     62     for (p = &L.elem[L.length]; p >= q; --p) {
     63         *(p + 1) = *p;                    //i元素及之后的元素往后移动  
     64     }
     65     *q = e;                             //插入e  
     66     L.length++;        //表长加1    
     67     return OK;    //操作成功
     68 }
     69 
     70 /******** 删除第i个元素,并用e返回其值 **********/
     71 Status deleteListElem(SqList &L, int i, ElemType &e){
     72     ElemType *p, *q;    //申明两个类型为ElemType的指针变量
     73     if (i<1 || i > L.length)
     74         return ERROR;  //i值不合法 (i的合法范围是 1<=i<=L.length) 
     75     p = &L.elem[i - 1];                       //被删除元素的位置为i,L.elem就是数组名,  
     76     e = *p;                               //被删除元素的值赋值给e
     77     q = L.elem + L.length - 1;            //表尾元素的位置
     78     for (++p; p <= q; p++){       
     79         *(p - 1) = *p;        //被删除元素后的元素左移
     80     }
     81     L.length--;    //表长减一
     82     return OK;    //操作成功
     83 }
     84 
     85 /************** 比较函数 **************/
     86 Status Integercompare(ElemType x, ElemType y){
     87     if (x == y)
     88         return OK;
     89     else
     90         return ERROR;
     91 }
     92 
     93 /****** 在顺序线性表L中查找第i个值与e满足compare()的元素的位序 ******/
     94 int LocateElem_Sq(SqList L, Status e, Status(*compare)(ElemType, ElemType)){
     95     //Status(*compare)(ElemType, ElemType)是一个函数指针
     96     int i = 1;    //第一个元素的位序
     97     int *p;
     98     p = L.elem;    //p为第一个元素的储存位置
     99     while (i <= L.length&&!(*compare)(*p++, e))//从头开始一个一个往后比较(当到表尾或找到时跳出)
    100         i++;
    101     if (i <= L.length)    //即i在表L 的内部
    102         return i;    //返回找到的位序
    103     else
    104         return 0;    //没有找到
    105 }
    106 
    107 /********* 归并La和Lb得到新的线性表Lc *********/
    108 void MergeList_Sq(SqList La, SqList Lb, SqList &Lc){
    109     //已知顺序线性表La ,Lb的元素按值非递减排列
    110     ElemType *pa, *pb, *pc;        //申明3个类型为ElemType的指针变量
    111     Lc.listsize = Lc.length = La.length + Lb.length;    //Lc的长度是La的当前长度+Lb的当前长度
    112     pc = Lc.elem = (ElemType *)malloc(Lc.listsize*sizeof(ElemType));    //将Lc的首地址给pc
    113     if (!Lc.elem)    
    114         exit(OVERFLOW);    //存储分配失败(即Lc.elem 为NULL)
    115     ElemType *pa_last, *pb_last;    //申明2个类型为ElemType的指针变量
    116     pa_last = La.elem + La.length - 1;    //pa_last 是线性表La的末地址
    117     pb_last = Lb.elem + Lb.length - 1;    //pb_last 是线性表Lb的末地址
    118     while (pa <= pa_last && pb <= pb_last){    //判断La和Lb是否遍历完了
    119         if (*pa <= *pb) 
    120             *pc++ = *pa++;        //如果*pa <= *pb,则将*pc = *pa;
    121         else 
    122             *pc++ = *pb++;        //否则(*pa<*pb),则将*pc = *pb;
    123     }
    124     while (pa <= pa_last) *pc++ = *pa++;    //插入La的剩余元素
    125     while (pb <= pb_last) *pc++ = *pb++;    //插入Lb的剩余元素
    126 }
    127 
    128 int main(){
    129     //省略
    130     return 0;
    131 }

    2.线性链表实现(单链表)

    单链表的逻辑存储状态就是这样的。

    一般的操作:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 
      4 /******* 创建别名 ******/
      5 typedef int Status;
      6 typedef int ElemType;
      7 
      8 /******* 宏定义 *******/
      9 #define TRUE   1  
     10 #define FALSE   0  
     11 #define OK    1  
     12 #define ERROR   0  
     13 #define INFEASIBLE -1  
     14 #define OVERFLOW -2  
     15 
     16 /******* 单链表的存储结构 ******/
     17 typedef struct LNode{
     18     ElemType data;    //单链表的数据域
     19     struct LNode *next;    //单链表的指针域
     20 }LNode, *LinkList;    //*LinkList 是该结构体的指针
     21 
     22 /******* 单链表的创建 ********/
     23 Status ListInit_L(LinkList &L){
     24     L = (LinkList)malloc(sizeof(LNode));    //申请一个头结点
     25     if (!L)    
     26         exit(ERROR);    //申请空间失败(L = NULL)
     27     L->next = NULL;        //建立一个空链表
     28     return OK;    //操作成功
     29 }
     30 
     31 /******* 单链表的初始化 *******/
     32 void ListCreate_L(LinkList &L, int n){
     33     ElemType data1;
     34     LinkList p, q;    //创建两个结构体指针
     35     q = L;    //q指向L的地址
     36     for (int i = 0; i < n; i++) {        //添加n个数据(即要循环n次)
     37         p = (LinkList)malloc(sizeof(LNode)); //申请一个新节点  
     38         scanf("%d", &data1);        //输入数据
     39         p->data = data1;            //p的数据域为data1
     40         p->next = q->next;            //p的指针域指向 q的指针域指向的地址
     41         q->next = p;                //再将q的指针域指向p
     42         q = p;            //此时将p赋给q
     43         //后面有配图解释
     44     }
     45 }
     46 
     47 /********* 单链表中寻找元素 *********/
     48 Status GetElem_L(LinkList L, int i, ElemType &e){
     49     //当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
     50     LinkList p;
     51     p = L->next;    //初始化,p指向第一个节点
     52     int j =    1;    //j为计数器
     53     while (p && j<i){                //顺着指针向后查找,直到p指向第i个元素或p为空
     54         p = p->next;
     55         j++;
     56     }
     57     if (!p || j >i)            //第i个元素不存在
     58         return ERROR;
     59     e = p->data;    //取第i个元素用e储存
     60     return OK;        //操作成功
     61 }
     62 
     63 /********* 单链表中在第i个位置之前插入元素e ***********/
     64 Status ListInsert_L(LinkList &L, ElemType e, int i){
     65     LinkList s, p = L;    
     66     int j = 0;    //计数器
     67     while (p && j < i - 1){                //顺着指针向后查找第i-1节点  
     68         p = p->next;
     69         j++;
     70     }
     71     if (!p || j > i - 1)    //i小于1或者大于表长加一   就不是合法范围
     72         return ERROR;
     73     s = (LinkList)malloc(sizeof(LNode));       //生成新节点  
     74     s->data = e;
     75     s->next = p->next;            //插入L中  
     76     p->next = s;
     77     //后面有配图解释
     78     return OK;    //操作成功
     79 }
     80 
     81 /****** 删除第i个元素,并由e返回其值 *********/
     82 Status ListDelete_L(LinkList &L, int i, ElemType &e){
     83     LinkList p, q;
     84     int j = 0;        //计数器
     85     p = L;            //初始化,将L的头指针给p
     86     while (p->next && j < i-1){    //寻找第i个节点,并令p指向其前驱
     87         p = p->next;
     88         ++j;
     89     }
     90     if (!p->next || j > i-1)  //删除的位置不合理
     91         return ERROR;
     92     q = p->next;        //删除节点
     93     p->next = q->next;
     94     e = q->data;        //去其值给e
     95     //后面有配图解释
     96     free(q);            //释放节点  
     97     /*
     98         free是调用操作系统的函数,将原先分配的内存区域释放
     99         与malloc()函数配对使用,释放malloc函数申请的动态内存。
    100     */
    101     return OK;
    102 }
    103 
    104 /********* 逆位序输入n个元素的值,初始化单链表L **********/
    105 void CreateLiet_L(LinkList &L, int n){
    106     LinkList p;
    107     ElemType data1;
    108     for (int i = n; i > 0; i--){
    109         p = (LinkList)malloc(sizeof(LNode));
    110         scanf("%d", &data1);    //输入元素值
    111         p->data = data1;
    112         p->next = L->next;    //插入到表头
    113         L->next = p;
    114     }
    115 }
    116 
    117 /****** 归并La和Lb得到新的单链表Lc,Lc的元素也按非递减排列 *****/
    118 void mergeList(LinkList  &La, LinkList  &Lb,  LinkList &Lc){  
    119     LinkList pa, pb, pc;  
    120     pa  = La->next;  
    121     pb  = Lb->next;  
    122     Lc =  pc = La;        //用La的头结点作为Lc的头结点
    123     while (pa && pa) {        //当pa和pb都不为空的时候
    124         if (pa->data > pb->data) {  //当pa的数据域大于pb的数据域的时候
    125             pc->next = pb;            //pc的指针域指向pb
    126             pc = pb;                //将pb赋给pc
    127             pb =pb->next;            //pb后移一个
    128         }else{                        //当pa的数据域小于或等于pb的数据域的时候
    129             pc->next = pa;            //pc的指针域指向pa
    130             pc = pa;                //将pa赋给pc
    131             pa =pa->next;            //pa后移一个
    132         }  
    133     }  
    134     pc->next = pa? pa :pb;            //插入剩余段
    135     free(Lb);                        //释放Lb的头结点
    136 }
    137 
    138 int main(){
    139     //
    140     return 0;
    141 }

     

     

     

     (循环链表和双向链表略)

  • 相关阅读:
    基于Memcached的tomcat集群session共享所用的jar及多个tomcat各种序列化策略配置
    response.getWriter().write()和 response.getWriter().print()的区别
    response.getWriter().write()与out.print()的区别
    跳转到页面后加载一个请求的方法
    【遍历集合】Java遍历List,Map,Vector,Set的几种方法
    Java中通过方法创建一个http连接并请求(服务器间进行通信)
    【tomcat】手动部署动态JavaWeb项目到tomcat
    【Eclipse】Eclipse中修改项目的映射名称与端口
    使用Cookie进行会话管理
    操作系统内核框架图整理
  • 原文地址:https://www.cnblogs.com/ouyang_wsgwz/p/7695713.html
Copyright © 2011-2022 走看看