文章目录
- 二 线性表
- 1.定义与基本操作
- 2.顺序表
- 2.1 定义
- 2.2 静态分配
- 3.链式表
- 3.1 单链表
- 3.1.1 定义
- 3.1.2 建立
- 1)头插法建立单链表
- 2)尾插法建立单链表
- 3.1.3 插入
- 3.1.4 删除
- 3.1.5 查找
- 1)按序号查找结点
- 2)按值查找结点
- * 单链表完整代码
- 3.2 双链表
- 3.2.1 定义
- 3.2.2 插入
- 3.2.3 删除
- 3.2.4 销毁
- 3.2.5 查找
- * 双链表完整代码
- 3.3 循环链表
- 3.3.1 循环单链表
- 3.3.2 循环双链表
- 3.4 静态链表
- 3.5 顺序表和链表
- 3.5.1 比较
- 3.5.2 选取
二 线性表
1.定义与基本操作
-
定义
是有相同数据类型的n个数据元素的有限序列。
其中n为表长,当n=0时线性表是一个空表。
除最后一个数外,其他都有唯一后驱;从第一个数外,其他都有唯一前驱。
-
什么时候要传入参数的引用“&”?
对参数的修改结果需要从函数中带回来。
2.顺序表
2.1 定义
用顺序存储的方式实现线性表顺序存储。
把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中。
-
如何知道一个元素大小?
sizeof()
2.2 静态分配
#include<stdio.h>
#define ElemType int //定义数据类型
//静态定义顺序表
//一旦空间占满,会溢出
#define MaxSize 50 //定义线性表的最大长度
typedef struct {
ElemType data[MaxSize]; //存顺序表的元素
int length; //顺序表当前长度
}SqList; //顺序表的类型定义
//静态分配初始化
void InitList(SqList& L)
{
L.length = 0;
}
//插入操作
//在第i位插入e,成功则返回true
//将第i个元素依次往后移动一个位置,腾出空位插入新元素e
bool ListInsert(SqList& L, int i, ElemType e)
{
//判断i位置是否合理
if (i<1 || i>L.length + 1)
{
return false;
}
//存储空间已满,不能插入
if (L.length >= MaxSize)
{
return false;
}
//将第i个元素及之后的元素后移
for (int j = L.length; j >= i; j--)
{
L.data[j] = L.data[j - 1];
}
L.data[i] = e;//位置i放入e
L.length++;//长度加1
return true;
}
//删除操作
//删除第i个元素,被删元素存在e
bool ListDelete(SqList& L, int i, ElemType& e)
{
if (i<1 || i>L.length)
{
return false;
}
e = L.data[i-1];//将被删元素给i
//将第i位后的元素前移
for (int j = i; j < L.length; j++)
{
L.data[j - 1] = L.data[j];
}
L.length--;//长度减一
return true;
}
//按值查找
//查找第一个等于e的元素,并返回其位序
int LocateElem(SqList L, ElemType e)
{
int i;
for (i = 0; i < L.length; i++)
{
if (L.data[i] == e)
{
return i + 1;//下标为i的元素,位序为i+1
}
}
return 0;
}
void printList(SqList& L)
{
for (int i = 0; i < L.length; i++)
{
printf_s("%d ", L.data[i]);
}
printf_s("\n");
}
int main()
{
SqList L;
InitList(L);
//赋值
for (int i = 0; i < 10; i++)
{
L.data[i] = i;
L.length++;
}
printList(L);
printf_s("插入:\n");
int e = -1,pos=4;
ListInsert(L, pos-1, e);
printList(L);
printf_s("删除:\n");
int a;
ListDelete(L, pos, a);
printList(L);
printf_s("%d\n", a);
printf_s("查找:\n");
pos=LocateElem(L, 5);
printf_s("%d", pos);
}
3.链式表
3.1 单链表
3.1.1 定义
-
注:
元素离散的分布在存储空间中,所以单链表是非随机存取的存储结构。
即不能直接找到表中某个特定的结点,需要从表头开始遍历,依次查找。
-
定义的代码
typedef struct LNode { ElemType data;//每个节点存放一个数据元素 struct LNode* next;//指向下一个节点 }LNode,*LinkList;
-
头结点和头指针
-
初始化
分为带或不带头结点的初始化。
一般用带头结点的链表,会使后续操作方便。
-
不带头结点的初始化
bool InitList(LinkList &L) { L=NULL; return ture; }
-
带头结点的初始化
bool InitList(LinkList& L) { L = (LNode*)malloc(sizeof(LNode));//分配一个头节点 if (L == NULL)return false;//分配失败 L->next = NULL; return true; }
-
3.1.2 建立
1)头插法建立单链表
在链表表头插入新结点。
-
步骤
1.将要插入结点的指针指向 原第一个结点;
2.将头结点指针指向 要插入的结点。
//头插法建立单链表
LinkList List_HeadInsert(LinkList& L)
{
LNode* s;
int x;
InitList(L);//初始化
scanf_s("%d", &x);//输入结点值
//插入表中
while (x != 9999)//9999表示结束
{
//创建新结点
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;//新结点指针域指向原来的第一个结点
//头结点指向新结点
L->next = s;
scanf_s("%d", &x);
}
return L;
}
2)尾插法建立单链表
在链表末尾插入新结点。
-
步骤
1.将尾结点的指针指向新结点;
2.更新尾指针(新尾指针变成新结点)。
//尾插法建立链表
LinkList List_TailInsert(LinkList& L)
{
LNode* s, * r = L;//r为表尾指针
int x;
scanf_s("%d", &x);//输入结点值
//插入表中
while (x != 9999)//9999表示结束
{
//创建新结点
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
//表尾指针指向新结点
r->next = s;
//更新表尾结点
r = s;
scanf_s("%d", &x);
}
r->next = NULL;//尾结点指针置空
return L;
}
3.1.3 插入
-
步骤
1.查找插入位置的前驱结点;
2.将插入结点的指针 指向 插入位置的后驱结点;
3.将前驱结点的指针指向 插入结点。
//在表L中的第i个位置上插入指定元素e
bool ListInsert(LinkList& L, int i, ElemType e)
{
if (i < 1)return false;
LNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while(p!=NULL&&j<i-1)
{
p = p->next;
j++;
}
if (p == NULL)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
3.1.4 删除
- 步骤
bool ListDelete(LinkList& L, int i, ElemType& e)
{
if (i < 1)return false;
LNode* p;//指针p指向当前扫描到的结点
int j = 0;//当前p指向的是第几个结点
//循环找到第i-1个结点
p = L;//指向头结点
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
//i值不合法
if (p == NULL||p->next==NULL)return false;
LNode* q = p->next;//令q指向被删除结点
e = q->data;//用e返回元素的值
p->next = q->next;//将*q结点从链中断开
free(q);//释放结点存储空间
return true;
}
3.1.5 查找
1)按序号查找结点
//按序号查找结点
LNode* GetElem(LinkList L, int i)
{
if (i < 1)return NULL;
int j = 1;
LNode* p = L->next;//第1个结点指针赋给p
while (p != NULL && j < i)
{
p = p->next;
j++;
}
return p;
}
2)按值查找结点
//按值查找
LNode* LocateElem(LinkList L, ElemType e)
{
LNode* p = L->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
* 单链表完整代码
#include<stdio.h>
#include <malloc.h>
#include<time.h>//用于生成随机数
#include<stdlib.h>
#define ElemType int
//---------------定义---------------
typedef struct LNode
{
ElemType data;//每个节点存放一个数据元素
struct LNode* next;//指向下一个节点
}LNode,*LinkList;
初始化不带头节点的单链表
//bool InitList(LinkList& L) {
// L = NULL;
// return true;
//}
不带会麻烦
//初始化带头节点的单链表
bool InitList(LinkList& L)
{
L = (LNode*)malloc(sizeof(LNode));//分配一个头节点
if (L == NULL)return false;
L->next = NULL;
return true;
}
//---------------建立单链表---------------
//头插法建立单链表
LinkList List_HeadInsert(LinkList& L)
{
int m;
printf("\n1.手动输入\n2.自动生成\n");
scanf_s("%d", &m);
if (m == 1)
{
LNode* s;
int x;
scanf_s("%d", &x);//输入结点值
//插入表中
while (x != 9999)//9999表示结束
{
//创建新结点
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;//新结点指针域指向原来的第一个结点
//头结点指向新结点
L->next = s;
scanf_s("%d", &x);
}
return L;
}
else if (m == 2)
{
LNode* s;
int n = 10;//结点个数
srand(time(0));//初始化随机数种子
while (n--)
{
//创建新结点
s = (LNode*)malloc(sizeof(LNode));
s->data = rand() % 100 + 1;//随机产生100以内的数
s->next = L->next;
L->next = s;
}
}
else
{
printf("请重新输入!\n");
List_HeadInsert(L);
}
}
//尾插法建立链表
LinkList List_TailInsert(LinkList& L)
{
int m;
printf("\n1.手动输入\n2.自动生成\n");
scanf_s("%d", &m);
if (m == 1)
{
LNode* s, * r = L;//r为表尾指针
int x;
scanf_s("%d", &x);//输入结点值
//插入表中
while (x != 9999)//9999表示结束
{
//创建新结点
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
//表尾指针指向新结点
r->next = s;
//更新表尾结点
r = s;
scanf_s("%d", &x);
}
r->next = NULL;//尾结点指针置空
return L;
}
else if (m == 2)
{
LNode* s,*r=L;
int n = 10;//结点个数
srand(time(0));//初始化随机数种子
while (n--)
{
//创建新结点
s = (LNode*)malloc(sizeof(LNode));
s->data = rand() % 100 + 1;//随机产生100以内的数
r->next = s;
r = s;
}
r->next = NULL;
return L;
}
else
{
printf("请重新输入!\n");
List_TailInsert(L);
}
}
//---------------插入-----------------
//在表L中的第i个位置上插入指定元素e
bool ListInsert(LinkList& L, int i, ElemType e)
{
if (i < 1)return false;
LNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while(p!=NULL&&j<i-1)
{
p = p->next;
j++;
}
if (p == NULL)
return false;
LNode* s = (LNode*)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
//---------------删除----------------
bool ListDelete(LinkList& L, int i, ElemType& e)
{
if (i < 1)return false;
LNode* p;//指针p指向当前扫描到的结点
int j = 0;//当前p指向的是第几个结点
//循环找到第i-1个结点
p = L;//指向头结点
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
//i值不合法
if (p == NULL||p->next==NULL)return false;
LNode* q = p->next;//令q指向被删除结点
e = q->data;//用e返回元素的值
p->next = q->next;//将*q结点从链中断开
free(q);//释放结点存储空间
return true;
}
//---------------查找----------------
//按序号查找结点
LNode* GetElem(LinkList L, int i)
{
if (i < 1)return NULL;
int j = 1;
LNode* p = L->next;//第1个结点指针赋给p
while (p != NULL && j < i)
{
p = p->next;
j++;
}
return p;
}
//按值查找
LNode* LocateElem(LinkList L, ElemType e)
{
LNode* p = L->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
return p;
}
void List_print(LinkList& L)
{
LinkList t = L->next;
while (t->next != NULL)
{
printf("%d,", t->data);
t = t->next;
}
printf("%d\n", t->data);
}
void PutMenu()
{
printf("\n----------菜单----------\n");
printf("1.头插法创建单链表\n2 尾插法创建单链表\n");
printf("3.插入元素\n");
printf("4.删除元素\n");
printf("5.按序号查找结点\n");
printf("6.按值查找结点\n");
printf("请选择想执行的操作:\n");
}
int main()
{
LinkList L1;
InitList(L1);
//---------------菜单---------------
PutMenu();
int x;
while (~scanf_s("%d", &x))
{
if (x == 1)
{
//头插法创建单链表
List_HeadInsert(L1);
List_print(L1);
}
else if (x == 2)
{
//尾插法创建单链表
List_TailInsert(L1);
List_print(L1);
}
else if (x == 3)
{
int pos, e;
printf("请输入要插入的位置和元素:\n");
scanf_s("%d %d", &pos, &e);
ListInsert(L1, pos, e);
List_print(L1);
}
else if (x == 4)
{
int pos, e;
printf("请输入要删除的元素位置:\n");
scanf_s("%d", &pos);
ListDelete(L1, pos, e);
printf("被删元素:%d\n",e);
List_print(L1);
}
else if (x == 5)
{
LNode* p;
int n;
printf("请输入需要查找的序号:\n");
scanf_s("%d", &n);
p = GetElem(L1, n);
printf("查找结点的值:%d", p->data);
}
else if (x == 6)
{
LNode* p;
int n;
printf("请输入需要查找的结点值:\n");
scanf_s("%d", &n);
p =LocateElem(L1, n);
printf("success!");
}
PutMenu();
}
return 0;
}
3.2 双链表
3.2.1 定义
- 作用
方便找上一个结点。
typedef struct DNode {
ElemType data;
struct DNode* prior, * next;//指向上一个和下一个的结点
}DNode,*DLinklist;
//DNode强调是结点,*DLinklist强调是链表
//初始化双链表
bool InitDLinkList(DLinklist& L) {
L = (DNode*)malloc(sizeof(DNode));//分配一个头结点
if (L == NULL)return false;
L->prior = NULL;//头结点的prior永远指向null
L->next = NULL;
return true;
}
3.2.2 插入
-
步骤
1.插入节点的next指向后继节点;
2.后继节点的prior指向插入节点;
3.插入节点的prior指向前驱节点;
4.前驱节点的next指向插入节点。
//p后插s
bool InsertNextDNode(DLinklist& L, int i, ElemType e) {
if (i < 1)return false;
DNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while (p != NULL && j < i )
{
p = p->next;
j++;
}
//非法参数
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;//指向后继节点
if (p->next != NULL)//如果插入位置不是链表末尾
{
p->next->prior = s;//后继节点指向插入节点
}
s->prior = p;//插入节点指向前驱节点
p->next = s;//前驱节点指向插入节点
return true;
}
//p前插s
//找到待插入位置的前驱节点,再进行后插
bool InsertPriorDNode(DLinklist& L, int i, ElemType e) {
if (i < 1)return false;
DNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
//非法参数
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;//指向后继节点
if (p->next != NULL)//如果插入位置不是链表末尾
{
p->next->prior = s;//后继节点指向插入节点
}
s->prior = p;//插入节点指向前驱节点
p->next = s;//前驱节点指向插入节点
return true;
}
3.2.3 删除
-
步骤
1.前驱节点的next指向后驱节点;
2.后继节点的prior指向前驱节点;
3.释放要删除的节点。
bool ListDelete(DLinklist& L, int i, ElemType& e)
{
if (i < 1)return false;
DNode* p;//指针p指向当前扫描到的结点
int j = 0;//当前p指向的是第几个结点
//循环找到第i-1个结点
p = L;//指向头结点
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
//i值不合法
if (p == NULL || p->next == NULL)return false;
DNode* q = p->next;//令q指向被删除结点
e = q->data;//用e返回元素的值
p->next = q->next;//将*q结点从链中断开
if (q->next != NULL)//q不是最后一个
{
q->next->prior = p;
}
free(q);//释放结点存储空间
return true;
}
3.2.4 销毁
相当于循环删除每个节点。
void DestoryList(DLinklist& L)
{
//循环释放各节点
DNode* p = L->next;
while (p != NULL)
{
DNode* q = p->next;
if (q != NULL)
{
p->next = q->next;
if (q->next != NULL)
{
q->next->prior = p;
}
free(q);
}
p = p->next;
}
free(L);//释放头结点
L = NULL;
}
3.2.5 查找
同单链表查找
时间复杂度:O(n)
* 双链表完整代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ElemType int
//----------------定义-----------------
typedef struct DNode {
ElemType data;
struct DNode* prior, * next;//指向上一个和下一个的结点
}DNode,*DLinklist;
//DNode强调是结点,*DLinklist强调是链表
//*DNode等价于DLinklist
//初始化双链表
bool InitDLinkList(DLinklist& L) {
L = (DNode*)malloc(sizeof(DNode));//分配一个头结点
if (L == NULL)return false;
L->prior = NULL;//头结点的prior永远指向null
L->next = NULL;
return true;
}
//---------------建立单链表---------------
//头插法建立单链表
DLinklist List_HeadInsert(DLinklist& L)
{
int m;
printf("\n1.手动输入\n2.自动生成\n");
scanf_s("%d", &m);
if (m == 1)
{
DNode* s;
int x;
scanf_s("%d", &x);//输入结点值
//插入表中
while (x != 9999)//9999表示结束
{
//创建新结点
s = (DNode*)malloc(sizeof(DNode));
s->data = x;
s->next = L->next;//新结点指针域指向原来的第一个结点
s->prior = L;
//头结点指向新结点
L->next = s;
scanf_s("%d", &x);
}
return L;
}
else if (m == 2)
{
DNode* s;
int n = 10;//结点个数
srand(time(0));//初始化随机数种子
while (n--)
{
//创建新结点
s = (DNode*)malloc(sizeof(DNode));
s->data = rand() % 100 + 1;//随机产生100以内的数
s->next = L->next;
L->next = s;
}
}
else
{
printf("请重新输入!\n");
List_HeadInsert(L);
}
}
//尾插法建立链表
DLinklist List_TailInsert(DLinklist& L)
{
int m;
printf("\n1.手动输入\n2.自动生成\n");
scanf_s("%d", &m);
if (m == 1)
{
DNode* s, * r = L;//r为表尾指针
int x;
scanf_s("%d", &x);//输入结点值
//插入表中
while (x != 9999)//9999表示结束
{
//创建新结点
s = (DNode*)malloc(sizeof(DNode));
s->data = x;
s->prior = r;
//表尾指针指向新结点
r->next = s;
//更新表尾结点
r = s;
scanf_s("%d", &x);
}
r->next = NULL;//尾结点指针置空
return L;
}
else if (m == 2)
{
DNode* s, * r = L;
int n = 10;//结点个数
srand(time(0));//初始化随机数种子
while (n--)
{
//创建新结点
s = (DNode*)malloc(sizeof(DNode));
s->data = rand() % 100 + 1;//随机产生100以内的数
r->next = s;
r = s;
}
r->next = NULL;
return L;
}
else
{
printf("请重新输入!\n");
List_TailInsert(L);
}
}
//-------------------插入操作-----------------------
//p后插s
bool InsertNextDNode(DLinklist& L, int i, ElemType e) {
if (i < 1)return false;
DNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while (p != NULL && j < i )
{
p = p->next;
j++;
}
//非法参数
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;//指向后继节点
if (p->next != NULL)//如果插入位置不是链表末尾
{
p->next->prior = s;//后继节点指向插入节点
}
s->prior = p;//插入节点指向前驱节点
p->next = s;//前驱节点指向插入节点
return true;
}
//p前插s
//找到待插入位置的前驱节点,再进行后插
bool InsertPriorDNode(DLinklist& L, int i, ElemType e) {
if (i < 1)return false;
DNode* p;//指针指向当前扫描到的节点
int j = 0;//当前p指向的是第几个节点
//查找第i个位置
p = L;//L指向头节点,头节点是第0个节点
while (p != NULL && j < i - 1)
{
p = p->next;
j++;
}
//非法参数
if (p == NULL)return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;//指向后继节点
if (p->next != NULL)//如果插入位置不是链表末尾
{
p->next->prior = s;//后继节点指向插入节点
}
s->prior = p;//插入节点指向前驱节点
p->next = s;//前驱节点指向插入节点
return true;
}
//-----------------删除------------------
bool ListDelete(DLinklist& L, int i, ElemType& e)
{
if (i < 1)return false;
DNode* p;//指针p指向当前扫描到的结点
int j = 0;//当前p指向的是第几个结点
//循环找到第i-1个结点
p = L;//指向头结点
while (p != NULL && j < i - 1) {
p = p->next;
j++;
}
//i值不合法
if (p == NULL || p->next == NULL)return false;
DNode* q = p->next;//令q指向被删除结点
e = q->data;//用e返回元素的值
p->next = q->next;//将*q结点从链中断开
if (q->next != NULL)//q不是最后一个
{
q->next->prior = p;
}
free(q);//释放结点存储空间
return true;
}
//-----------------销毁------------------
void DestoryList(DLinklist& L)
{
//循环释放各节点
DNode* p = L->next;
while (p != NULL)
{
DNode* q = p->next;
if (q != NULL)
{
p->next = q->next;
if (q->next != NULL)
{
q->next->prior = p;
}
free(q);
}
p = p->next;
}
free(L);//释放头结点
L = NULL;
}
//---------------查找----------------
//按序号查找结点
DNode* GetElem(DLinklist L, int i)
{
if (i < 1)return NULL;
int j = 1;
DNode* p = L->next;//第1个结点指针赋给p
while (p != NULL && j < i)
{
p = p->next;
j++;
}
return p;
}
//按值查找
DNode* LocateElem(DLinklist L, ElemType e)
{
DNode* p = L->next;
while (p != NULL && p->data != e)
{
p = p->next;
}
if (p != NULL)
{
printf("Success!\n");
}
else
{
printf("没有这个值!\n");
}
return p;
}
void Menu()
{
printf("\n----------菜单----------\n");
printf("1.头插法创建\n2.尾插法创建\n");
printf("3.后插\n4.前插\n");
printf("5.删除节点\n6.销毁双链表\n");
printf("7.按序号查找\n8.按值查找\n");
}
void Listprint(DLinklist& L)
{
if (L == NULL)
{
printf("链表为空!\n");
return;
}
DLinklist t = L->next;
while (t->next != NULL)
{
printf("%d ", t->data);
t = t->next;
}
printf("%d\n", t->data);
}
int main()
{
DLinklist L;
InitDLinkList(L);
int x;
Menu();
while (~scanf_s("%d", &x)) {
if (x == 1)
{
List_HeadInsert(L);
Listprint(L);
}
else if (x == 2)
{
List_TailInsert(L);
Listprint(L);
}
else if (x == 3)
{
int pos;
ElemType data;
printf("请输入要插入的位置和值:\n");
scanf_s("%d %d", &pos,& data);
InsertNextDNode(L, pos,data);
Listprint(L);
}
else if (x == 4)
{
int pos;
ElemType data;
printf("请输入要插入的位置和值:\n");
scanf_s("%d %d", &pos, &data);
InsertPriorDNode(L, pos, data);
Listprint(L);
}
else if (x == 5)
{
int pos;
ElemType x;
printf("请输入要删除的位置:\n");
scanf_s("%d", &pos);
ListDelete(L, pos, x);
printf("已删除元素:%d\n", x);
Listprint(L);
}
else if (x == 6)
{
DestoryList(L);
printf("Success!\n");
Listprint(L);
}
else if (x == 7)
{
DNode* p;
int n;
printf("请输入需要查找的序号:\n");
scanf_s("%d", &n);
p = GetElem(L, n);
printf("查找结点的值:%d", p->data);
}
else if (x == 8)
{
DNode* p;
int n;
printf("请输入需要查找的结点值:\n");
scanf_s("%d", &n);
p = LocateElem(L, n);
}
Menu();
}
return 0;
}
3.3 循环链表
3.3.1 循环单链表
将最后一个节点指针指向头结点。
好处
1.可从表中任意一个节点开始遍历整个链表。
2.可不设头指针而设尾指针,此时对表头表尾的操作时间复杂度都只需O(1)。
3.3.2 循环双链表
头节点的prior指针指向尾结点;
尾结点的next指针指向头结点。
-
初始化循环双链表
bool InitDLinkList(DLinklist &L){ L=(DNode*)malloc(sizeof(DNode)); if(L==NULL)return false; //头结点的prior指向头结点 L->prior=L; //头结点的next指向头结点 L->next=L; return true; }
-
双链表判空
bool Empty(DLinklist L) { if(L->next==L) return true; else return false; }
3.4 静态链表
- 静态链表:分配一整片连续内存空间,各个节点集中安置。
- 单链表:分散分布。
-
定义
相当于将单链表的next指针变成下一个元素下标。
typedef struct{ ElemType data; int next; //下一个元素的数组下标 }SLinkList[MaxSize];
3.5 顺序表和链表
3.5.1 比较
-
1.读取方式
- 顺序表:可顺序存取,也可随机存取。
- 链表:只能从表头顺序存取元素。
-
2.逻辑结构和物理结构
- 顺序表:逻辑上相邻,对应的物理存储位置也相邻。
- 链表:逻辑上相邻,物理存储位置不一定相邻,对应的逻辑关系是通过指针链接来表示的。
-
3.查找
- 按值查找时,两者都相同。数据无序则 O ( n ) O(n) O(n),有序按折半查找为 O ( l o g 2 n ) O(log_2n) O(log2n)。
- 按序号查找时,
- 顺序表:支持随机访问,所以为 O ( 1 ) O(1) O(1)。
- 链表:要遍历,所以为 O ( n ) O(n) O(n)。
-
4.查找和删除
- 顺序表:平均要移动半个表长的元素。
- 链表:修改相关节点指针域即可。
-
5.空间分配
- 顺序表:
- 静态存储:不能扩充。
- 动态存储:需移动大量元素,导致操作效率降低。如果内存中没有大块连续存储空间,会导致分配失败。
- 链表:只在需要时申请分配,只要内存有空间就可以分配。
- 顺序表:
3.5.2 选取
-
基于存储考虑
难以估计线性表长度时,用链表。
-
基于运算考虑
- 按序号查找多时用顺序表。
- 插入删除操作多时用链表。