408数据结构入门引导

408数据结构

1 基本概念

数据结构:是相互之间存在一种或者多种特定关系的数据元素的集合

数据:毋庸置疑,世界上好多东西都是数据。

数据对象:是数据的子集,是性质相同的数据元素的集合

数据元素:是数据的基本单位,是由一个或者若干数据项组成

数据项:是数据不可分割的最小单位

2 数据结构三大组成(看目录更明确)

数据结构包括逻辑结构和存储结构

2.1 逻辑结构

2.1.1 集合结构

特点:集合就和高数上面的集合体一样

2.1.2 线性结构(除此之外其他结构都是非线性)

特点:一对一

2.1.3 树形结构

特点:一对多

2.1.4 图形结构

特点:多对多

2.2 存储结构(物理结构)

各个数据元素在内存中如何存储

2.2.1 顺序存储结构

顺序存储结构把数据元素放到地址连续的存储单元里面,数据间的逻辑关系和物理关系是一致的。C语言中的数组就如此。

2.2.2 链式存储结构

把数据元素放在任意的存储单元里面,存储单元可以连续也可以不连续,最后都是根据指针找出相邻元素的位置。链式存储结点内的存储单元地址一定连续

2.2 数据运算

运算就是用来指出运算的具体操作步骤

以上三元素全部集齐才可以叫做数据结构

3 数据类型、抽象数据类型

3.1 数据类型

在这里不一一赘述就是c语言中各个数据类型。

3.2 抽象数据类型(ADT)

定义一个ADT就是定义了数据的逻辑结构、数据运算,也就是定义了一个数据结构

4 算法

4.1 定义

求解问题的步骤

4.2 特性

- 有穷性;
- 确定性(有输入有输出);
- 可行性(算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现)
- 正确性;可读性(注释);健壮性;高效率低存储量

4.3 算法的度量

4.3.1 时间复杂度

加法规则

加法就是留下最高的阶的项
通俗的来讲就是程序基本执行操作的次数

for(int i=0;i<n;i++)
    printf("hello");i++;

执行的时间复杂度为T(n)=n+1;但是复杂度表示为O(n)

时间复杂度还有不同的类型比如指数型、搜索型

指数型

while(i<=n){
    i=i*2;
    print("OK");
}

时间复杂度为 T ( n ) = l o g 2 n + 1 ; 则 O ( n ) = O ( l o g n ) T(n)=log_2n+1;则O(n)=O(log n) T(n)=log2n+1;O(n)=O(logn)

搜索型
最好时间复杂度
最坏时间复杂度
平均时间复杂度

for(int i=0;i<n;i++){
    if(flag[i]==n){
        print("%d",n);
    }
}

i值可以最早找到相等的可能为1则最好时间复杂度为O(1)
i值最晚找到相等的为n次则有最坏时间复杂度为O(n)
平均时间复杂度为 每一次找到的概率为 1 n \frac1n n1
所以用每一次找到的次数乘以概率得结果为 1 + n 2 \frac{1+n}{2} 21+n

4.3.2 空间复杂度

空间复杂度考察不多,定义:算法运行所需的内存空间
空间复杂度用 S(n) 表示

void test(int n){
    int flag[n];
    int i;
}

一个int所需内存空间为4
则4+4n+4=4n+8同样保存最高阶作为空间复杂度
S(n)=O(n)

void test(int n){
    int flag[n][n];
    int i;
}

二维数组则为 n 2 n^2 n2

5 线性表

定义:由n个数据特性相同的元素构成的有限序列成为线性表
线性表的类型定义

ADT List{
    数据对象
    数据关系
    基本操作:建立、存取、插入、删除、按位查找、按值查找、分解、排序
}ADT List

线性表的顺序存储又称为顺序表
顺序存储:用一组地址连续的存储单元以此存储线性表的数据元素的方式
线性表的为序是从1开始,而数组的元素的下标是从0开始

5.1 线性表中顺序表中的基本操作的实现

好多有C语言基础的小伙伴在学习数据结构的时候会出现树上的代码无法运行在这里我给大家贴上能运行的代码,文件后缀是cpp/c++ 头文件,一下代码对初学者可以更好的理解顺序表的操作,建议能够自己敲下来

#include<stdio.h>
#include<stdlib.h>
#define Size 5
//一般采用动态分配数组的方式去构造首先是一个结构体
typedef struct{
    int *data;//定义动态分配数组的指针
    int length;//定义顺序表长度
    int size;//定义数组大小
}sqlList;

