顺序表与链表(数据结构的根基)

 

一、顺序表。

  1.定义

顺序表也称线性表,顺序表可以随机访问其存储数据。

2.结构样式(物理)

 

3.顺序表初始化代码

//定义结构体,确定描述顺序表的属性
typedef int SeqTabData;
typedef struct SeqTab
{
	SeqTabData* p;//顺序表起始地址
	int capacity;//顺序表容量
	int size;//顺序表存储已数据个数
}ST;
//初始化顺序表
void SeqTabInit(ST* SeqTab)
{
	SeqTab->p = (SeqTabData*)malloc(sizeof(SeqTabData) * 4);
	SeqTab->capacity = 4;//初始容量
	SeqTab->size = 0;
}

4.实现顺序表增删查改

举指定位置插入数据为例:

//检查是否满容量
int STFullCheck(ST*SeqTab)
{
	if (SeqTab->size == SeqTab->capacity) {
		return 1;
	}
	else {
		return 0;
	}
}
//扩容
void AddCapicity(ST* SeqTab)
{
	SeqTabData* tmp = (SeqTabData*)realloc(SeqTab->p, sizeof(SeqTabData) * SeqTab->capacity *2);
	if (tmp==NULL) {
		printf("增容失败\n");
		
	}
	else {
		printf("增容成功\n");
		SeqTab->p = tmp;
		SeqTab->capacity *= 2;
	}
}
//指定位置插入数据
void SeqTabInsert(ST* SeqTab, int pos, int x)//传参:顺序表起始地址、指定位置下标、放置的数据
{
	assert(pos < SeqTab->size);
    //记录数组最后一个数据的位置  	
    int i = SeqTab->size-1;
    //检查数组是否需要扩容
	int ret = STFullCheck(SeqTab);
    //已满,需要扩容
	if (ret) {
		AddCapicity(SeqTab);
     //将要插入位置后边数据从最后一项开始,向后挪动1个单位直至i=pos   
		for (;i <= pos;i--) {
			SeqTab->p[i + 1] = SeqTab->p[i];
		}
		SeqTab->p[pos] = x;
     //数据个数+1  
		SeqTab->size++;
	}
    //未满,不需要扩容,数据挪动如上
	else {
		for (;i >= pos;i--) {
			SeqTab->p[i + 1] = SeqTab->p[i];
		}
		SeqTab->p[pos] = x;
		SeqTab->size++;
	}
}

总结方法:通过正确挪动数据,改变顺序表数据的相对位置,切记从何处数据开始挪动!

二、链表

1.定义

链表是一种物理存储单元非连续、非顺序存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

2.逻辑结构

3.链表的不同结构

1. 单向、双向
2. 带头、不带头
3. 循环、非循环

 

 

 

现主要讨论单向链表、带头双向循环链表!

4、链表初始化代码、增删查改代码思路

//单向链表基本属性
typedef int SLIST_TYPE;
typedef struct SignalList
{
	struct SignalList* Next;//下一个节点的地址
	SLIST_TYPE Data;//存储数据
}SLTNode;
//指定位置后部插入
void SLTPushAfter(SLTNode** pphead,SLTNode* pos, int x)
{
    //创建新节点
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	newnode->Data = x;
	newnode->Next = NULL;
    //判断是否头节点处尾插
	if ((*pphead)==pos) {
		newnode->Next = (*pphead)->Next;
		(*pphead)->Next= newnode;
	}
	else {
         //从头节点处开始判断是否此节点为pos  
		SLTNode* previous = *pphead;
		while (previous!= pos) {
            //迭代
			previous = previous->Next;
		}
         //插入
		newnode->Next = previous->Next;
		previous->Next = newnode;
	}
}

单向链表总结:总体而言,单向链表增删查改主要需要通过遍历整个链表,找到指定位置进行新节点的链接,切记前后指针地址的赋值顺序!防止出现找不到参与链接节点的地址!

带头双向循环链表
//基本属性
typedef int ListType;
typedef struct DoubleCirList
{
	struct DoubleCirList* pre;前一个结点地址
	ListType Data;存储数据
	struct DoubleCirList* Next;后一个地址结点

}DCList;
//创建新节点
DCList* BuyDCList(ListType x)
{
	DCList* newnode = (DCList*)malloc(sizeof(DCList));
	newnode->Data = x;
	newnode->pre =NULL;
	newnode->Next = NULL;
	return newnode;
}
//初始化哨兵节点
DCList* Initinfo()
{
	DCList* phead = (DCList*)malloc(sizeof(DCList));
	phead->Data = NULL;
	phead->pre = phead;
	phead->Next = phead;
	return phead;
}
//指定位置前方插入
void DCListInsertBefore(DCList* pos, ListType x)
{
	DCList* newnode = BuyDCList(x);
	DCList* pre = pos->pre;//先保存前一个结点,后续方便找到
	newnode->pre = pre;
	newnode->Next = pos;
	pos->pre = newnode;
	pre->Next = newnode;
}

总结:相较于单向链表,带头双向循环链表不需要遍历便可以实现数据的增删查改!同样要记住地址的赋值顺序!

三、顺序表与链表的优缺点

顺序表:
优点:
空间连续、支持随机访问
缺点:
1. 中间或前面部分的插入删除时间复杂度O(N)
2. 增容的代价比较大。
链表:
缺点:
以节点为单位存储,不支持随机访问,时间复杂度为O(N)
优点:
1. 任意位置插入删除时间复杂度为O(1)
2. 没有增容消耗,按需申请节点空间,不用了直接释放。
总之两者互补!

四、小结

  两者都为基本数据结构,用于存储数据。二者优缺点互补。打好顺序表链表基础,对以后复杂数据结构的实现有着举足轻重的作用!

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值