文章目录
一、线性表基础知识
表是由同类型的数据元素构成有序序列的线性结构。表中元素个数称为表的长度,没有元素时称为空表,表的第一个位置称为表头,最后一个位置称为表尾。
二、线性表的基本操作
一般来讲,有以下六种操作:
三、线性表的存储方式
线性表可以由抽象数据类型来表示,包括数据对象集和操作集。线性表有两种实现方法,第一种为数组(顺序存储),第二种为链表(链式存储)。
补充知识 单链表,双链表,数组的区别
1、线性表的顺序存储
需要两个元素,数组长度和指针(指示元素位置);
定义: 顺序存储就是用一组地址连续的存储单元依次存储线性表的数据元素,这种存储结构的线性表称为顺序表。
特点: 逻辑上相邻的数据元素,物理上也是相邻的。
缺点: 不便于插入和删除操作(因为插入删除会引起大量数据的移动),存储密度高,需要预先分配足够应用的存储空间(必须事先知道元素的个数),不然可能会造成存储空间的浪费。
注意,线性表顺序存储时进行插入操作的时候,首先需要从后往前依次向后挪一个位置出来,然后进行插入。相反,进行删除操作的时候,需要先进行删除工作,然后从前往后依次往前挪一个位置。
2、线性表的链式存储
定义: 链式存储通过链建立起数据元素之间的逻辑关系,这种存储结构的线性表称为链式表,存储链表就是存储链表中的一个节点的地址,因此需要定义一个节点类型。。
特点: 不要求逻辑上相邻的数据元素,在物理上也是相邻的。便于插入和删除操作
优点: 不需要事先准备存储空间,需要时动态申请空间元素分散存储在内存中,用指针记住有关系的元素的存储地址
链表分类: 单链表,双链表,循环链表
下面一一介绍单链表,双链表,循环链表。
1)单链表相关操作及c++代码实现
单链表需要定义一个节点类型,每个节点有两部分:一是保持当前节点的数据,二是下一个节点的存储地址。
单链表插入操作
//先把p后的节点地址放在temp中,再把temp的地址放在p中
struct linkRec
{
datatype data;
linkRec *next;
}
tmp = new LinkRec; // 创建一个新节点
tmp->data = x; // 把x放入新节点的数据成员中
tmp->next = p->next; // 把新节点和p的下一成员相连
p->next = tmp; //把p和新节点连接起来
单链表删除操作
delPtr=p->next;
p->next=delPtr->next;
delete delPtr;
单链表头节点操作
引入头节点是为了避免在处理头节点与之后其他节点操作不一致的问题。建立头节点步骤, 1申请空间,2设为头节点。头节点指向链表在内存的首地址。链表的尾节点由于无后续节点,其指针域为空,写作为NULL。
//定义头指针
linkRec *head;
单链表的相关操作总结
//头文件
#pragma once
#include "pch.h"
#include <iostream>
using namespace std;
struct lianbiaoshengming
{
int data;
lianbiaoshengming *next;
};
class Lianbiaohanshu
{
public:
/*删除链表中某一节点函数*/
void delete_lianbiao()
{
cout << "请输入要删除的位置:" << endl;
int index;
cin >> index;
cout << endl;
p = head->next;
temp = new lianbiaoshengming;
for (int i = 0; i < index - 1; i++)
{
p = p->next;
}
temp= p->next;
p->next = temp->next;
cout << "第" << index << "位置的数据删除成功!" << endl;
};
/*在链表中插入某一节点函数*/
void insert_lianbiao()
{
cout << "请输入要插入的数字,换行输入的位置:" << endl;
int y,index;
cin >> y;
cout << endl;
cin >> index;
cout << endl;
temp = new lianbiaoshengming;
p = head->next;
for (int i = 0; i < index - 1; i++)
{
p = p->next;
}
temp->data = y;
temp->next = p->next;
p->next = temp;
cout << "数据插入" << "第" << index << "位置成功!" << endl;
};
/*创建链表函数*/
void create_lianbiao()
{
head = rear = new lianbiaoshengming;
rear->next = NULL;
int x;
cout << "请按行输入数字,输入0结束链表输入:" << endl;
while (true)
{
cin >> x;
p = new lianbiaoshengming;
if (x == 0)
break;
p->data = x;
rear->next = p;
rear = p;
}
rear->next = NULL;
cout << "链表创建结束!" << endl;
};
/*打印链表函数*/
void print_lianbiao()
{
cout << "链表的内容如下:" << endl;
p = head->next;
while (p!=NULL)
{
cout <<p->data;
cout << endl;
p= p->next;
}
cout << endl;
};
/*链表长度函数*/
int getlength()
{
p = head->next;
int len = 0;
while (p != NULL)
{
p = p->next;
len++;
}
return len;
};
/*查找链表中某一元素函数*/
void find_lianbiao(int len)
{
cout << "请输入要查找的元素,换行结束输入:" << endl;
int v;
cin >> v;
cout << endl;
p = head->next;
temp = new lianbiaoshengming;
for (int i = 2; i < len - 1; i++)
{
p = p->next;
if (p->data != v)
{
continue;
}
cout << "查找的元素位于第" << i << "个位置!" << endl;
return;
}
cout << "要查找的元素不存在链表中" << endl;
};
private:
lianbiaoshengming *head, *rear, *p,*temp;
};
//主函数
#include "pch.h"
#include <iostream>
using namespace std;
#include "lianbiao.h"
class Lianbiaohanshu;
Lianbiaohanshu function;
int main()
{
function.create_lianbiao();
function.print_lianbiao();
int len=function.getlength();
cout << "链表长度为:" <<len<< endl;
function.find_lianbiao(len);
function.find_lianbiao(len);
}
2)双链表相关操作及c++代码实现
双向链表(简称双链表),即链表是 “双向”的,因为单链表更适合 “从前往后” 找,而 “从后往前”是双链表的强项,只需要在数据结构中附加一个域,使他包含前一个节点的地址,所以它每个数据结点中都有三个类型,分别存放前驱节点位置,后继节点位置,数据。
双链表的相关操作
- 判断双链表是否为空
- 计算双链表的长度
- 遍历和查找双链表
- 插入双链表(插入表头,插入中间,插入末尾)和删除双链表节点操作
三种插入操作
//头文件
#pragma once
#include "pch.h"
#include <iostream>
using namespace std;
struct shuanglianbiao
{
int data;
shuanglianbiao *next;
shuanglianbiao *pre;
};
class shuanglianbiaohanshu
{
public:
/*创建链表函数*/
void create_shuanglianbiao()
{
rear=head = new shuanglianbiao;
head->pre = NULL;
head->next = NULL;
cout << "请依次输入双链表的值,换行,输入0结束输入" << endl;
int a,x;
cin >> a;
head->data = a;
while (true)
{
cin >> x;
if (x == 0)
break;
p = new shuanglianbiao;
p->data = x;
p->pre = rear;
rear->next = p;
p->next = NULL;
rear = p;
}
cout << "链表创建结束!" << endl;
};
/*打印双链表函数*/
void print_shaunglianbiao()
{
cout << "双链表的内容如下:" << endl;
p = head;
while (p != NULL)
{
cout << p->data;
cout << endl;
p = p->next;
}
cout << endl;
};
/*获取双链表长度函数*/
int getlength_shaunglianbiao()
{
p = head;
int len = 0;
while (p != NULL)
{
p = p->next;
len++;
}
return len;
};
/*插入双链表元素函数,插入分三种情况*/
void insert_shaunglianbiao(int len)
{
cout << "请输入要插入的数字,并换行,再输入插入的位置:" << endl;
int y, index;
cin >> y;
cin >> index;
temp = new shuanglianbiao;
temp->data = y;
if (index == 1)
{
head->pre = temp;
temp->next = head;
temp->pre = NULL;
head= temp;
}
else if (index == len)
{
p = head;
for (int i = 0; i < index - 1; i++)
{
p = p->next;
}
s = p->pre;
s->next = temp;
temp->pre = s;
p->pre = temp;
temp->next = p;
p->next = NULL;
}
else
{
p = head;
for (int i = 0; i < index - 1; i++)
{
p = p->next;
}
s=p->pre;
s->next = temp;
temp->pre = s;
temp->next = p;
temp = p->pre;
}
cout << "数据插入" << "第" << index << "位置成功!" << endl;
};
/*删除双链表元素函数,双链表删除结点时,只需遍历链表找到要删除的结点,然后将该节点从表中摘除即可。*/
void delete_shaunglianbiao(int len)
{
cout << "请输入要删除的位置:" << endl;
int index;
cin >> index;
if(index>len)
cout << "超出链表范围,请重新输入:" << endl;
p = head;
for (int i = 0; i < index - 1; i++)
{
p = p->next;
}
s = p->pre;
k = p->next;
s->next = k;
s = k->pre;
cout << "元素删除成功" << endl;
};
/*查找链表中某一元素函数,通常,双向链表同单链表一样,都仅有一个头指针。因此,双链表查找指定元素的实现同单链表类似,都是从表头依次遍历表中元素。*/
void find_shuanglianbiao(int len)
{
cout << "请输入要查找的元素,换行结束输入:" << endl;
int v;
cin >> v;
p = head;
int i = 0;
while (p->data != v)
{
p = p->next;
i++;
}
cout << "查找的元素位于第" << i+1 << "个位置!" << endl;
return;
cout << "要查找的元素不存在链表中" << endl;
};
private:
shuanglianbiao *pre,*next,data,*head,*p,*rear,*temp,*s,*k;
};
//主函数
#include "pch.h"
#include <iostream>
using namespace std;
#include "shuanglianbiao.h"
class shuanglianbiaohanshu;
shuanglianbiaohanshu function;
int main()
{
function.create_shuanglianbiao();
int len=function.getlength_shaunglianbiao();
cout << "双链表的长度为:" << len << endl;
function.find_shuanglianbiao(len);
function.print_shaunglianbiao();
}
3)循环链表
定义: 对于单链表而言,最后一个结点指针域是空指针,如果将该链表头指针置入该指针域,则使得链表头尾结点相连,这就构成了单循环链表。
优点: 单链表有个缺点,就是无法随机查找,每次查找一个结点都要从头开始,那么单循环链表就很好地解决掉了这个问题。单循环链表可以从表中任意结点开始遍历整个链表。
3、小结
链表需要用结构体来表示每一个节点,每一个节点包括一个数据结构(数据结构就是用于存放各种类型的数据的集合),其中有两个类型,data为存放的内容,指针next为下一节点的地址。如下
//定义链表节点
struct node {
int data;
struct node *next;}
插入节点和删除节点需要保存前置节点的指针。