1.顺序表
我在学习完顺序表后一直对顺序表、数组、结构体数组这几个概念存在一些疑问,这里给出一些分析和看法。
顺序表:在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构。
数组:把具有相同数据类型的若干变量按有序的形式组织起来,以便于程序处理,这些数据元素的集合就是数组。
从顺序表的定义来看,它和数组确实有很大的联系。首先,它是以数组的形式来保存的,其次,它和数组一样都是存储的元素物理地址相邻,具有很大的相似性。
但,仔细研究还是会发现它们的不同之处:
typedef struct Sqlist
{
ElemType *slist; /*存储空间的基地址,动态分配的一维数组*/
int length; /*顺序表的当前长度*/
int listsize; /*当前分配的存储空间*/
} Sqlist;
顺序表是通过结构体来定义的,在结构体中有一个数组来保存顺序表所存储的数据,然后用定义的整形变量来确定数组中存储的有效数据的个数。而数组直接定义,简洁明了,很容易使用。这样看来数组比顺序表更加方便使用了。但是,数组也有它的缺陷它不能进行增,删等操作,而这些对顺序表来说就很简单了。
1 #include<stdio.h>
2 #include<malloc.h>
3 #define ERROR 0
4 #define OK 1
5 #define INIT_SIZE 5 /*初始分配的顺序表长度*/
6 #define INCREM 5 /*溢出时,顺序表长度的增量*/
7 typedef int ElemType; /*定义表元素的类型*/
8 typedef struct Sqlist
9 {
10 ElemType *slist; /*存储空间的基地址*/
11 int length; /*顺序表的当前长度*/
12 int listsize; /*当前分配的存储空间*/
13 } Sqlist;
14
15 int InitList_sq(Sqlist *L); /*线性表的初始化*/
16 int CreateList_sq(Sqlist *L,int n); /* 构造一个长度为n顺序表 */
17 int ListInsert_sq(Sqlist *L,int i,ElemType e);/*在表的第i个位置前插入一个元素e */
18 int PrintList_sq(Sqlist *L); /*输出顺序表的元素*/
19 int ListDelete_sq(Sqlist *L,int i); /*删除第i个元素*/
20 int ListLocate(Sqlist *L,ElemType e); /*查找值为e的元素*/
21
22 int InitList_sq(Sqlist *L)
23 {
24 L->slist=(ElemType*)malloc(INIT_SIZE*sizeof(ElemType));
25 if(!L->slist)
26 {
27 return ERROR;
28 }
29 L->length=0;///空表的长度为0
30 L->listsize=INIT_SIZE;///初始存储容量
31 return OK;
32 }/*InitList*/
33
34 int CreateList_sq(Sqlist *L,int n)
35 {
36 ElemType e;
37 int i;
38 for(i=0; i<n; i++)
39 {
40 printf("input data %d",i+1);
41 scanf("%d",&e);
42 if(!ListInsert_sq(L,i+1,e))
43 {
44 return ERROR;
45 }
46 }
47 return OK;
48 }/*CreateList*/
49
50 /*输出顺序表中的元素*/
51 int PrintList_sq(Sqlist *L)
52 {
53 int i;
54 for(i=1; i<=L->length; i++)
55 {
56 printf("%5d",L->slist[i-1]);
57 }
58 return OK;
59 }/*PrintList*/
60
61 int ListInsert_sq(Sqlist *L,int i,ElemType e)
62 {
63 int k;
64 if(i<1||i>L->length+1)///i值不合法
65 {
66 return ERROR;
67 }
68 if(L->length>=L->listsize)///当前存储空间已满,增加分配
69 {
70 L->slist=(ElemType*)realloc(L->slist,(INIT_SIZE+INCREM)*sizeof(ElemType));
71 if(!L->slist)
72 {
73 return ERROR;
74 }
75 L->listsize+=INCREM;
76 }
77 for(k=L->length-1; k>=i-1; k--)///元素后移
78 {
79 L->slist[k+1]= L->slist[k];
80 }
81 L->slist[i-1]=e;///在第i个位置上插入元素e
82 L->length++;///表长加1
83 return OK;
84 }/*ListInsert*/
85
86 /*在顺序表中删除第i个元素*/
87 int ListDelete_sq(Sqlist *L,int i)
88 {
89 int p;
90 if(i<1||i>L->length)///i值不合法
91 {
92 return ERROR;
93 }
94 for(p=i-1; p<L->length-1; p++)///元素后移
95 {
96 L->slist[p]=L->slist[p+1];
97 }
98 L->length--;///表长减1
99 return OK;
100 }
101 /*在顺序表中查找指定值元素,返回其序号*/
102 int ListLocate(Sqlist *L,ElemType e)
103 {
104 int i;
105 i=0;
106 while((i<=L->length)&&(L->slist[i]!=e))
107 {
108 i++;
109 }
110 if(i<=L->length)
111 {
112 return i+1;
113 }
114 else
115 {
116 return -1;
117 }
118 }
119
120 int main()
121 {
122 Sqlist sl;
123 int n,m,k;
124 printf("please input n:"); /*输入顺序表的元素个数*/
125 scanf("%d",&n);
126 if(n>0)
127 {
128 printf("\n1-Create Sqlist:\n");
129 InitList_sq(&sl);
130 CreateList_sq(&sl,n);
131 printf("\n2-Print Sqlist:\n");
132 PrintList_sq(&sl);
133 printf("\nplease input insert location and data:(location,data)\n");
134 scanf("%d,%d",&m,&k);
135 ListInsert_sq(&sl,m,k);
136 printf("\n3-Print Sqlist:\n");
137 PrintList_sq(&sl);
138 printf("\n");
139 }
140 else
141 printf("ERROR");
142 return 0;
143 }
2.链表
顺序表在使用的时候有以下两个主要的缺点:
(1)插入和删除运算的时候必须移动大量(几乎一半)数据元素,效率低下。
(2)必须预先分配存储空间,造成空间利用率低,而且表的容量很难扩充。
为了克服顺序表的缺点,可以使用动态存储分配来存储线性表,也就是链式存储结构。
typedef struct LNode /*线性表的单链表存储*/
{
ElemType data;///数据域
struct LNode *next;///指针域
} LNode,*LinkList;
在单链表中任何两个元素的存储位置之间没有固定的联系,每个元素的存储位置都包含在其直接前驱结点的信息中。
1 #include<stdio.h>
2 #include<malloc.h>
3 #define ERROR 0
4 #define OK 1
5 typedef int ElemType; /*定义表元素的类型*/
6 typedef struct LNode /*线性表的单链表存储*/
7 {
8 ElemType data;///数据域
9 struct LNode *next;///指针域
10 } LNode,*LinkList;
11
12 LinkList CreateList(int n); /*构造长度为n的链表*/
13 void PrintList(LinkList L); /*输出带头结点单链表的所有元素*/
14 int GetElem(LinkList L,int i,ElemType *e); /* 在第i个元素存在的情况下,替换为e*/
15
16 LinkList CreateList(int n)
17 {
18 LNode *p,*q,*head;
19 int i;
20 head=(LinkList)malloc(sizeof(LNode));
21 head->next=NULL;///头结点
22 p=head;
23 for(i=0; i<n; i++)
24 {
25 q=(LinkList)malloc(sizeof(LNode));
26 printf("input data %i:",i+1);
27 scanf("%d",&q->data); /*输入元素值*/
28 q->next=NULL; /*结点指针域置空*/
29 p->next=q; /*新结点连在表末尾*/
30 p=q;
31 }
32 return head;
33 }/*CreateList*/
34
35 void PrintList(LinkList L)///输出链表存储内容
36 {
37 LNode *p;
38 p=L->next; /*p指向单链表的第1个元素*/
39 while(p!=NULL)
40 {
41 printf("%5d",p->data);
42 p=p->next;
43 }
44 }/*PrintList*/
45
46 int GetElem(LinkList L,int i,ElemType *e)///获取链表第i位置上的元素
47 {
48 LNode *p;
49 int j=1;
50 p=L->next;///指向第一个节点
51 while(p&&j<i)///向后查找,直到p指向第i个元素或者p为空
52 {
53 p=p->next;
54 j++;
55 }
56 if(!p||j>i)///第i个元素不存在
57 {
58 return ERROR;
59 }
60 *e=p->data;///获取到第i个元素
61 return OK;
62 }/*GetElem*/
63
64 int ListInsert_sq(LinkList L,int i,ElemType e)///向链表中第i个位置前插入元素
65 {
66 int j=0;
67 LinkList p=L,s;
68 while(p&&j<i-1)///向后查找寻找第i-1个元素
69 {
70 p=p->next;
71 j++;
72 }
73 if(!p||j>i-1)
74 {
75 return ERROR;
76 }
77 s=(LinkList)malloc(sizeof(struct LNode));///生成新结点
78 s->data=e;///插入
79 s->next=p->next;
80 p->next=s;
81 return OK;
82 }
83 int ListDelete(LinkList L,int i,ElemType *e)///删除链表第i个位置上的元素,并由e返回其值
84 {
85 int j=0;
86 LinkList p=L,q;///p初始化时指向头结点
87 while(p->next&&j<i-1)///向后寻找第i个结点,并令p指向其前驱
88 {
89 p=p->next;
90 j++;
91 }
92 if(!(p->next)||j>i-1)
93 {
94 return ERROR;
95 }
96 q=p->next;///q指向被删除结点
97 p->next=q->next;
98 *e=q->data;
99 free(q);
100 return OK;
101 }
102 int main()
103 {
104 int n,i;
105 ElemType e;
106 LinkList L=NULL; /*定义指向单链表的指针*/
107 printf("please input n:"); /*输入单链表的元素个数*/
108 scanf("%d",&n);
109 if(n>0)
110 {
111 printf("\n1-Create LinkList:\n");
112 L=CreateList(n);
113 printf("\n2-Print LinkList:\n");
114 PrintList(L);
115 printf("\n3-GetElem from LinkList:\n");
116 printf("input i=");
117 scanf("%d",&i);
118 if(GetElem(L,i,&e))
119 printf("No%i is %d",i,e);
120 else
121 printf("not exists");
122 }
123 else
124 printf("ERROR");
125 return 0;
126 }
作者:王陸