###初始化顺序表

sqlList InitList(sqlList &L)
{
    //首先申请内存空间
    if((L.data=(int *)malloc(Size*sizeof(int)))==NULL)
    {
        printf("申请存储空间失败");
    }
    printf("申请存储空间成功!!");
    L.length=0;//初始化顺序表长度
    L.size = Size;//初始化数组长度
    return L;
}

int main(void)
{
    
    sqlList L;//定义数据表
    L = InitList(L);    //初始化数据表
    return 0;
}
//以上程序可以作测试可以看到结果。

###顺序表赋值

sqlList Assignment(sqlList &L){
    for(int i = 0;i < L.length;i++)
    {
        L.data[i]=i+1;
        L.length++;
    }
    printf("赋值成功,请调用展示函数");
    return L;
}
int main(void)
{
    sqlList L;          //定义数据表
    L = InitList(L);    //初始化数据表   此处返回的L都是顺序表在内存中的地址
    L = Assignment(L);  //赋值给顺序表
    
    return 0;
}

###顺序表遍历

sqlList Export(sqlList &L){
    printf("顺序表存储数据如下:");
    for(int i=0;i < L.size;i++)
    {
        printf("%d\t",L.data[i]);
    }
    printf("\n");
}
int main(void)
{
    sqlList L;          //定义数据表
    L = InitList(L);    //初始化数据表   此处返回的L都是顺序表在内存中的地址
    L = Assignment(L);  //赋值给顺序表
    Export(L);          //遍历顺序表
    return 0;
}

###顺序表插入元素

bool ListInsert(sqlList &L,int i,int e){
    if(i > L.size + 1 || i < 0)
    {
        printf("插入元素位置错误");
        return false;
    }
    if(i=L.size+1)
    {
        printf("顺序表已满");
        return false;   
    }
    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;
}

int main(void)
{
    sqlList L;          //定义数据表
    L = InitList(L);    //初始化数据表   此处返回的L都是顺序表在内存中的地址
    L = Assignment(L);  //赋值给顺序表
    Export(L);          //遍历顺序表\
    ListInsert(L,2,3);  //在第二个元素后面插入3
    return 0;
}

结果:

OK
申请存储空间成功
赋值成功!!
存储的数据如下
1	2	3	4	5	
存储的数据如下
1	2	3	3	4	5	

###顺序表删除元素

bool ListDelete(sqlList &L,int i,int &e)
{
    if(i > L.size + 1 || i < 0)
    {
        printf("插入元素位置错误");
        return false;
    }
    if(i=L.size+1)
    {
        printf("顺序表已满");
        return false;
    }
    e = L.data[i-1];        //将该位置的元素赋值给e
    for(int j = i;j < L.length;j++)
    {
        L.data[j]=L.data[j-1];//后面的元素往前移
    }
    L.length--;
    return true;
}
int main(void)
{
    sqlList L;          //定义数据表
    L = InitList(L);    //初始化数据表   此处返回的L都是顺序表在内存中的地址
    L = Assignment(L);  //赋值给顺序表
    Export(L);          //遍历顺序表
    ListInsert(L,2,3);  //在第二个元素后面插入3
    Export(L);
    int a = 0;          //删除元素的存储位置
    ListDelete(L,3,a);  //删除元素
    Export(L);
    return 0;
}
结果:

OK
申请存储空间成功
赋值成功!!
存储的数据如下
1 2 3 4 5
存储的数据如下
1 2 3 3 4 5
存储的数据如下
1 2 3 4 5
删除的元素为:3

###顺序表按位查找
因为按位查找出来顺序表是1开始的数组是0开始的所以按位查找很简单

bool GetElem(sqlList &L,int i)
{
    if(i > L.size + 1 || i < 0)
    {
        printf("插入元素位置错误");
        return false;
    }
    if(i=L.size+1)
    {
        printf("顺序表已满");
        return false;
    }
    printf("查找第%d个位置的元素为%d",i,L.data[i-1]);
    return true;
}
int main(void)
{
    sqlList L;          //定义数据表
    L = InitList(L);    //初始化数据表   此处返回的L都是顺序表在内存中的地址
    L = Assignment(L);  //赋值给顺序表
    Export(L);          //遍历顺序表
    ListInsert(L,2,3);  //在第二个元素后面插入3
    Export(L);
    int a = 0;          //删除元素的存储位置
    ListDelete(L,3,a);  //删除元素
    Export(L);
    GetElem(L,2);
    return 0;
}

