(头冷巨制)数据结构学习日志2——(初级掉发向)--关于顺序表.单链表的核心操作实现(By Ivan小黄)

又是在千家万户熟睡的深夜,老夫依然坐在寝室的硬椅子上,点一支烟(并没有),手指在键盘之间舞动,一根根发丝随着空调冷风从头皮缓缓剥落…咳咳····好了不贫啦!来来来,我们乖乖写完博客睡觉觉哈~

今天带来的是数据结构的第二弹:我不打算细讲,因为我写的程序里有大量注释,相信应该是叫通俗好懂了吧,老少皆宜哈哈~

1.数据类型的定义

这里我们自己定义一个头文件DataElement.h
用来定义需要用到的各种数据类型

#pragma once
#define MAX_SIZE 255	//	顺序表的最大空间

//	定义一种数据类型
typedef struct {
	int id;
	char name[10];
}DataType;
//	定义顺序表类型
typedef struct {
	DataType datas[MAX_SIZE];
	int length;
}SeqList;

//	定义结点类型
typedef struct Node {
	DataType data;	//	数据域
	struct Node * next;	//	指针域
}Node;

//	定义链表类型
typedef struct LinkList {
	Node * headPointer;	//	头指针
	int length;		//	记录单链表的长度
}LinkList;

2.顺序表的操作方法定义

在这里我也是先定义一个头文件SequenceList.h,定义与实现分离,这样的话程序会比较有条理,观察也更清晰~(注意要引入刚才的头文件)

//	对顺序表定义操作
#pragma once
#include"DataElement.h"

//	1.初始化元素
/*	参数1:要初始化的顺序表
 *	参数2:要初始化顺序表中的元素
 *	参数3:要初始化顺序表中的元素个数
 */
void InitSeqList(SeqList & sequenceList, DataType * dataElements, int length);

//	2.插入元素
/*	参数1:要插入的顺序表
 *	参数2:要插入的元素位置(下标)
 *	参数3:要插入的元素
 */
void InsertElement(SeqList & sequenceList, int index, DataType  dataElement);

//	3.打印顺序表
void PrintSeqList(SeqList seqenceList, int length);

//	4.删除顺序表中的元素
void DeleteElement(SeqList & seqList, int index, DataType & deleteElement);

//	5.获取顺序表中的元素,通过下标访问
DataType* GetData(SeqList & seqList, int index);

3.顺序表的操作方式实现

这里实现的话我做了一个SequenceList.cpp与之前的头文件对应啦~
(同样注意引入头文件)

#include"SequenceList.h"
#include<iostream>
using namespace std;

//	1.初始化元素
/*	参数1:要初始化的顺序表
 *	参数2:要初始化顺序表中的元素
 *	参数3:要初始化顺序表中的元素个数
 */
void InitSeqList(SeqList & sequenceList, DataType * dataElements, int length)
{
	//	1.初始化即为可以向顺序表中初始输入元素
	//	2.注意初始化的长度不能超过数组的最大长度
	if (length > MAX_SIZE) return;
	sequenceList.length = 0;
	for (int i = 0; i < length; i++)
	{
		InsertElement(sequenceList, i, dataElements[i]);
	}
}


//	2.插入元素
/*	参数1:要插入的顺序表
 *	参数2:要插入的元素位置(下标)
 *	参数3:要插入的元素
 */
void InsertElement(SeqList & sequenceList, int index, DataType  dataElement)
{
	//	1.首先判断插入的下标是否合法
	if (index > MAX_SIZE)
	{
		cout << "下标越界,超过了数组的最大长度!" << endl;
		return;
	}
	if (index < 0 || index > sequenceList.length)
	{
		cout << "插入的下标不合法!" << endl;
		return;
	}
	//	2.再检查插入后数组是否越界
	if (sequenceList.length + 1 > MAX_SIZE)
	{
		cout << "数组越界!无法插入!" << endl;
		return;
	}
	//	3.插入算法的实现
	else{
		for (int i = sequenceList.length - 1; i >= index; i--)
		{
			sequenceList.datas[i + 1] = sequenceList.datas[i];
		}
		sequenceList.datas[index] = dataElement;
		//	4.最后记得顺序表的长度加一
		sequenceList.length++;
	}
}

//	3.打印顺序表
void PrintSeqList(SeqList seqenceList, int length)
{
	for (int i = 0; i < length; i++)
	{
		cout << seqenceList.datas[i].id << ": " << seqenceList.datas[i].name << endl;
	}
}

//	4.删除元素
/*	参数1:要选择删除的顺序表
 *	参数2:要删除元素的下标
 *	参数3:返回的删除元素
 */
void DeleteElement(SeqList & seqList, int index, DataType & deleteElement)
{
	//	1.首先判断要删除的下标是否合法
	if (index < 0 || index >= seqList.length)
	{
		cout << "要删除的下标越界!不可以删除!" << endl;
		return;
	}
	deleteElement = seqList.datas[index];
	//	2.删除算法的实现
	for (int i = index; i < seqList.length - 1; i++)
	{
		seqList.datas[i] = seqList.datas[i + 1];
	}

	seqList.length--;
}
//	得到顺序表中某一元素,根据下标访问
DataType* GetData(SeqList & seqList, int index)
{
    DataType* ele = &(seqList.datas[index]);
	return ele;
}

4.单链表操作方法的定义

链表相对于顺序表来说比较复杂,但还是有门路的。要习惯数据域与指针域还有结点之间的关系。关键是结点的指针域。大部分的操作都是基于结点的指针域。这里我不讲太细(困,以后有机会再补)
直接上代码感受一下
定义了头文件LinkList.h

