【数据结构地图】单链表操作

本篇主要专注与于解析操作代码的各部分意义,包含链表的增删改查算法实现


下面进入正题:

通过创建结构体实现链表,结构体包含节点的主要信息,包括但不限于节点数据域、节点指针域下面是一段节点定义代码,定义了一个节点结构体。为方便理解,尽可能地简化了语法并在栈区创建节点对象及相关来链表元素,链表实例化对象及要素写在全局区中来调用,代码仅仅表现大体逻辑框架,接近伪代码

#include <iostream>
using namespace std;
struct Node {
	Node* next;//指针域
	int data;//数据域
};

Node* head; Node* tail;
int curlength;
void CreateList() {//创建一个只有头节点的链表
	Node* p = new Node();
	p->data = 0;
	p->next = NULL;
	head = p;
	tail = p;
	cout << "已创建新表" << endl;
}
void tailinsert() {//尾插法
	Node* tmp = new Node();
	cout << "输入新节点data: ";
	cin >> tmp->data;//给新节点的数据赋值
	tmp->next = NULL;//给新节点的指针赋值
	tail->next = tmp;//尾指针的节点next指向新节点
	tail = tmp;//尾指针迁移
}

 以上两段代码负责创建链表和尾端插入元素

bool empty(SeqStack &S) {//判断栈指针是-1,如果是就是空栈
	return S.top == -1;
}

用于检测是否空栈的函数

Clear()——链表清除函数

这个清除的思路是指针迭代,指针p和指针tmp的任务各不相同,tmp用于删除p经过的节点,p移动至下一节点后,tmp将后一个节点删除,然后tmp又指向p所指的节点,p再次向下一节点移动,上述操作重复,直到p指向NULL,此时链表只剩头节点,让tail指向head所指,然后头节点的指针指向NULL,任务就结束了

void Clear() {
	Node* p, * tmp;//两个临时指针,tmp用于删节点
	p = head->next;//p指向头节点下一位节点
	while(p != NULL) {//tmp和p通过反复迭代将节点全部删除,最后只剩头节点
		tmp = p;//tmp也指向p指向的节点
		p = p->next;//p移动到下一个节点
		delete tmp;//用tmp将指向节点删除
	}
	head->next = NULL;//头节点next指针指向NULL
	tail = head;//tail指向head的箭头指向
	curlength = 0;
}

 Traverse()——链表遍历函数

用一个指针p遍历链表,p!=NULL的意义是,当p指向空的时候,while不再执行,这意味着之前经过的所有节点都被访问了一遍数据域,算法符合任务目标

void Traverse(){
	if (empty()) {
		cout << "链表为空,无数据" << endl;
		return;
	}
	Node* p = head->next;//p指向1号节点
	cout << "result: ";
	while (p != NULL) {//遍历所有节点并打印数据
		cout <<"此链表数据为: " << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

 Getposition()——序号查找函数

这个算法负责获得节点序号为参数i的节点首地址,核心语句是while循环,新建一个变量count用于计数和条件判断,初始化为0,则参数是几那么就执行循环几次,循环结束后的p指向的便是符合参数i的节点序号的节点。

Node* Getposition(int i){
	if ( i < -1 || i > curlength - 1)//叛定参数是否合法 
		return NULL;
	Node* p = head;//p指向head所指
	int count = 0;
	while (count < i) {//当count递增至i的值时,函数返回p指向的地址(或者说返回p指针)
		p = p->next;
		count++;
	}
	return p;
}

 Search()——数据查找函数

算法通过接收一个参数值,用指针p遍历链表查找这个值在哪个节点,最后返回这个节点的序号。核心代码还是while循环,判断条件的意义是,指针p没有到达链表尾,也没有找到参数对应的节点,符合条件则继续遍历链表;若指针p指向NULL则是未找到数据,否则便返回那个节点的序号

int Search(int value) {
	Node* p = head->next;
	int count = 0;
	while(p != NULL && p->data != value) {//当p既不指向NULL,p指向的节点data也不是要搜索的参数
		p = p->next;//p移动至下一个节点
		count++;//计数+1
	}
	if(p == NULL)
		return - 1;
	else
		return count;//返回计数值
}

 Insert()——元素插入函数

算法接收两个参数:插入元素的位数、插入元素的数据;老生重谈,涉及链表序号的操作,参数需要做合法性判断,p用于指向目标位数的前一位节点,q指向定义的新节点,然后将参数数据值赋到q指向节点的数据域里,然后q指向的节点的指针域指向q所指节点的next指针所指,再将p指向的节点的next指针指向q所指。

Caution!:核心代码吗中p与q的关系,p指向的节点就是q指向节点的前一个节点

int Insert(int i,int value) {
	Node* p, * q;
	if (i < 0 || i > curlength)//判定参数值在合法范围内
		return 0;
	p = Getposition(i);
	q = new Node();
	q->data = value; //赋值到新节点
    q->next = p->next//q指向节点的next之指针指向前一个节点的next所指
	p->next = q;//p指向的节点的next指针指向q指针所指
	if (p == tail) 
		tail = q;
	curlength++;//链表长度+1
}

Delete()——元素删除函数()

 依然是做个参数合法性判断后,才开始执行删除任务。需要两个指针,一个指针用于引导,一个指针用于删除;首先pre指针指向目标节点系数,p指向pre指向节点的下一位节点,此时进入一个判断,若p指向与tail指向相同,则tail指向pre所指,然后pre指向节点的指针域指向NULL,再删除p指向的对象。不然就让pre指向节点的next指针去指向p指向节点的next所指,然后删除p指向的对象

int Delete(int i) {
	Node* pre, * p;
	if (i < 0 || i > curlength)//判定参数值在合法范围内
		return 0;
	pre = Getposition(i);
	p = pre->next;
	if(p == tail) {
		tail = pre;
		pre->next = NULL;
		delete p;
	}
	else{
		pre->next = p->next;
		delete p;
	}
	curlength--;

Inverse()——链表反转函数         (我自认为这个算法是最麻烦的)

本算法使用两个指针进行迭代,逐步将链表顺序反转。首先p指向头节点的下一个节点,让头节点的next指向空,下面进入一个判断:若p不指向空,则tail指向p所指对象,此时1号节点变成最后一位节点(因为tail已经指向1号了,逻辑上成为了尾节点)。接下来进入循环,当p不指向空时持续执行;tmp指向p所指节点的下一个节点,然后p所指节点的next指针指向头节点的next指向然后头节点的next再指向p所指节点,p接下来指向tmp所指节点

Caution!在一次循环中,tmp指向节点在p指向节点的下一位

void Inverse() {
	Node* p, * tmp;
	p = head->next;//指针p指向1号节点
	head->next = NULL;//头节点next指向空
	if(p != NULL)
		tail = p;
	while(p != NULL) {
		tmp = p->next;
		p->next = head->next;
		head->next = p;
		p = tmp;
	}
}

 Visit()——元素访问函数

算法接收一个变量i,通过while循环遍历到i指定的序号,然后访问对应节点的数据域。切记凡是涉及序号查找的任务,最好做一个参数合法性判断,来增加算法的健壮性。

int Visit(int i) {
	Node* p = head->next;//p指针指向头节点下一个节点
	int count = 0;
	if (i < 0 || i > curlength-1)//判定参数值在合法范围内
		return 0;
	while(count < i) {
		p = p->next;//p指针移动至下一个节点
		count++;//计数增加
	}
	return p->data;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值