结果:

OK
申请存储空间成功
赋值成功!!
存储的数据如下
1	2	3	4	5	
存储的数据如下
1	2	3	3	4	5	
存储的数据如下
1	2	3	4	5	
删除的元素为:3
查找第2个位置的元素为:2

###顺序表按值查找

bool GetElemNum(sqlList &L,int e)
{
    for (int i = 1; i < L.length; i++)
    {
        if(L.data[i]==e){
            printf("查找的元素下标为%d\n",i+1);
        }
    } 
}
//主函数
int main(void)
{
    printf("OK\n");
    sqlList L;
    L = InitList(L);            //结构体初始化
    L = Assignment(L);          //结构体赋值
    Export(L);                  //展示顺序表中数据
    ListInsert(L,2,3);          //插入元素到顺序表
    Export(L);
    int a = 0;                  //删除之后的元素存放变量位置
    ListDelete(L,3,a);          //删除
    Export(L);
    printf("删除的元素为:%d\n",a);
    GetElem(L,2);           //按位查找
    GetElemNum(L,5);        //按值查找
    return 0;
}

结果:

OK
申请存储空间成功
赋值成功!!
存储的数据如下
1	2	3	4	5	
存储的数据如下
1	2	3	3	4	5	
存储的数据如下
1	2	3	4	5	
删除的元素为:3
查找第2个位置的元素为:2
查找的元素下标为:5

###顺序表替换元素
以此类体替换先查询想要替换元素的下标

代码已经写完了你能知道他们的时间复杂度么,有的时间复杂度分为最好时间复杂度和最坏时间复杂度你能计算出平均时间复杂度么?

5.2 线性表的链式表示和实现

5.2.1 单链表

在顺序表中找到元素的方式是通过首指针和元素序号可以在O(1)时间内找到指定的元素,元素分布式连续的而在链式存储的时候可以通过指针来找到指定元素下面是必须要知道的概念
首元结点:是指链表存储第一个数据元素的结点
头结点:是首元素结点之前附设的一个结点,他的指针指向首元结点,头结点数据域可以不设任何信息,他的指针域指向线性表的第一个元素结点(首元结点)
头指针:是指向链表中第一个结点的指针,若链表设有头结点,则头指针所指结点为线性表的头结点;若链表不设头结点,则头指针所指结点为该线性表的首元结点。
内容:一个单链表中有若干的结点,结点里分为指针域数据域指针域存放着指向下一个结点的地址,数据域存放着该结点的数据元素内容

5.2.1.1 单链表的基本操作实现

5.2.1.2 单链表

头文件内容

#include<iostream>
using namespace std;
typedef struct LNode {
	int data;
	struct LNode* next;
}LNode,*LinkList;
int main(void)
{

	return 0;
}
  • 单链表的初始化
    初始化操作就是申请一个头结点,将指针域置空。
void LinkListInit(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));
	L->next = NULL;
}
  • 单链表头插法的赋值
    头插法就是 先创建一个结点s,s的数据域指向想要插入的元素,s的指针域指向头结点的指针域,头指针的指针域指向s(新结点)
void LinkListHeadInsert(LinkList& L) {
	LinkListInit(L);
	int x;
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		cin >> x;
	}
}

运行结果在遍历里面一并展示

  • 单链表的遍历
    遍历就是让结点一直指向头结点一直遍历循环,当结点指向NULL的时候说明链表结束
#include<iostream>
using namespace std;
typedef struct LNode {
	int data;
	struct LNode* next;

}LNode,*LinkList;

void LinkListInit(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));
	L->next = NULL;
	cout << "success" << endl;
}
//头插法
void LinkListHeadInsert(LinkList& L) {
	LinkListInit(L);
	int x;
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		cin >> x;
	}
	cout << "插入成功" << endl;
}

void Export(LinkList L)
{
	LNode* p = L->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
		
	}
	cout << endl;
}
int main(void)
{
	LinkList L;
	LinkListHeadInsert(L);
	Export(L);
	return 0;
}

运行结果

