又是在千家万户熟睡的深夜,老夫依然坐在寝室的硬椅子上,点一支烟(并没有),手指在键盘之间舞动,一根根发丝随着空调冷风从头皮缓缓剥落…咳咳····好了不贫啦!来来来,我们乖乖写完博客睡觉觉哈~
今天带来的是数据结构的第二弹:我不打算细讲,因为我写的程序里有大量注释,相信应该是叫通俗好懂了吧,老少皆宜哈哈~
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;
}
结语
当然,这还算是数据结构中比较基础的东西,感觉多看看还是有好处的。有时候靠的是一种意识哈哈,好了啦!不多话啦好困鸭~睡觉觉去。
晚安地球人!