顺序表和链表

1.线性表

具有n个相同的特性的数据元素的有限序列

2.顺序表

2.1概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素。

2. 动态顺序表:使用动态开辟的数组存储。

空间不够则扩容

缺点 :1.空间不够,需要扩容,扩容需要一定的性能消耗,一般扩容2 倍,存在空间浪费

            2.头部或者中间位置插入删除效率低下

改善方案使用链表

3.链表

3.1链表的概念及结构

概念:链表是一种物理存储结构上非连续非顺序的存储结构,数据元素的逻辑顺序是通过链表
中的指针链接次序实现的 。

相较顺序表优点:

1.按需申请释放空间

2.头部或者中间插入删除,不需要挪动数据

在数据结构中

3.2链表的分类

一般使用无头单向非循环链表和带头双向循环链表

 1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结
构的子结构,如哈希桶、图的邻接表等等。 
2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都
是带头双向循环链表。

3.3双向链表的实现

// 2、带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{
LTDataType _data;
struct ListNode* next;
struct ListNode* prev;
}ListNode;
// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* plist);
// 双向链表打印
void ListPrint(ListNode* plist);
// 双向链表尾插
void ListPushBack(ListNode* plist, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* plist);
// 双向链表头插
void ListPushFront(ListNode* plist, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* plist);
// 双向链表查找
ListNode* ListFind(ListNode* plist, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的结点
void ListErase(ListNode* pos);
#include"list.h"

LTNode* BuyListNode(LTDataType x)
{
	LTNode* node = (LTNode*)malloc(sizeof(LTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	node->data = x;
	node->next = NULL;
	node->prev = NULL;
	return node;
}
//void ListInit(LTNode** pphead)//初始化
//{
//	*pphead = BuyListNode(-1);
//	(*pphead)->next = *pphead;
//	(*pphead)->prev = *pphead;
//}
LTNode* ListInit()//初始化
{
	LTNode* phead = BuyListNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}
void ListPrint(LTNode* phead)//打印
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
void ListPushBack(LTNode* phead, LTDataType x)//尾插
{
	assert(phead);

	/*LTNode* newnode = BuyListNode(x);
	LTNode* tail = phead->prev;
	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;*/
	ListInsert(phead, x);

}
void ListPushFront(LTNode* phead, LTDataType x)//头插
{
	assert(phead);
	/*LTNode* newnode = BuyListNode(x);
	LTNode* next = phead->next;
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = next;
	next->prev = newnode;*/
	ListInsert(phead->next, x);
}
void ListPopBack(LTNode* phead)//尾删
{
	assert(phead);
	assert(!ListEmpty(phead));
	/*LTNode* tail = phead->prev;
	LTNode* tailPrev = tail->prev;
	free(tail);
	tailPrev->next = phead;
	phead->prev = tailPrev;*/
	ListErase(phead->prev);
}
void ListPopFront(LTNode* phead, LTDataType x)//头删
{
	assert(phead);
	assert(phead->next != phead);
	ListErase(phead->next,x);
}
bool ListEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}
void ListInsert(LTNode* pos, LTDataType x)//在pos位置插入
{ 
	assert(pos);
	LTNode* prev = pos->prev;
	LTNode* newnode = BuyListNode(x);
	prev->next = newnode;
	newnode->prev = prev;
	newnode->next = pos;
	pos->prev = newnode;
}
void ListErase(LTNode* pos)//删除pos位置的节点
{
	assert(pos);
	LTNode* prev = pos->prev;
	LTNode* next = pos->next;
	prev->next = next;
	next->prev = prev;
	free(pos);
}
int ListSize(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	int size = 0;
	//遍历一遍
	while (cur != phead)
	{
		size++;
		cur = cur->next;
	}
	return size;
}

void ListDestory(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	int size = 0;
	//遍历一遍
	while (cur != phead)
	{
		LTNode* next = cur->next;
		ListErase(cur);
		cur = next;
	}
	free(phead);
	phead = NULL;
}

4.顺序表和链表的区别

不同点    顺序表       链表
存储空间上物理上一定连续 逻辑上连续,但物理上不一定连续
随机访问 支持O(1)   不支持:O(N)
任意位置插入||删除元素可能需要搬移元素,效率低O(N) 只需修改指针指向
插入 动态顺序表,空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问 任意位置插入和删除频繁
缓存利用率  低

顺序表优点:下标随机访问,CPU高速缓存命中率高

           缺点:头部或中间插入删除效率低,扩容有一定程度性能消耗,存在一定程度空间浪                        费

链表优点:任意位置插入删除O(1),按需申请释放空间

       缺点:不支持下标访问

二者相辅相成。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
比较基本的功能 #include <stdio.h> #include <stdlib.h> #include <ctype.h> typedef struct node{ char d; struct node *next; } node; node *findalpha(node *sor) /*提取字母*/ { node *nea; if (sor==NULL) { return NULL; } else if (isalpha(sor->d)) { nea=malloc(sizeof(node)); nea->d=sor->d; nea->next=findalpha(sor->next); } else return findalpha(sor->next); return nea; } node *finddigit(node *sor) /*提取数字*/ { node *nea; if (sor==NULL) { return NULL; } else if (isdigit(sor->d)) { nea=malloc(sizeof(node)); nea->d=sor->d; nea->next=finddigit(sor->next); } else return finddigit(sor->next); return nea; } node *findother(node *sor) /*提取其它字符*/ { node *nea; if (sor==NULL) { return NULL; } else if (!isdigit(sor->d)&&!isalpha(sor->d)) { nea=malloc(sizeof(node)); nea->d=sor->d; nea->next=findother(sor->next); } else return findother(sor->next); return nea; } int main(int argc, char* argv[]) { node *a=NULL,*b,*st,*alpha,*digit,*other; char c; while ((c=getchar())!='\n') /*读取字符并建*/ { if (a==NULL) { a=malloc(sizeof(node)); st=a; a->d=c; } else{ b=malloc(sizeof(node)); b->d=c; a->next=b; a=b; } } a->next =NULL; a=st; puts("\nAll:"); while (a!=NULL) /*输出所有字符*/ { printf("%c",a->d); a=a->next ; } alpha=findalpha(st); digit=finddigit(st); other=findother(st); puts("\n\nLetter:"); while (alpha!=NULL) { printf("%c",alpha->d); alpha=alpha->next ; } puts("\n\nDigit:"); while (digit!=NULL) { printf("%c",digit->d); digit=digit->next ; } puts("\n\nOther:") ; while (other!=NULL) { printf("%c",other->d); other=other->next ; } return 0; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值