【数据结构】顺序表与链表

线性表的两种实现方式

线性表是由同类型数据元素构成的有序序列的线性结构。
包含的基本操作主要有:初始化、查找、插入、删除。
两种实现方式:顺序表和链表,在实现基本操作时各自的关键点如下。

顺序表

利用数组的连续存储空间顺序存放线性表的个元素。
由此说明顺序表的元素都是一个一个挨在一起的,那么如果操作是在当前数组元素序列外插入元素,例如与数组最后一个元素隔几个再插入,这是不允许的,所以其删除给出的位置也不会超过表长。

定义顺序表结构体: 需要MAXSIZE大小的数组——存放数据 需要指示数组最后一个数据位置的标志——判断插入、删除位置是否合法,以及空满。 表有两种使用方式:结构体变量、结构体指针。

#define MAXSIZE 10
template <typename ElementType>

typedef int Position;
typedef struct LNode *List;

struct LNode{
	ElementType data[MAXSIZE];
	Position last;
};

初始化: 结构体变量 struct LNode L; 使用方式:L.data[i] = 10;L.last = 10; 结构体指针如下,使用方式L->data[i] = 10;
~
将L->last赋值为-1,表示此时没有元素,同时需要注意表的长度为L->last+1。

List MakeEmpty()
{
	List L = (List)malloc(sizeof(struct LNode));
	L->last = -1;
	return L;
}

查找: 根据给出的元素值返回元素所在位置。 对于顺序表来说,给出数组元素索引,可以直接得到元素值,操作简单。 遍历数组,与 x
比较,相等即返回元素位置,否则返回error。

#define ERROR -1;
Position Find(List L,ElementType x)
{
	Position i = 0;
	for(;i<=L->last;i++)
	{
		if(L->data[i]==x)
		{
			return i;
		}
	}
	return ERROR;	
}

插入: 在给出的位置上插入一个元素,并返回插入操作结果(bool)。
~
首先,插入位置是在哪?为什么这么问,是因为如果给出的位置是 “-1” 呢?(这里的实现是数组索引从0开始)或者超出表长呢?(表长是last+1,就是在表最后一个元素后面插入一个元素)这都是不可以的,需要判断
~
对于顺序表的插入,在插入之前需要将给定位置腾出来,所以需要将给定位置后面的元素都向后移一位,这里就有个疑问了——还有位置给我腾吗?需要判断是否满
~
方法:last++增加一个位置,从后往前一个一个移,直到下一个位置是给定位置,直接赋值。


bool insert(List L,ElementType x,Position p)
{
	if(L->last == MAXSIZE)
	{
		cout<<"表满"<<endl;
		return false; 
	}
	if(p<0||p>L->last+1)
	{
		cout<<"不能插入在该位置"<<endl;
		return false; 
	}
	L->last++;
	Position i = L->last;
	for(;i>p;i--)
	{
		L->data[i] = L->data[i-1];
	}
	L->data[i] = x;
	return true;	
}

删除: 删除给定位置的元素,并返回操作结果(bool)
~
表中是否有元素可以被删除?即判断表是否为空。
~
删除位置是否已经存储数据?即给定位置要在[0,last]范围中。
~
方法:从给定位置开始,将其后面的元素一个一个往前移,最后last–,实时更新表长度。

bool delete(List L,Position p)
{
	if(L->last == -1)
	{
		cout<<"表空"<<endl;
		return false;
	}
	if(p<0||p>L->last)
	{
		cout<<"该位置不存在元素"<<endl;
		return false; 
	}
	Position i = p;
	for(;i<L->last;i++)
	{
		L->data[i] = L->data[i+1];
	}
	L->last--;
	return true;
 } 

链表

不要求逻辑上相邻的两个元素物理上也相邻。通过“链”建立起数据元素之间的逻辑关系。因此插入、删除不需要移动数据元素,只需要修改“链”。

定义链结构体: 其实就是定义每个结点的结构,包括存储的数据和指向下个结点或NULL的“链”。

typedef struct LNode *PtrtoLNode;

template <typename E>

typedef PtrtoLNode List;

struct LNode{
	E data;
	List next;
};

初始化: 根据传入的值定义头结点,头结点指向NULL。

List MakeEmpty(E x)
{
	List L = (List)malloc(sizeof(struct LNode));
	L->data = x;
	L->next = NULL;
	return L;
}

查找:

  1. 根据给出的元素值返回存储该元素的结点。
  2. 根据给出的序号返回该位置的结点。
    ~
    对于链表来说,查找是很不方便的,无论哪种查找方式,都需要遍历、比较来获取最后的结果。
#define ERROR NULL

//给出元素值
List Find(List L,E x)
{
/*直接赋值时,不需要申请空间 */
//	List p = (List)malloc(sizeof(List)); //需要释放空间吗?要如何释放呢?
//	p = L;
	List p = L; 
	while(p&&p->data!=x)
	{
		p = p->next;
	}
	return p;
}

//给出序号
List FindByIndex(List L,int x)
{
	List p = L;
	int i = 1;
	while(i<x&&p)
	{
		p = p->next;
		i++;
	}
	return p;
}

插入: 在给出的位置插入一个结点,并返回头结点。
~
因为可能在表头插入,那么会改变头结点,所以为了避免失去头结点而无法获取其他节点,需要返回头结点(无论是否修改)。

List Insert(List L,E x,int i)
{
	if(i==1)	//表头插入
	{
		List k = (List)malloc(sizeof(struct LNode));
		k->data = x;
		k->next = L;
		return k;
	} 
	else
	{
		List p = FindByIndex(L,i-1);
		if(p == NULL)
		{
			cout<<"插入位置参数有误"<<endl;
		}
		else
		{
			List k = (List)malloc(sizeof(struct LNode));
			k->data = x;
			k->next = p->next;
			p->next = k;
		}
		return L; 
	}
}

删除: 删除给定位置的元素,并返回头结点
~
当头结点为空时,直接返回NULL。
~
同样可能删除头结点,所以要返回头结点。
~
链表的删除核心操作是需要将位置 i-1 的结点的“链”修改正确,并释放位置 i 的结点的空间。尤其要注意结点(i-1)和结点(i)为NULL的情况。

List Delete(List L,int i)
{
	if(L == NULL) return NULL;
	if(i == 1)	//删除头结点 
	{
		List S = L;
		L = L->next;
		free(S);
	}
	else
	{
		List p = FindByIndex(L,i-1);
		if( p == NULL || p->next == NULL )
		{
			cout<<"删除结点不存在"<<endl;
		}
		else
		{
			List s = p->next;
			p->next = s->next;
			free(s);
		}
	}
	return L;
}

表长: 直接遍历即可

int Length(List L)
{
	int len = 0;
	List p = L;
	while(p)
	{
		len++;
		L = L->next;
	}
	return len;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值