线性表

首先,线性表是一种最简单的一种数据结构。嗯,简单的说,一个线性表是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 }

 

 

 

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

posted @ 2017-10-19 21:57  ouyang_wsgwz  阅读(479)  评论(0编辑  收藏  举报