#pragma once
//	单链表
#include"DataElement.h"



/**初始化链表
 *参数1:要初始的链表
 *参数2:初始化链表所需的数据元素
 *参数3:初始化链表的长度
 */
void InitLinkList(LinkList * linkList, DataType * datas, int length);

/**插入链表
 *参数1:选择要插入的链表
 *参数2:选择插入的位置
 *参数3:插入的元素
 */
void InsertLinkList(LinkList * linkList, int pos, DataType data);

/**删除链表元素
 *参数1:选择要删除的链表
 *参数2:选择要删除的位置
 */
void DeleteLinkList(LinkList * linkList, int pos);

//	查找元素并返回结点的地址
Node * GetLinkListData(LinkList * linkList, int pos);


void PrintLinkList(LinkList * linkList);	//打印单链表

5.单链表操作方法的实现

同样继承上面的头文件,我们来把方法的思路实现
代码:

#include"LinkList.h"
#include<stdlib.h>
#include<iostream>
using namespace std;

/**初始化链表
 *参数1:要初始的链表
 *参数2:初始化链表所需的数据元素
 *参数3:初始化链表的长度
 */

void InitLinkList(LinkList * linkList, DataType * datas, int length)
{
	linkList->length = 0;
	for (int i = 0; i < length; i++)
	{
		InsertLinkList(linkList, i + 1, datas[i]);
	}
}

/**插入链表
 *参数1:选择要插入的链表
 *参数2:选择插入的位置
 *参数3:插入的元素
 */
void InsertLinkList(LinkList * linkList, int pos, DataType data)
{
	//	新建一个结点
	Node * node = new Node;
	node->data = data;		//	为插入的结点复制
	node->next = NULL;	//	结点的指针先置为空
	
	if (linkList->length != 0 && pos == 1)
	{
		node->next = linkList->headPointer;
	}
	
	if (pos == 1)		//	如果要插入结点是第一个位置
	{
		linkList->headPointer = node;		//	直接把头指针指向node结点
		linkList->length++;		//	单链表的长度加一
	}

	else
	{
		//	新建一个节点指针,主要用来表示插入节点前一个的位置
		Node * currNode = linkList->headPointer;
		
		//	找到要插入的结点位置
		//	这个循环的话我不多讲,大家自己画图理一下,很有必要,需要理解的这里,建议边画图边理解
		for (int i = 1; currNode && i < pos - 1; i++)
		{
			currNode = currNode->next;
		}
		//	具体插入操作的实现
		if (currNode)
		{
			node->next = currNode->next;	//	先把插入位置的上一个结点的next赋给node的next
			currNode->next = node;		//	再把前一个结点的next指向新插入的node结点
			linkList->length++;		//	单链表的长度加一
		}
	}
}


/**删除链表元素
 *参数1:选择要删除的链表
 *参数2:选择要删除的位置
 */
void DeleteLinkList(LinkList * linkList, int pos)
{
	if (pos > linkList->length)
	{
		cout << "访问位置超过链表长度,程序退出!!!" << endl;
		return;
	}

	Node * delNode = GetLinkListData(linkList, pos);
	if (pos == 1)
		 linkList->headPointer = delNode->next;

	if (pos >= 2)
	{
		Node * preNode = GetLinkListData(linkList, pos - 1);
		preNode->next = delNode->next;
	}
	delete delNode;	
}	

//	查找元素并返回结点的地址
Node * GetLinkListData(LinkList * linkList, int pos)
{
	Node * node = linkList->headPointer;
	for (int i = 1; node && i < pos; i++)
	{
		node = node->next;
	}
	return node;
}


void PrintLinkList(LinkList * linkList)	//打印单链表
{
	Node * node = linkList->headPointer;
	for (int i = 0; node && i < linkList->length; i++)
	{	
		cout << node->data.id  << "  " << node->data.name << endl;
		node = node->next;
	}
}

6.最后的测试程序

没啥好讲的啦~基本上已经完成了,我写一遍就写好了哈哈哈开心,嗯,还是粘一下吧

#include"SequenceList.h"
#include"LinkList.h"
#include<iostream>
using namespace std;

DataType dataElements[5] = {
	{1, "小明"},
	{2, "小丽"},
	{3, "小猪"},
	{4, "小狗"},
	{5, "小猫"}
};

int main()
{
//	测试顺序表
	/*SeqList seqList;
	DataType insertEle = {6, "诸葛亮"};
	DataType deleteEle;
	InitSeqList(seqList, dataElements, 5);
	PrintSeqList(seqList, seqList.length);
	cout << "数组的长度为:" << seqList.length << endl;
	InsertElement(seqList,0, insertEle);
	PrintSeqList(seqList, seqList.length);
	cout << "数组的长度为:" << seqList.length << endl;
	DeleteElement(seqList, 1, deleteEle);
	PrintSeqList(seqList,seqList.length);
	cout << "删除掉的元素为:" << deleteEle.id  << ":" << deleteEle.name << "  数组的长度为:" << seqList.length << endl;
	*/

	//	测试单链表
	LinkList * list = new LinkList;
	InitLinkList(list, dataElements, sizeof(dataElements)/sizeof(dataElements[0]));
	PrintLinkList(list);
	DataType insData = {4, "多啦A梦"};
	InsertLinkList(list, 4, insData);
	PrintLinkList(list);
	return 0;
}

结语

当然,这还算是数据结构中比较基础的东西,感觉多看看还是有好处的。有时候靠的是一种意识哈哈,好了啦!不多话啦好困鸭~睡觉觉去。
晚安地球人!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值