数据结构——表(1)

注:本文为根据《数据结构与算法分析》一书所做笔记与理解

首先,介绍相关的定义:
我们称大小为0的表为空表
除空表外的任何表(A1 , A2 , A3 , …… , AN),我们说 Ai+1 后继 Ai (或继 Ai 之后)并称 A i-1 (i < N)前驱A i ( i > 1)。
元素 Ai 在表中的位置为i。
接下来,介绍要在表ADT中进行的操作:
PrintList:打印表
MakeEmpty:清空表
Find:返回关键字首次出现的位置
Insert:从表的某个位置插入某个关键字
Delete:从表的某个位置删除某个关键字

1 数组实现

如果用数组来实现表这个数据结构,打印、清空、查找元素还好说。但是,如果要插入一个元素在某个位置,那就得从这个位置开始,后面的元素全部往后挪一位。同样的,如果要在某个位置删除一个元素,就得从这个位置开始,后面的元素全部往前挪一位。这也太麻烦了。另外,在定义数据结构的时候,还需要预估一下这个表的大小,从而初始化数组的大小。
由于这些原因,我们一般不用数组。

2 链表

为了避免插入和删除时的移动操作,考虑使用指针。这样,表中的元素就可以不用连续存储,随便放在内存中的哪个位置,只要通过指针指过去就可以了。

如图
链表中每个j节点包括两部分——值和指向下一个节点的指针(即下一个j节点的地址)。
有可能存在的问题是:如果我们删掉了第一个元素,或者在第一个元素前面再插入了一个元素,这样,我们的首元素的指针就会发生变化。因此,一般来说,我们会流出一个标志节点——表头。表头不存储任何值,只是为了保证链表的第一个节点一直不变。
以int型元素为例,放上C++代码

class Node{
public:
	int element;
	Node* next;
	Node(){
		next = NULL;
	}
	Node(int x){
		element = x;
		next = NULL;
	}
	Node(int x , Node* next){
		element = x;
		this->next = next;
	}
}; 
class List{
private:
	Node* head;
	Node* cur;
public:
	//构造函数
	List(){
		head = new Node();
		cur = head;
	} 
	List(Node* node){
		head = new Node(0 , node);
		cur = head;
	}
	//其他一些成员函数
	……
};

添加一些辅助的成员函数:

//清空链表 
void makeEmpty(){
	head->next = NULL;
	cur = head;
} 
//判断是否为空
bool isEmpty(){
	if(head->next == NULL)
		return true;
	else
		return false;
} 
//判断当前是否为链表结尾
bool isLast(){
	return cur->next == NULL;
} 

//移动到表头
void toHead(){
	cur = head;
} 

//往后移动一位
void toNext(){
	if(!isLast())
		cur = cur->next;
} 

//往前移动一位
void toPre(){
	Node* t = cur;
	toHead();
	while(cur->next != t)
		toNext();
} 

2.1 链表的打印和查找

对于PrintList或Find操作,只需要从表头的指针开始,依次获取下一个,下下个……节点的指针即可。

//打印链表 
void print(){
	Node* t = cur;
	cur = head;
	while(!isLast()){
		cout << cur->next->element << "  ";
		toNext();
	}
	cout << endl;
	cur = t;
}
//查找元素,返回位置,没有找到返回-1
int find(int k){
	int pos = 0;
	cur = head;
	while(cur->next != NULL){
		cur = cur->next;
		if(cur->element == k){
			return pos;
		}
		++pos;
	}
	return -1;
} 

2.2链表的删除

对于删除元素,只需要从要删除的节点那里修改一个指针即可。如下图,以要删除节点3为例
在这里插入图片描述
先令当前节点的指针(cur指针)指向要删除的节点的前一个节点,即节点2
在这里插入图片描述
然后将节点2的next指针直接指向节点4即可。这样,在链表中,就没有节点3这个结构了。在这里插入图片描述

相应代码如下:

//删除值为k的元素 
void deleteNode(int k){
	Node* t = cur;
	findPrevious(k);
	if(!isLast()){
		cur->next = cur->next->next;
	}
	cur = t;
}

//找到值为k的节点的前驱节点
void findPrevious(int k){
	toHead();
	while(cur->next != NULL && cur->next->element != k){
		toNext();
	}
} 

2.3链表的元素插入

对于插入元素,只需要新建一个新的节点,将其插入相应的位置,只需要修改两个指针。以下图中链表为例,在节点2和节点4之间插入新的节点3.
在这里插入图片描述
首先,令当前节点指针(cur指针)指向要插入的位置的前一个节点,然后新建一个节点。新建这个节点的值为要插入的值,next指针为插入位置的下一个节点的地址(即节点4的地址)
在这里插入图片描述
然后,将cur节点的next指针指向新节点即可。
在这里插入图片描述
代码就很简单了,假设已经将cur指针移动到了指定位置,只需新建节点并修改相应的next指针即可。

//在当前位置插入值为k的元素
void insert(int k){
	Node* temp = new Node(k , cur->next);
	cur->next = temp;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值