数据结构学习笔记 (二)

线性表的链式表示和实现

单链表

链式结构的特点是用一组任意的存储元素来存储线性表的元素,在内存中可以是连续的也可以是不连续的。对于单链表来说,存储数据元素除了本身信息外(数据域),还要存储指示其直接后续的信息(指针域)。

struct Node
{
	int data;
	Node *next;
};
class LinkList
{
	Node *head;

public:
	LinkList(){ head = new Node; head->next = NULL; };
	~LinkList(){ delete head; };
	void Create(int n);			//创建长度为n的单链表
	int GetElem(int i);			//获取第i个元素
	int Locate(int e);			//返回第一个与e匹配的元素位序
	bool IsEmpty(){ return (head->next == NULL); }//判断是否为空表
	int Prior(int e);			//e的前驱
	int Next(int e);			//e的后续
	void Insert(int x, int i);	//将x插入到i位置
	int Delete(int i);			//删除表中第i个元素
	void Clear();				//清空
	void Print();				//输出
};

结构体Node用来表示链表的每一个元素分别是数据域和它的指针域;

取元素
int LinkList::GetElem(int i){
	Node *p;
	int k, j;
	if (head->next == NULL)
	{
		cout << "表为空" << endl;
		exit(0);
	}
	else
	{
		p = head;
		k = 0;
		while (p && k<i)
		{
			p = p->next;
			k++;
		}
		if (!p||k>i)
		{
			cout << "第" << i << "个元素不存在" << endl;
			exit(0);

		}
		return(p->data);
	}
}

时间复杂度O(n);


插入操作
void LinkList::Insert(int x, int i){
	Node *p = head;
	int k = 0;
	while (p && k<i-1)
	{
		p = p->next;
		k++;
	}
	if (!p||k>i-1)
	{
		cout << "第" << i - 1 << "个元素不存在" << endl;
		exit(0);
	}
	Node *s = new Node;
	if (!s)
	{
		cout << "空间分配失败" << endl;
		exit(0);
	}
	s->data = x;
	s->next = p->next;
	p->next = s;

}

插入操作需要从链表的第一个节点开始根据后续的指针找到插入位置的前一个节点,然后把这个节点的后续指针指向新插入的节点,新插入的节点的后续指针则指向之前这个位置的节点。

删除操作
int LinkList::Delete(int i){
	Node *p = head;
	int k = 0;
	while (p&&k<i-1)
	{
		p = p->next;
		k++;
	}
	if (!p||p->next==NULL)
	{
		cout << "删除位置非法" << endl;
		exit(0);
	}
	Node *q = p->next;		//暂存删除节点
	p->next = q->next;		//删除
	int e = q->data;
	delete q;
	return e;

}

删除操作也需要从第一个节点开始直到找到第i-1个节点,然后把i-1位置节点的后续指向i+1位置的节点,然后把第i位置的节点在内存中清除才能完成删除操作。

建立单链表
void LinkList::Create(int n){
	Node *p;
	for (int i = 0; i < n; i++)
	{
		p = new Node;
		cin >> p->data;
		p->next = head->next;
		head->next == p;
	}
}

双向链表

双向链表与单链表相比,最大的不同就是双向链表的元素不仅有数据和后续指针,它还有前驱的指针。通过一个节点不仅可以向前查找,也可以向后查找。

struct DNode
{
	int data;
	DNode *prior;		//前驱指针
	DNode *next;		//后续指针
};
class DBList
{
	DNode *head;

public:
	DBList(){ head = new DNode; head->next = NULL; head->prior == NULL; };
	~DBList();
	void Create(int n);		//创建长度为n的双链表
	int GetElem(int i);		//取表中第i个元素
	DNode Locate(int e);	//返回第一个与e匹配的节点指针
	bool IsEmpty();
	void Insert(int x, int i);
	int Delete(int i);
	void Clear();
};

在双链表中,有些操作如取元素,求表长,定位等,只涉及一个方向的指针,则这些操作的算法描述和单链表相同。但在进行插入,删除操作时有很大的不同,在双链表中需同时修改两个方向上的指针,还要小心修改顺序。

双链表的节点删除操作
p -> prior -> next = p -> next;
if(!p->next)
p -> next -> prior = p -> prior;

双链表的节点插入操作
s = new DNode;
s -> data = e;
s -> prior = p -> prior;
p -> prior = next = s;
p -> prior = s;
s -> next = p;

循环链表

循环链表是线性链表的一种变形,一般的链表结构最后一个节点的指针域为空,表示链表的结束。若使最后一个节点的指针指向头节点,则链表呈环状,称循环链表。


小结

链式存储结构特点:

优点:
1.节点空间的动态申请和动态释放,克服了顺序存储结构中需要预先设定数据元素的最大个数的缺点。
2.数据元素之间的次序是用指针来控制的,不像在顺序存储结构中进行插入,删除时需要移动大量数据元素。

缺点:
1.每个节点的指针域需要额外的存储空间,特别是当每个节点的数据域所占空间不是很大时,指针域所占空间就会显得很大。
2.链式存储结构是一种非随机存储结构,不能直接访问,从而增加了算法的时间复杂度。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值