单链表以及链表和顺序表的优缺点分析

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.
定义结点和链表
结点定义(1)值(2)next下一个结点的地址
链表的定义定义头
typedef int SListDataType;
// 链表中的一个结点
typedef struct Node {
SListDataType value; // 值
struct Node *next; // 下一个结点的地址
} Node, *NodePointer;

// Single List
typedef struct SList {
Node *first; // *head; 第一个结点的地址
} SList;
初始化和销毁
void SListInit(SList *slist) {
slist->first = NULL;
}
// 头插
void SListPushFront(SList *slist, SListDataType v) {
// 1. 申请新结点
Node *node = (Node *)malloc(sizeof(Node));
node->value = v;
// 更改链表的关系
node->next = slist->first;
slist->first = node;
// 考虑完空链表和非空链表都是一样的处理
}
尾插
void SListPushBack(SList *slist, SListDataType v) {
Node *node = (Node *)malloc(sizeof(Node));
node->value = v;
node->next = NULL;

if (slist->first == NULL) {
	slist->first = node;
}
else {
	// 找原来链表的最后一个结点
	Node *c = slist->first;
	while (c->next != NULL) {
		c = c->next;
	}
	// 循环结束,c->next 一定是 NULL,也就是 c 是最后一个结点
	c->next = node;
}

}
尾删
void SListPopBack(SList *s) {
// 排除掉链表中一个结点都没有的情况
assert(s->first != NULL);

if (s->first->next == NULL) {
	// 只有一个结点
	free(s->first);
	s->first = NULL;
	return;
}

// 找倒数第二个结点
Node *c;
for (c = s->first; c->next->next != NULL; c = c->next);
free(c->next);
c->next = NULL;

}

Node * SListFind(SList *s, SListDataType v) {
for (Node *c = s->first; c != NULL; c = c->next) {
if (c->value == v) {
return c;
}
}

return NULL;

}
找到结点中的某个值
Node * SListFind(SList *s, SListDataType v) {
for (Node *c = s->first; c != NULL; c = c->next) {
if (c->value == v) {
return c;
}
}
return NULL;
}
在中间位置插入一个值
void SListInsertAfter(SList *s, Node *pos, SListDataType v) {
Node *node = (Node *)malloc(sizeof(Node));
node->value = v;
node->next = pos->next;
pos->next = node;
}
删除中间一个结点
void SListEraseAfter(SList *s, Node *pos) {
Node *next = pos->next->next;
free(pos->next);
pos->next = next;
}
移除链表中的一个值
void SListRemove(SList *s, SListDataType v) {
if (s->first == NULL) {
return;
}
if (s->first->value == v) {
Node *second = s->first->next; // 记录原来的第二个结点
free(s->first); // 释放第一个结点空间
s->first = second; // 原来的第二个升级第一个了
}
else {
Node *c = s->first;
while (c->next != NULL) {
if (c->next->value == v) {
Node *next = c->next;
c->next = c->next->next;
free(next);
return;
}
c = c->next;
}
}
}
移除所有该值在链表中的所有的值
void SListRemoveAll(SList *s, SListDataType v) {
if (s->first == NULL) {
return;
}
Node *c = s->first;
while (c->next != NULL) {
if (c->next->value == v) {
Node *next = c->next;
c->next = c->next->next;
free(next);
}
else {
c = c->next;
}
}
// 除了第一个没有检查过
if (s->first->value == v) {
// 头删
Node *first = s->first;
s->first = s->first->next;
free(first);
}
}
链表的代码有两个特点

  1. 要操作某一个结点,往往需要找到这个结点的上一个结点(前驱结点)
  2. 操作链表的第一个结点,往往是特殊情况
    针对第 2 个特点,有个取巧的办法
    在第一个结点前面加一个假的结点
    链表和顺序表的优缺点分析
    链表以节点为单位存储,不支持随机访问任意位置插入删除时间复杂度为O(1) 2.没有增容问题插入一个开辟的新空间
    顺序表:空间连续、支持随机访问1.中间或前面部分的插入删除时间复杂度O(N) 2.增容的代价比较大
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值