22计算机408考研—数据结构—线性表栈队列数组
Posted 发呆哥o_o ....
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了22计算机408考研—数据结构—线性表栈队列数组相关的知识,希望对你有一定的参考价值。
2022计算机考研408—数据结构—线性表、栈、队列、数组
手把手教学考研大纲范围内的线性表、栈、队列、数组
22考研大纲数据结构要求的是C/C++,笔者以前使用的都是Java,对于C++还很欠缺,
如有什么建议或者不足欢迎大佬评论区或者私信指出
Talk is cheap. Show me the code.
理论到处都有,代码加例题自己练习才能真的学会
顺序表
官方含义:一段地址连续的存储单元依次存储线性表的数据元素。
其实就相当于数组,`把顺序表当数组看`最简单了
// 顺序表
#include <iostream>
#define MAXSIZE 1001
using namespace std;
typedef struct { //定义学生结构体,包含学号和姓名
char ID[20];
char name[50];
} Student;
typedef struct { //定义线性表,和长度属性
Student *elem;
int length;
} StuList;
bool ListInit(StuList &L) { //初始化线性表
L.elem = new Student[MAXSIZE]; //给数组分配空间长度
if (!L.elem) { //如果没分配成功,就返回失败
return false;
}
L.length = 0; //初始化线性表后长度为0
return true;
}
//插入的时候需要注意把这一位后面的,每个都后移一位,然后把数据放到空出来的那位
bool ListInsert(StuList &L, int i, Student stu) { //把Student类型插入到序列为i的位置
if (i < 0 || i > L.length + 1) { //判断插入位置是否正确
return false;
}
if (L.length == MAXSIZE) { //如果插入位置到达最大值,无法插入
return false;
}
for (int j = L.length - 1; j >= i - 1; j--) { //把i以后元素都向后移动一位,
L.elem[j + 1] = L.elem[j];
}
L.elem[i - 1] = stu; //把将要插入的放到指定位置
++L.length; //线性表长度+1
return true;
}
//也是和插入的时候一样,把i后面的都向前移动一位
bool ListDelete(StuList &L, int i) { //删除序列为i的元素
if (i < 1 || i > L.length) {
return false;
}
for (int j = i; j < L.length; j++) { //把序列i以后的元素全部前移一位,盖住了序列为i的那位
L.elem[j - 1] = L.elem[j];
}
--L.length; //线性表长度-1
return true;
}
bool ListGetStu(StuList &L, int i, Student &s) { //返回序列为i的元素
if (i < 1 || i > L.length) {
return false;
}
s = L.elem[i - 1];
return true;
}
int ListGetIndex(StuList &L, Student s) { //找到与s相等的元素的下标
for (int i = 0; i < L.length; i++) {
if (L.elem[i].ID == s.ID && L.elem[i].name == s.name) {
return i + 1;
}
}
return 0;
}
void ListMerge(StuList &A, StuList B) { //把B表中A表没有的元素插入到A表后面
int a = A.length, b = B.length;
for (int i = 0; i < B.length; i++) {
if (!ListGetIndex(A, B.elem[i])) { //A表中是否存在B.elem[i]
ListInsert(A, ++a,B.elem[i]);
}
}
A.length = a; //a代表新线性表的大小,初始为A线性表大小,后面每次插入到A线性表一个值,a++
}
void ListaddAll (StuList &A, StuList B) { //把B线性表插入到A线性表后面
int a = A.length, b = B.length;
for (int i = 0; i < B.length; i++) {
ListInsert(A, ++a,B.elem[i]);
}
A.length = a;
}
int main() {
StuList demo;
ListInit(demo);
Student student = {"123", "张三"};
Student student2 = {"456", "李三"};
ListInsert(demo, 1, student);
ListInsert(demo, 2, student2);
ListGetStu(demo, 1, student2);
cout << student2.ID << student2.name << "\\n";
cout << ListGetIndex(demo, student) << "\\n";
ListMerge(demo, demo);
ListaddAll(demo, demo);
cout << demo.length;
return 0;
}
链表
链表和顺序表其实是差不多的
顺序表在访问下一个的时候是用下标访问
链表访问下一个只能通过结构体中的指针
插入,删除的时候不需要改变其他元素,只需要修改指定元素前后元素的指针
即可
//此链表的index为序列号从1开始 !!!!不是下标
//此链表多处用到new ,建议大家删一个new调试一下,就能了解到new和不用new的区别了
#include "iostream"
#include "vector"
using namespace std;
typedef struct LNode { //LNode类型 包含一个int值和一个指针指向下一个地址
int data;
struct LNode *next;
} LNode, *LinkList;
bool ListInit(LinkList &L, int val) { //初始化链表,要给一个初始值当作链表头节点
L = new LNode;
L->next = NULL;
L->data = val;
return true;
}
bool ListInsertE(LinkList &L, int val) { //添加一个元素到链表尾端
LNode *headL = new LNode; //保存一下链表当前的位置
headL = L;
while (L->next) { //循环到L最后面,然后把当前值给L的下一个
L = L->next;
}
LNode *temp = new LNode; //new一个结点,如果不new可能会使用上一个temp结点
temp->data = val;
temp->next = NULL;
L->next = temp;
L = headL; //链表的头位置给L
}
bool ListInsert(LinkList &L, int index, int val) { //插入到链表的序列index(注意不是下标)位置
LNode *headL = new LNode; //保存头位置的上一个(headL的下一个是头位置)
headL->next = L; //这里不保存头位置, 防止添加第一个位置时,链表会添加到第二个位置
int j = 0;
while (headL && j < (index - 1)) { //找到第index个位置
j++;
headL = headL->next;
}
if (!headL || index < 1) {
return false;
}
LNode *temp = new LNode; //new一个结点,(不new可能会用到上一个结点)
temp->data = val;
temp->next = headL->next; //把headL的下一个结点给temp的下一个结点
headL->next = temp; //把temp给headL的下一个结点 现在temp的下一个就是原headL的下一个结点,相当于把temp插入到了里面
L = headL->next;
return true;
}
bool ListDelete(LinkList &L, int index) { //删除指定序列index的值
LNode *headL = new LNode;
LNode *tempL = new LNode;
tempL->next = L; //tempL的下一个是头节点(防止删除第一个结点出现问题)
headL = tempL; //保存头结点的上一个,就是tempL
int j = 0;
while (tempL && j < (index - 1)) { //找到序列index的结点
tempL = tempL->next;
j++;
}
if (!tempL) { //如果tempL为NULL,直接退出,没有要删除的结点
return false;
}
tempL->next = tempL->next->next; //tempL的下一个的下一个给下一个 相当于下一个会被直接盖住(删除了下一个 )
L = headL->next; //把头结点给L
}
bool ListGetElem(LinkList L, int index, int &val) { //找到知道序列index的值,传送给val
int j = 0;
while (L && j < (index - 1)) { //找到序列为index的值
L = L->next;
j++;
}
if (!L) { //如果L为空,直接退出,没有此节点
return false;
}
val = L->data;
return true;
}
int ListGetIndex(LinkList L, int val) { //通过值找到指定序列下标
int index = 1;
while (L->data != val) {
L = L->next;
index++;
}
if (!L) {
return 0;
}
return index;
}
void ListCreateH(LinkList &L, vector<int> num) { //前插法创建节点(num数组的值创建链表)
L = new LNode;
L->next = NULL;
for (int i = 0; i < num.size(); i++) {
LNode *p = new LNode;
p->data = num[i];
p->next = L->next; //每次把L的下一个给p的下一个
L->next = p; //然后把p给L的下一个 p的下一个是原来L的下一个
}
L = L->next; //L的下一个才是num数组创建的第一个值
}
void ListCreateE(LinkList &L, vector<int> num) { //前插法创建节点(num数组的值创建链表)
L = new LNode;
LNode *headL = new LNode;
headL = L;
L->next = NULL;
for (int i = 0; i < num.size(); i++) {
LNode *p = new LNode;
p->data = num[i];
p->next = NULL;
L->next = p; //当前指针p给L的下一个
L = p; //把p给L p的上一个就是原L
}
L = headL->next; //头结点的下一个才是num创建的第一个结点
}
void ListPrint(LinkList L) { //输出链表各个的值
while (L) {
cout << L->data << " ";
L = L->next;
}
cout << "\\n";
}
int main() {
vector<int> num = {1,2,3,4,5};
LinkList temp;
// ListCreateE(temp, num);
// ListPrint(temp);
// ListCreateH(temp, num);
// ListPrint(temp);
ListInit(temp, 10); //创建List链表
ListInsertE(temp, 10); //尾端插入值
ListInsertE(temp, 10);
ListPrint(temp);
ListInsert(temp, 1, 20); //插入一个值 到序列index位置
ListPrint(temp);
ListDelete(temp, 3); //删除链表中序列index的值
ListPrint(temp);
int val;
ListGetElem(temp, 3, val); //通过序列index找到值,传给val
cout << val << "\\n";
ListPrint(temp);
cout << ListGetIndex(temp, 2) << "\\n"; //通过值找到序列index
}
双向循环链表
双向循环链表和单链表也是大致相同的
只是在修改结点的关系的时候需要修改每个结点的前后节点
//循环链表
#include "iostream"
#include "vector"
using namespace std;
typedef struct DuLNode { //结点,每个结点有一个值,
int data; //每个结点包括两个指针,一个指向前一个结点,一个指向后一个结点
struct DuLNode *prior; //指定当前结点的前一个结点
struct DuLNode *next; //指定当前结点的后一个结点
} DuLNode, *DuLinkList;
bool ListInitDul(DuLinkList &L, vector<int> data) { //初始化双指针循环链表
DuLNode *headL = new DuLNode; //记录一下头结点,初始化结束后,把头结点重新赋值给L
DuLNode *node = new DuLNode; //初始化的时候,把第一个值给node,依次向下连接
node->data = data[0];
L = node;
headL = L;
for (int i = 1; i < data.size(); i++) {
DuLNode *temp = new DuLNode;
temp->data = data[i]; //每次创建一个新的结点,当作node的下一个,绑定与node的关系
node->next = temp; //绑定temp变成node的下一个
temp->prior = node; //绑定node变成temp的上一个
node = temp; //绑定后,把当前点给node, 方便下次循环绑定下一个值
}
node->next = L; //node此时为最后一个值,,node的下一个绑定头结点(循环链表)
L->prior = node; //L的前一个为node,首结点的上一个就是当前链表的最后一个
L = headL; //把初始头结点给L
return true;
}
bool ListGetDulElem(DuLinkList L, int index, DuLNode &node) { //得到链表序列为index的值,传给node
int j = 1;
while (L && j < index) { //找到序列为index的结点,
L = L->next; //前面有几个,就循环几次,每次都向下走一位
j++;
}
if (!L) { //如果L为空,直接跳过
return false;
}
node = *L; //如果不为空,把当前结点传给node
return true;
}
bool ListInsertDul(DuLinkList &L, int index, int data) { //在序列index位置插入结点
DuLNode *node = new DuLNode;
if (!ListGetDulElem(L, index, *node)) { //查找一下指定index位置,如果没有当前位置,返回false
return false;
}
//假设在a b的位置插入c(在a b中间插入c,b为node,c为newNode)
//设置c的前一个为a 设置a的下一个为c 设置c的下一个为b 设置b的上一个为c
DuLNode *newNode = new DuLNode;
newNode->data = data;
newNode->prior = node->prior; //把node的前一个给newNode的前一个,
node->prior->next = newNode; //把newNode给node的前一个的后一个
newNode->next = node; //把node给newNode的下一个
node->prior = newNode; //把newNode给node的前一个
if (index == 1) { //如果是插入第一个的话,返回node的上一个
L = node->prior; //node此时为第二个,新插入的为第一个值,把第一个值给L
}
return true;
}
bool ListDeleteDul(DuLinkList &L, int index) { //删除序列为index的值
DuLNode *headL = new DuLNode;
headL = L;
DuLNode *node = new DuLNode;
if (!ListGetDulElem(L, index, *node)) { //找到序列index的结点,传给node
return false;
}
//删除node(node为序列index的结点)
//假设a b c删除 b (b为node)
//设置a的下一个为c 设置c的上一个为a
node->prior->next = node->next;
node->next->prior = node->prior;
return true22计算机408考研—数据结构—线性表栈队列数组