定义
线性表:零个或多个数据元素的有限序列。
首先,他是一个序列,元素之间是有顺序的,若存在多个元素,**则第一个无前驱,最后一个无后继,其他元素每个元素都有且只有一个前驱和后继。 **然后,线性表强调是有限的,元素的个数是有限的。
线性表元素的个数n(n>-0)定义为线性表的长度,当n=0时,称为空表。
在复杂的线性表中,一个数据元素可以由若干个数据项组成。相同类型的数据。
线性表的抽象数据类型
ADT 线性表(List)
Data
线性表的数据对象集合为{a1,a2,......,an}
,每个元素的类型均为DataType
。其中,除第一个元素a1
外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an
外,每一个元素有且只有一个直接后驱元素,数据元素直接的关系是一一对应的关系。
Operation
InitList(*L)
: 初始化操作,建立一个空的线性表L。
ListEmpty(L)
: 若线性表为空,,返回true,否则返回false。
ClearList(*L)
: 将线性表清空。
GetElem(L,i,*e)
: 将线性表L中的第i个位置元素值返回给e。
…
//此为大话数据结构中的简单例子,可以忽略
void unionL(List *La,List Lb)
{
int La_len,Lb_len,i;
ElemType e; //声明与La和Lb相同的数据元素e
La_len = ListLenght(*La); //求线性表的长度
for (i=1; i<=Lb_len; i++)
{
GetElem(Lb, i, &e); //取Lb中第i个数据元素附给e
if(!LocateElem(*La, e)) //La中不存在和e相同数据元素
ListInsert(La, ++La_len, e); //插入
}
}
顺序存储结构
//结构代码
typedef struct LinkList{
int data[MAXSIZE];
int length;
}list;
//获取元素
int get_elem(list l, int i,int *e){
if (l.length==0 || i<1 || i>l.length)
return 0;
*e=l.data[i-1];
return 1;
}
//插入元素
int list_insert(list* l, int i, int e){
int k;
if (l->length==MAXSIZE)
return 0;
if (i<1 || i>l->length+1)
return 0;
if (i<=l->length){
for (k=l->length;k>=i-1;k--){
l->data[k+1]=l->data[k];
}
}
l->data[i-1]=e;
l->length++;
for (int i = 0; i < l->length; ++i) {
printf("%d",l->data[i]);
}
return 1;
}
//删除元素
int list_delete(list *l, int i, int *e){
int k;
if (l->length==0)
return 0;
if (i<1 || i>l->length)
return 0;
*e=l->data[i-1];
if (i<l->length){
for (k = i; k < l->length; ++k) {
l->data[k-1]=l->data[k];
}
}
l->length--;
for (int i = 0; i < l->length; ++i) {
printf("%d",l->data[i]);
}
return 1;
}
//查找线性表中与e相等的元素
int locate_elem(list l, int e){
if (l.length==0)
return 0;
for (int i=0; i<l.length; ++i){
if (l.data[i]==e)
return i+1;
}
return 0;
}
链式存储结构
链表中的第一个结点的存储位置叫做头指针,有时为了方便操作,会在单链表的第一个结点前附设一个结点。称为头结点。
头结点的数据域可以不存储任何信息。
结点由存放数据元素的数据域和存放后继结点地址的指针域组成。
//线性表的单链表存储结构
typedef struct node{
int data;
struct node* next;
}node;
typedef struct node *linklist; //定义struct node* 的linklist,之后进行修改链表的操作时,直接使用linklist代表struct node*。
//创建链表
linklist * initlink(){
linklist p=(linklist*)malloc(sizeof(linklist)); //头节点p
linklist temp=p; //头指针
for (int i = 0; i < 5; ++i) {
linklist a=(linklist*)malloc(sizeof(linklist));
a->data=i;
a->next=NULL;
temp->next=a;
temp=temp->next;
}
return p;
}
//获取第i个元素
int get_elem(linklist l, int i, int* e){
int j;
linklist p;
p = l->next;
j = 1;
while (p && j<i){
p = p->next;
++j;
}
if (!p || j>i)
return 0;
*e = p->data;
return 1;
}
//插入
int list_insert(linklist l, int i, int e){
int j;
linklist p,s;
p = l;
j = 1;
while (p && j<i){
p = p->next;
++j;
}
if (!p || j>i)
return 0;
s=(linklist)malloc(sizeof(node));
s->data=e;
s->next=p->next;
p->next=s;
return 1;
}
//删除
int list_delete(linklist l, int i, int* e){//如上所说,此处的l可以理解为一个指向实参的指针,所以修改了l的数据,也就是修改了实参的数据
int j=1;
linklist p,q;
p = l;
while (p->next && j<i){ //寻找第i-1个节点
p=p->next;
++j;
}
if (!p->next) //若链表末尾为空,第i个节点不存在
return 0;
q=p->next; //p->next为将删除的结点
p->next=q->next; //将q的后继赋值给p的后继
*e=q->data; //将q结点中的数据给e
free(q); //回收该节点,释放内存
return 1;
}
单链表的整表创建
//单链表的整表创建
//头插法
void create_list_head(linklist l, int n){
linklist p;
int i;
srand(time(0));
l = (linklist)malloc(sizeof(node));
l->next=NULL;
for (int i = 0; i < n; ++i) {
p=(linklist)malloc(sizeof(node));
p->data=rand()%100+1;
p->next=l->next;
l->next=p;
}
}
//尾插法
void create_list_tail(linklist l, int n){
linklist p,r;
int i;
srand(time(0));
l=(linklist)malloc(sizeof(node));
r=l;
for (int i = 0; i < n; ++i) {
p=(node*)malloc(sizeof(node));
p->data = rand()%100+1;
r->next=p;
r=p;
}
r->next=NULL;
}
//删除链表,将链表置空
int clear_list(linklist l){
linklist p,q;
p=l->next;
while (p){
q=p->next;
free(p);
p=q;
}
l->next=NULL;
return 1;
}
单链表结构与顺序存储结构优缺点
存储分配方式
- 顺序存储结构用一段连续的存储单元依次存储线性表的数据元素
- 单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素
时间性能
- 查找:顺序存储结构O(1)、单链表O(n)
- 插入和删除:顺序存储结构需要平均移动表长一半的元素,时间为O(n)、单链表找出某位置的指针后,仅为O(1)
空间性能
- 顺序存储结构需要预分配存储空间,分大了浪费,小了容易溢出
- 单链表不需要分配存储空间,只要有就可以分配,元素个数也不受限制
//这里简单写个main函数调用以上顺序存储结构的函数,链式相同不再重复
#include <stdio.h>
#define MAXSIZE 20
typedef struct LinkList{
int data[MAXSIZE];
int length;
}list;
int get_elem(list l, int i,int *e){
if (l.length==0 || i<1 || i>l.length)
return 0;
*e=l.data[i-1];
return 1;
}
int list_insert(list* l, int i, int e){
int k;
if (l->length==MAXSIZE)
return 0;
if (i<1 || i>l->length+1)
return 0;
if (i<=l->length){
for (k=l->length;k>=i-1;k--){
l->data[k+1]=l->data[k];
}
}
l->data[i-1]=e;
l->length++;
for (int i = 0; i < l->length; ++i) {
printf("%d",l->data[i]);
}
return 1;
}
int list_delete(list *l, int i, int *e){
int k;
if (l->length==0)
return 0;
if (i<1 || i>l->length)
return 0;
*e=l->data[i-1];
if (i<l->length){
for (k = i; k < l->length; ++k) {
l->data[k-1]=l->data[k];
}
}
l->length--;
for (int i = 0; i < l->length; ++i) {
printf("%d",l->data[i]);
}
return 1;
}
int locate_elem(list l, int e){
if (l.length==0)
return 0;
for (int i=0; i<l.length; ++i){
if (l.data[i]==e)
return i+1;
}
return 0;
}
int main() {
//printf("Hello, World!\n");
list l1;
int num,num1;
for (int i=0; i<10; i++){
l1.data[i]=i;
l1.length++;
}
get_elem(l1, 9, &num);
printf("%d\n",num);
list_insert(&l1,5,100);
printf("\n");
list_delete(&l1, 1, &num1);
printf("\n");
printf("%d",locate_elem(l1,1));
return 0;
}