线性表(顺序表和链表)

线性表

线性表L可用二元组形式描述:

L = ( D , R ) L= (D,R) L=(D,R)

即线性表L包含数据元素集合D和关系集合R

D = a i ∣ a i ∈ d a t a t y p e , i = 0 , 1 , 2 , ∙ ∙ ∙ ∙ ∙ ∙ ∙ ∙ ∙ n − 1 , n ≥ 0 D={ai | ai∈datatype ,i=0,1,2, ∙∙∙∙∙∙∙∙∙n-1 ,n≥0} D=aiaidatatype,i=0,1,2,n1,n0

R = < a i , a i + 1 > ∣ a i , a i + 1 ∈ D , 0 ≤ i ≤ n − 2 R={<ai , ai+1> | ai , ai+1∈D, 0≤i≤n-2} R=<ai,ai+1>ai,ai+1D,0in2

​ 关系符<ai, ai+1>在这里称为有序对

​ 表示任意相邻的两个元素之间的一种先后次序关系

​ ai是ai+1的直接前驱, ai+1是ai的直接后继

线性表的特征

  • 对非空表,a0是表头,无前驱
  • an-1是表尾,无后继
  • 其它的每个元素ai有且仅有一个直接前驱ai-1和一个直接后继ai+1

线性表顺序存储(顺序表

顺序存储结构的表示

​ 若将线性表 L = ( a 0 , a 1 , … … , a n − 1 ) L=(a0,a1, ……,an-1) L=(a0,a1,……,an1)中的各元素依次存储于计算机一片连续的存储空间。

L o c ( a i ) Loc(ai) Loc(ai) a i ai ai的地址, L o c ( a 0 ) = b Loc(a0)=b Loc(a0)=b,每个元素占d个单元 则: L o c ( a i ) = b + i ∗ d Loc(ai)=b+i*d Loc(ai)=b+id

顺序存储结构的特点

  • 逻辑上相邻的元素 ai, ai+1,其存储位置也是相邻的
  • 对数据元素ai的存取为随机存取或按地址存取
  • 存储密度高
  • 存储密度D=(数据结构中元素所占存储空间)/(整个数据结构所占空间)

顺序存储结构的不足

  • 对表的插入和删除等运算的时间复杂度较差

顺序表的构建(C语言)

在C语言中,可借助于一维数组类型来描述线性表的顺序存储结构

顺序表结构体
typedef struct {
	data_t data[N];
	int last;
}sqlist, *sqlink;
创建顺序表
sqlink list_create() {
	//malloc
	sqlink L;

    L =(sqlink)malloc(sizeof(sqlist));
    if (L == NULL) {
        printf("list malloc failed\n");
        return L;
    }

    //initialize
    memset(L, 0, sizeof(sqlist));
    L->last = -1;

    //return
    return L;
}
清空顺序表
/*
 * @ret   0-success   -1-failed
 * */
   int list_clear(sqlink L) {
   if (L == NULL)
   	return -1;

   memset(L, 0, sizeof(sqlist));
   L->last = -1;

   return 0;
   }
删除顺序表
int list_delete(sqlink L){
	if (L == NULL) 
		return -1;
	free(L);
	L = NULL;
	return 0;
}
判断顺序表是否为空
/*
 * list_empty: Is list empty?
 * para L: list
 * @ret  1--empty   0--not empty
 * */
   int list_empty(sqlink L) {
   if (L->last == -1) 
   	return 1;
   else 
   	return 0;
   }
顺序表的长度
int list_length(sqlink L) {
	if (L == NULL) 
		return -1;
	return (L->last+1);
}
确定某个值的位置
int list_locate(sqlink L, data_t value) {
	int i ;
	for (i = 0; i <= L->last; i++) {
		if (L->data[i] == value) 
			return i;
	}
	return -1;
}
插入操作
int list_insert(sqlink L, data_t value, int pos) {
	int i;

//full
if (L->last == N-1) {
	printf("list is full\n");
	return -1;
}

//check para    0<=pos<=Last+1   [0, last+1]
if (pos < 0 || pos > L->last+1) {
	printf("Pos is invalid\n");
	return -1;
}

//move
for (i = L->last; i >= pos; i--) {
	L->data[i+1] = L->data[i];
}

//update value last
L->data[pos] = value;
L->last++;

return 0;
}
删除操作
int list_delete(sqlink L, int pos) {
	int i;

if (L->last == -1) {
	printf("list is empty\n");
	return -1;
}

//pos [0, last]
if (pos < 0 || pos > L->last) {
	printf("delete pos is invalid\n");
	return -1;
}

//move  [pos+1, last]
for (i = pos+1; i <= L->last; i++) {
	L->data[i-1] = L->data[i];
}

//update
L->last--;

return 0;
}
展示顺序表
int list_show(sqlink L) {
	int i;

if (L == NULL) 
	return -1;
if (L->last == -1)
	printf("list is empty\n");

for (i = 0; i <= L->last; i++) {
	printf("%d ", L->data[i]);
}
puts("");

return 0;
}
合并顺序表
int list_merge(sqlink L1, sqlink L2) {
	int i = 0;
	int ret;

while (i <= L2->last){
	ret = list_locate(L1, L2->data[i]);
	if (ret == -1) {
		if (list_insert(L1, L2->data[i], L1->last+1) == -1) 
			return -1;
	}
	i++;
}
return 0;
}

线性表链式存储(单链表

链式存储结构的表示

  • 将线性表 L = ( a 0 , a 1 , … … , a n − 1 ) L=(a0,a1,……,an-1) L=(a0,a1,……,an1)中各元素分布在存储器的不同存储块,称为结点,通过地址或指针建立元素之间的联系

image-20221017213737208

  • ​ 结点的data域存放数据元素ai,而next域是一个指针,指向ai的直接后继ai+1所在的结点。

image-20221017213744004

结点类型描述

   typedef  struct node
       
   {  
       data_t  data;  //结点的数据域//
       struct node *next; //结点的后继指针域//

   }listnode, *linklist;
可调用C语言中== m a l l o c ( ) malloc() malloc()函数==向系统申请结点的存储空间
      linklist p; 
      p = (linklist)malloc(sizeof(listnode));
    //创建一个类型为linklist的结点,且该结点的地址已存入指针变量p中:

单链表的优缺点

优点

  1. 是动态数据结构,可随时是链表分配和取消内存来增长或者缩短链表,不用给链表初始化大小
  2. 插入和删除操作简单,不必移动元素

缺点

  1. 遍历链表会比较麻烦,不能用索引的方式

链表的构建(C语言)

创建链表

linklist list_create() {
	linklist H;

    H = (linklist)malloc(sizeof(listnode));
    if (H == NULL) {
        printf("malloc failed\n");
        return H;
    }

    H->data = 0;
    H->next = NULL;

    return H;
}

链表尾部插入

int list_tail_insert(linklist H, data_t value) {
	linklist p;
	linklist q;

if (H == NULL) {
	printf("H is NULL\n");
	return -1;
}

//1 new node p
if ((p = (linklist)malloc(sizeof(listnode))) == NULL) {
	printf("malloc failed\n");
	return -1;
}
p->data = value;
p->next = NULL;

//2 locate tail node 
q = H;
while (q->next != NULL) {
	q = q->next;
}

//3 insert
q->next = p;

return 0;
}

获得链表第pos个节点

int list_tail_insert(linklist H, data_t value) {
	linklist p;
	linklist q;

if (H == NULL) {
	printf("H is NULL\n");
	return -1;
}

//1 new node p
if ((p = (linklist)malloc(sizeof(listnode))) == NULL) {
	printf("malloc failed\n");
	return -1;
}
p->data = value;
p->next = NULL;

//2 locate tail node 
q = H;
while (q->next != NULL) {
	q = q->next;
}

//3 insert
q->next = p;

return 0;

}

指定位置插入

int list_insert(linklist H, data_t value, int pos) {
	linklist p;
	linklist q;

if (H == NULL) {
	printf("H is NULL\n");
	return -1;
}

//1 locate node p (pos-1)
p = list_get(H, pos-1);
if (p == NULL) {
	return -1;
}

//2 new node q
if ((q = (linklist)malloc(sizeof(listnode))) == NULL) {
	printf("malloc failed\n");
	return -1;
}
q->data = value;
q->next = NULL;

//3 insert
q->next = p->next;
p->next = q;

return 0;
}

删除指定位置节点

int list_delete(linklist H, int pos) {
	linklist p;
	linklist q;

//1
if (H == NULL) {
	printf("H is NULL\n");
	return -1;
}

//2 locate prior
p = list_get(H, pos-1);
if (p == NULL) 
	return -1;
if (p->next == NULL) {
	printf("delete pos is invalid\n");
	return -1;
}

//3 update list
q = p->next;
p->next = q->next;//p->next = p->next->next;

//4 free
printf("free:%d\n", q->data);
free(q);
q = NULL;

return 0;
}

展示链表

int list_show(linklist H) {
	linklist p;

if (H == NULL) {
	printf("H is NULL\n");
	return -1;
}

p = H;

while (p->next != NULL) {
	printf("%d ", p->next->data);
	p = p->next;
}
puts("");

return 0;

}

删除链表

linklist list_free(linklist H) {
	linklist p;

if (H == NULL) 
	return NULL;

p = H;

printf("free:");
while (H != NULL) {
	p = H;
	printf("%d ", p->data);
	free(p);
	H = H->next;
}
puts("");

return NULL;

}

逆转链表

int list_reverse(linklist H) {
	linklist p;
	linklist q;

if (H == NULL) {
	printf("H is NULL\n");
	return -1;
}

if (H->next == NULL || H->next->next == NULL) {
	return 0;
}

p = H->next->next;
H->next->next = NULL;

while (p != NULL) {
	q = p;
	p = p->next;

​	q->next = H->next;
​	H->next = q;
}

return 0;

}

合并链表

int list_merge(linklist H1, linklist H2) {
	linklist p, q, r;

if (H1 == NULL || H2 == NULL) {
	printf("H1 || H2 is NULL\n");
	return -1;
}

p = H1->next;
q = H2->next;
r = H1;
H1->next = NULL;
H2->next = NULL;

while (p && q) {
	if (p->data <= q->data) {
		r->next = p;
		p = p->next;
		r = r->next;
		r->next = NULL;
	} else {
		r ->next = q;
		q = q->next;
		r = r->next;
		r->next = NULL;
	}
}

if (p == NULL) {
	r->next = q;
}else {
	r->next = p;
}

return 0;

}

xt;
​ H->next = q;
}

return 0;

}


### 合并链表

```c
int list_merge(linklist H1, linklist H2) {
	linklist p, q, r;

if (H1 == NULL || H2 == NULL) {
	printf("H1 || H2 is NULL\n");
	return -1;
}

p = H1->next;
q = H2->next;
r = H1;
H1->next = NULL;
H2->next = NULL;

while (p && q) {
	if (p->data <= q->data) {
		r->next = p;
		p = p->next;
		r = r->next;
		r->next = NULL;
	} else {
		r ->next = q;
		q = q->next;
		r = r->next;
		r->next = NULL;
	}
}

if (p == NULL) {
	r->next = q;
}else {
	r->next = p;
}

return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深センのHZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值