success
1 2 3 4 5 0
插入成功
5 4 3 2 1

  • 尾插法建立链表
    就是定义一个结点一直指向链表的尾结点,让尾结点的指向s(新结点),修改尾指针指向新节点 示例代码如下
#include<iostream>
using namespace std;
typedef struct LNode {
	int data;
	struct LNode* next;

}LNode,*LinkList;

void LinkListInit(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));
	L->next = NULL;
	cout << "success" << endl;
}
//头插法
void LinkListHeadInsert(LinkList& L) {
	LinkListInit(L);
	int x;
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		cin >> x;
	}
	cout << "插入成功" << endl;
}
void LinkListTail(LinkList& L)
{
	LinkListInit(L);	//链表初始化
	int x;
	LNode* r = L;		//让一个结点指向链表的尾部
	cin >> x;
	while (x!=0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;              //让r一直指向新的最后一个结点
		cin >> x;
	}
	r->next = NULL;
}
void Export(LinkList L)
{
	LNode* p = L->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}
int main(void)
{
	LinkList L;
	//LinkListHeadInsert(L);
	LinkListTail(L);
	Export(L);
	return 0;
}

运行结果

success
12 3 0
12 3
  • 单链表的查询
    按位
    按位查询的思想就是根据元素所在位置从头结点开始遍历查找
#include<iostream>
using namespace std;
typedef struct LNode {
	int data;
	struct LNode* next;

}LNode,*LinkList;

void LinkListInit(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));
	L->next = NULL;
	cout << "success" << endl;
}
//头插法
void LinkListHeadInsert(LinkList& L) {
	LinkListInit(L);
	int x;
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		cin >> x;
	}
	cout << "插入成功" << endl;
}
void LinkListTail(LinkList& L)
{
	LinkListInit(L);	//链表初始化
	int x;
	LNode* r = L;		//让一个结点指向链表的尾部
	cin >> x;
	while (x!=0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;		//这一步没看懂		
		cin >> x;
	}
	r->next = NULL;
}

LNode* GetELem(LinkList& L, int i)
{
	int j = 1;
	LNode* p = L->next;
	while (p&& j<i)
	{
		p = p->next;
		j++;
	}
	cout << "按位查找的元素为:" << p->data << endl;
	return p;
}

void Export(LinkList L)
{
	LNode* p = L->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}
int main(void)
{
	LinkList L;
	//LinkListHeadInsert(L);
	LinkListTail(L);
	Export(L);
	GetELem(L,3);
	return 0;
}

运行结果:

success
1 2 5 0
1 2 5
按位查找的元素为:5

按值
按值查找的思想更简单,直接根据数值,遍历单链表的data数据域

#include<iostream>
using namespace std;
typedef struct LNode {
	int data;
	struct LNode* next;

}LNode,*LinkList;

void LinkListInit(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));
	L->next = NULL;
	cout << "success" << endl;
}
//头插法
void LinkListHeadInsert(LinkList& L) {
	LinkListInit(L);
	int x;
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		cin >> x;
	}
	cout << "插入成功" << endl;
}
void LinkListTail(LinkList& L)
{
	LinkListInit(L);	//链表初始化
	int x;
	LNode* r = L;		//让一个结点指向链表的尾部
	cin >> x;
	while (x!=0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;		//这一步没看懂		
		cin >> x;
	}
	r->next = NULL;
}

LNode* GetELem(LinkList& L, int i)
{
	int j = 1;
	LNode* p = L->next;
	while (p&& j<i)
	{
		p = p->next;
		j++;
	}
	cout << "按位查找的元素为:" << p->data << endl;
	return p;
}
LNode* LocateGetElem(LinkList& L, int e)
{
	int i = 0;
	LNode* p = L->next;
	while (p->data!=e)
	{
		p = p->next;
		i++;
	}
	cout << "按值查找的元素位置在:" << i + 1 << endl;
	return p;
}
void Export(LinkList L)
{
	LNode* p = L->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}
int main(void)
{
	LinkList L;
	//LinkListHeadInsert(L);
	LinkListTail(L);
	Export(L);
	GetELem(L,3);
	LocateGetElem(L,3);
	return 0;
}

运行结果

success
1 2 4 5 3 0
1 2 4 5 3
按位查找的元素为:4
按值查找的元素位置在:5
  • 单链表的中间插入
    学完之前的代码之后相信大家对单链表有了很清晰的认识了,插入也变得非常的简单,思想是,找到像插入的位置,让新节点的指针域指向插入结点的指针域,让插入结点的指针域指向新节点,通俗的说就是断开再连上。
