线性表是n个数据特性相同的元素的组成有限序列,是最基本且常用的一种线性结构(线性表,栈,队列,串和数组都是线性结构),同时也是其他数据结构的基础。线性表有以下特点:
由0个或多个数据元素组成的有限序列
- 是一个序列
- 第一个无前驱,最后一个无后续
- 元素有限
1 顺序表
用一段地址连续的存储单元依次存储线性表的数据结构。顺序存储结构封装的三个属性
- 起始位置
- 最大存储容量 MaxSize
- 当前长度 length
顺序表存和读的时间复杂度为O(1),插入和删除的时间复杂度为O(n)。关于时间复杂度请参考
https://blog.youkuaiyun.com/dulalarepost/article/details/89336730
关于顺序表的优缺点:
优点: - 无需增加存储空间
- 可以快速存取表中任意元素
缺点: - 插入和删除需要移动大量元素
- 当线性表长度较大时,难以确定存储空间容量
- 容易造成空间“碎片”
有关顺序表实现的功能,直接上代码:
#include<iostream>
using namespace std;
#define MAXSIZE 15
typedef int DateType;
//struct 后面省略了定义的变量,因为重命名为SeqList
//SeqList不是变量名,而是异种类型,相当于int,double
typedef struct {
DateType date[MAXSIZE];//通常用数组描述顺序表的数据结构
int SeqLength;//线性表程度
}SeqList;
SeqList *Init_SeqList();//初始化
void Define_SeqList(SeqList *L, int n);//填充顺序表内容
void Display_SeqList(SeqList *L);//提取顺序表中元素
int Insert_SeqList(SeqList *L, int i, DateType x);//添加元素到指定位置(从开始)
int Delete_SeqList(SeqList *L, int i);//删除指定位置元素(从指定位置开始)
//函数实现
SeqList *Init_SeqList() {
SeqList *L;//相当于 int *L,但这个L可以细分,不是指针.,指针型用->
L = new SeqList;
L->SeqLength = 0;
return L;
}
void Define_SeqList(SeqList *L, int n) {
cout << "请依次输入顺序表中要存储的元素:" ;
for (int i = 1; i <=n; i++) {
cin >> L->date[i];
L->SeqLength++;
}
}
void Display_SeqList(SeqList *L) {
cout << "顺序表中的元素为:";
for (int i = 1; i <= L->SeqLength; i++) {
cout << L->date[i]<<" ";
}
cout << endl;
}
int Insert_SeqList(SeqList *L, int i, DateType x) {
cout << "把元素" << x << "插入到位置" << i << "上去!" << endl;
int j;
if (L->SeqLength == MAXSIZE - 1) {
cout << "没有位置存放新的元素!" << endl;
return -1;
}
if (i<1 || i>L->SeqLength + 1) {
cout << "位置错误!";
return -2;
}
for (j = L->SeqLength; j >= i; j--) {
L->date[j + 1] = L->date[j];
}
L->date[i] = x;
L->SeqLength++;
cout << "插入成功!" << endl;
Display_SeqList(L);
return 1;
}
int Delete_SeqList(SeqList *L, int i) {
cout << "删除位置" << i<<"上的元素" << endl;
int j;
if (L->SeqLength == 0) {
cout << "没有元素可以删除!";
return -1;
}
if (i < 1 || i >= L->SeqLength + 1) {
cout << "位置错误!" << endl;
return -2;
}
for (j = i; j <= L->SeqLength;j++) {
L->date[j] = L->date[j+1];
}
L->SeqLength--;
cout << "已删除,结果为:" << endl;
Display_SeqList(L);
return 1;
}
int main() {
SeqList *L;
L = Init_SeqList();
Define_SeqList(L, 5);
Display_SeqList(L);
Insert_SeqList(L, 3, 25);
Delete_SeqList(L, 3);
system("pause");
return 0;
}
实践结果如下:
2 单链表
顺序存储是将数据存储在一段连续的空间中,这样对数据的插入和删除很不利,为了节约空间,我们可以使用链式存储,方法是每个元素多用一个位置存储指向下一个位置的指针,这样可以从第一个元素找到第二个元素,第二个元素可以找到第三个元素。
存数据元素信息的域称为数据域,把存储直接候后继位置称为指针域,指针域中存储的信息称为指针或链。两部分加一起称为结点。链表第一个结点的存储位置叫头指针,最后一个结点的指针为空(NULL)。头结点数据域不存储信息,头指针是指链表指向第一个结点的指针。
2.1 单链表的插入
若想在ai和ai+中插入s其中结点p由ai和p->next组成,结点s由e和s->next组成,结点s由e和s->next组成。所以只需要将
s->next=p->next;
p->next=s;
单链表第i个数据插入结点的算法思路:
1、声明一节点p指向链表头结点,初始化j从1开始;
2、当j<1时,就遍历链表,让p的指针向后移动,不断指向下一节点,j累计加1;
3、若到链表末尾p为空时,说明第i个元素不存在;
4、若查找成功,系统中生成空节点s;
5、将数据元素e赋值给s->date;
6、两个标准语句;
7、返回成功。
2.2 单链表的删除
现有结点p:由a1和p->next组成 结点q:由a2和q->next组成 以及下一个元素a3
若要删除元素a2,则需要:
p->next=p->next->next;
或
q=p->next;
p->next=q->next;
单链表第i个数据删除结点的算法思路:
1、声明一节点p指向链表头结点,初始化j从1开始;
2、当j<1时,就遍历链表,让p的指针向后移动,不断指向下一节点,j累计加1;
3、若到链表末尾p为空时,说明第i个元素不存在;
4、若查找成功,将欲删除结点p->next赋值给q;
6、标准语句p->next=q->next;;
7、将q结点中的数据赋值给e,作为返回;
8、释放q结点。
对于插入或删除越频繁的操作,单链表优势越明显。
2.3 创建整表
单链表整表创建的算法思路:
1、声明一结点p和计数变量i;
2、初始化一空链表L;
3、让L的头结点的指针指向NULL,即建立一个带头结点的单链表;
4、循环实现后继结点的赋值和插入。
方法有头插法建立单链表以及尾插法创建单链表。
单链表基本操作代码如下:
#include<iostream>
using namespace std;
typedef int DateType;
typedef struct LNode {
DateType data;
struct LNode *next;
} LNode;
//用尾插法创建链表
LNode *Creat_Tail(int n) {
LNode *head; //指向头结点的指针
LNode *L=NULL; //链表指针
LNode *current; //临时指针
head = (LNode *)malloc(sizeof(LNode)); //为头结点分配内存空间
head->next = NULL; //将头结点指针域清空
current = head; //先将pre指向头结点
cout << "采用尾插法创建链表:" << endl;
for (int i = 1; i <= n; i++) {
L = (LNode *)malloc(sizeof(LNode));//为要插入的结点分配空间
cout << "请输入第" << i << "个数字:";
cin >> L->data;
current->next = L;
current = L;
}
L->next = NULL; //将最后一个结点的指针域清空
return head; //返回链表的首地址
}
//用头插法创建链表
LNode *Creat_Head(int n) {
LNode *head; //指向头结点的指针
LNode *s=NULL; //链表指针
head = (LNode *)malloc(sizeof(LNode));//给头结点分配内存空间
head->next = NULL;
cout << endl;
cout << "采用头插法创建链表:" << endl;
for (int i = 1; i <= n; i++) {
s = (LNode *)malloc(sizeof(LNode));
cout << "请输入第" << i << "个数字:";
cin >> s->data;
s->next = head->next;
head->next = s;
}
return head;
}
//将链表输出
void Display_List(LNode *h) {
cout << "单链表为:" << endl;
LNode *p;
p = h->next; //让p指针指向链表头结点
while (p) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
//将数据插入链表
LNode *Insert_List(LNode *list,int num,int Insert_num) {
cout << "在" << num << "后插入" << Insert_num << endl;
//head = (LNode *)malloc(sizeof(LNode));
LNode *p;
p = list;
while (p != NULL) {
if (p->data == num) {
LNode *pNew = (LNode *)malloc(sizeof LNode);
pNew->data = Insert_num;
pNew->next =p->next;
p->next = pNew;
break;
}
p = p->next;
}
return list;
}
LNode *Delete_List(LNode *list, int num) {
cout << "删除元素" << num << "后" << endl;
if (list->data == num) {
return list->next;
}
LNode *p,*pn;
p = list;
pn = NULL;
while (p != NULL) {
pn = p;
p = p->next;
if (p == NULL) {
cout << "表中没有此元素!" << endl;
}
else if(p->data==num){
pn->next = p->next;
}
}
return list;
}
int main() {
LNode *list1 = Creat_Tail(5);
Display_List(list1);
//LNode *list2 = Creat_Head(5);
//Display_List(list2);
LNode *list3 = Insert_List(list1, 5, 6);
Display_List(list3);
LNode *list4 = Delete_List(list3, 5);
Display_List(list4);
system("pause");
return 0;
}
实践结果如下: