天天看点

数据结构——顺序表与链表

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 }      

作者:王陸