#include<iostream>
using namespace std;
typedef struct LNode {
	int data;
	struct LNode* next;

}LNode, * LinkList;

void LinkListInit(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));
	L->next = NULL;
	cout << "success" << endl;
}
//头插法
void LinkListHeadInsert(LinkList& L) {
	LinkListInit(L);
	int x;
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		cin >> x;
	}
	cout << "插入成功" << endl;
}
void LinkListTail(LinkList& L)
{
	LinkListInit(L);	//链表初始化
	int x;
	LNode* r = L;		//让一个结点指向链表的尾部
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;		//这一步没看懂		
		cin >> x;
	}
	r->next = NULL;
}

LNode* GetELem(LinkList& L, int i)
{
	int j = 1;
	LNode* p = L->next;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	cout << "按位查找的元素为:" << p->data << endl;
	return p;
}
LNode* LocateGetElem(LinkList& L, int e)
{
	int i = 0;
	LNode* p = L->next;
	while (p->data != e)
	{
		p = p->next;
		i++;
	}
	cout << "按值查找的元素位置在:" << i + 1 << endl;
	return p;
}
void Export(LinkList L)
{
	LNode* p = L->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

LinkList Insert(LinkList& L, int i,int x)
{
	LNode * p = GetELem(L,i-1);			//这个决定是前插还是后插
	LNode* s = (LNode*)malloc(sizeof(LNode));
	s->data = x;
	s->next = p->next;
	p->next = s;
	cout << "新插入的链表为;";
	Export(L);
	return L;
}
int main(void)
{
	LinkList L;
	//LinkListHeadInsert(L);
	LinkListTail(L);
	Export(L);
	GetELem(L, 3);
	LocateGetElem(L, 3);
	Insert(L,2,11);	//在第二个位置上前插入存放11的结点
	return 0;
}

运行结果:

success
1 2 3 4 5 6 0
1 2 3 4 5 6
按位查找的元素为:3
按值查找的元素位置在:3
按位查找的元素为:1
新插入的链表为;1 11 2 3 4 5 6
  • 单链表的删除
    在删除的时候有一个误区,也是我犯错的地方,我原先觉得删除一个结点就是free,我考虑到了free 和malloc函数两个函数是成对出现的所以一开始我的思想就是创建新结点用malloc函数,但实际上删除操作是通过调整指针的指向来实现,虽然两个都可以实现最终结果,但是时间复杂度相差一个数量级,使用创建新的结点来实现删除时间复杂制度为O(n)而改变指针指向时间复杂度为O(1)。
    删除思想为:A–>B–>C
    先断开A和B,让A的next指向B的next,再让B的next指向新定义的结点的next
#include<iostream>
using namespace std;
typedef struct LNode {
	int data;
	struct LNode* next;

}LNode, * LinkList;

void LinkListInit(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));
	L->next = NULL;
	cout << "success" << endl;
}
//头插法
void LinkListHeadInsert(LinkList& L) {
	LinkListInit(L);
	int x;
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		cin >> x;
	}
	cout << "插入成功" << endl;
}
void LinkListTail(LinkList& L)
{
	LinkListInit(L);	//链表初始化
	int x;
	LNode* r = L;		//让一个结点指向链表的尾部
	cin >> x;
	while (x != 0)
	{
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		r->next = s;
		r = s;		//这一步没看懂		
		cin >> x;
	}
	r->next = NULL;
}

LNode* GetELem(LinkList& L, int i)
{
	int j = 1;
	LNode* p = L->next;
	while (p && j < i)
	{
		p = p->next;
		j++;
	}
	cout << "按位查找的元素为:" << p->data << endl;
	return p;
}
LNode* LocateGetElem(LinkList& L, int e)
{
	int i = 0;
	LNode* p = L->next;
	while (p->data != e)
	{
		p = p->next;
		i++;
	}
	cout << "按值查找的元素位置在:" << i + 1 << endl;
	return p;
}
void Export(LinkList L)
{
	LNode* p = L->next;
	while (p)
	{
		cout << p->data << " ";
		p = p->next;
	}
	cout << endl;
}

LinkList Insert(LinkList& L, int i,int x)
{
	LNode * p = GetELem(L,i-1);			//这个决定是前插还是后插
	LNode* s = (LNode*)malloc(sizeof(LNode));
	s->data = x;
	s->next = p->next;
	p->next = s;
	cout << "新插入的链表为;";
	Export(L);
	return L;
}

LinkList Delete(LinkList& L, int i)
{
	LNode* p = GetELem(L, i - 1);	//找到想要删除的结点
	LNode* q = p->next;
	p->next = q->next;
	free(q);
	cout << "删除的结点的新链表为:";
	Export(L);
	return L;
}
int main(void)
{
	LinkList L;
	//LinkListHeadInsert(L);
	LinkListTail(L);
	Export(L);
	GetELem(L, 3);
	LocateGetElem(L, 3);
	Insert(L,2,11);
	Delete(L,2);
	return 0;
}

运行结果:

success
1 2 3 0
1 2 3
按位查找的元素为:3
按值查找的元素位置在:3
按位查找的元素为:1
新插入的链表为;1 11 2 3
按位查找的元素为:1
删除的结点的新链表为:1 2 3

5.2.2 双链表

双链表一个道理,就是加一个指针域让结点都够双向遍历

#include<iostream>
using namespace std;
typedef struct DLNode{
	int data;
	struct DLNode* next, * prior;
}DLNode,*DLinkList;

void LinkListInit(DLinkList& L)
{
	L = (DLNode*)malloc(sizeof(DLNode));
	L->prior = NULL;
	L->next = NULL;
}

//建立双链表
void HeadInsert(DLinkList& L)
{
	LinkListInit(L);
	int x;
	cin >> x;
	while (x!=0)
	{
		DLNode* s = (DLNode*)malloc(sizeof(DLNode));
		s->data = x;
		if (L->next == NULL) {
			s->next = NULL;
			s->prior = L;
			L->next = s;
		}
		else {
			s->next = L->next;
			L->next->prior = s;
			s->prior = L;
			L->next = s;
		}
	}
}
int main(void)
{
	cout << "OK" << endl;
}

5.2.3 循环链表

循环链表也是,就是链表结构定义的时候让结点指向头结点最后形成一个闭环。

5.2.3.1 循环单链表

很简单前提是你已经掌握前面的所有知识给你一段代码你会明白一切

5.2.3.2 循环双链表

很简单前提是你已经掌握前面的所有知识给你一段代码你会明白一切

5.2.4 静态链表

定义:静态链表分配一整片连续的内存空间,各个结点集中安置。和单链表不一样,他的寻址方式是连续的,下一个结点就是连续的下一个结点,如何区分链表是否结束,他的地址通常被称为“游标”,当游标=-1的时候表示已经到达表尾,0号结点充当头结点

用代码定义一个静态链表

struct Node{
    int data;   //存储数据元素
    int next;   //下一个元素的数组下标
};
//初始化
void LinkListInit()
{
    struct Node a[MaxSize];
}

以上代码中以数组的形式初始化静态链表,这个数组的大小就是一片连续的存储空间
以上代码还有另外一种写法 是等价的大家可以去学习一下

#define MaxSize 10
typedef struct{
    int data;
    int next;
}SlinkList[MaxSize];

//等价于
#define MaxSize 10
struct Node{
    int data;
    int next;
};
typedef struct Node SLinkList[MaxSize];

//初始化代码
void Init()
{
    SLinkList a;//意思是你初始化了一个大小为MaxSise的静态链表
}

//等价于
void Init()
{
    struct Node a[MaxSize];
}

完整代码如下

#include<iostream>
using namespace std;
#define MaxSize 10
//正常方式
struct Node{
    int data;
    int next;
};
//简写方式
typedef struct{
    int data;
    int next;
}SlinkList[MaxSize];
int main(void)
{
    struct Node x;
    cout<<sizeof(x)<<endl;
    struct Node a[MaxSize];
    cout<<sizeof(a)<<endl;
    SlinkList b;
    cout<<sizeof(b)<<endl;

    return 0;
}
运行结果
8
80
80
5.2.4.1 静态链表的操作

5.3 顺序表和链表的区别

1.逻辑结构
都是线性表、都是线性结构
2.存储结构

顺序表链表
顺序存储链式存储
支持随机存取、存储密度高离散的校共建分配方便,改变容量方便
大片连续空间分配不方便,改变容量不方便不可以随机存取,存储密度低
3.数据的运算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值