数据结构

(可应用于大量有规律性数据,比如轮组转速与电流关系;浓度与检测值关系做出线性链表,可用moto模拟)

线性表的链式存储结构

单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映像)+指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。

1.链接存储方法

链接方式存储的线性表简称为链表(Linked List)

链表的具体存储表示为:
1.用一组任意的存储单元来存放线性表的结点(这组存储单元既可以是连续的,也可以是不连续的)
2.链表中结点的逻辑次序和物理次序不一定相同。为了能正确表示结点间的逻辑关系,在存储每个结点值的同时,还必须存储指示其后继结点的地址(或位置)信息(称为指针(pointer)或链(link))

链式存储是最常用的存储方式之一,它不仅可用来表示线性表,而且可用来表示各种非线性的数据结构。

2、结点结构
在这里插入图片描述
data域——存放结点值的数据域
next域——存放结点的直接后继的地址(位置)的指针域(链域)

带头结点的单链表:头结点的data不保存信息,next指针指向链表的第一个具有data域结点。

在这里插入图片描述
链表通过每个结点的链域将线性表的n个结点按其逻辑顺序链接在一起的,每个结点只有一个链域的链表称为单链表(Single Linked List)。单链表的最大特点是可以将物理地址上不连续的数据连接起来,通过指针来对物理地址进行操作,实现增删改查等功能。

线性表链式存储结构的建立

typedef struct Node
{
int data;
struct Node *next;
}Node,*List;

2、主要操作
void InitList(List plist);//初始化单链表
bool Insert_head(List plist,int val);//头插法
bool Insert_tail(List plist,int val);//尾插法
bool Insert_pos(List plist,int pos,int val);//pos 位置插入
Node *Search_pre(List plist,int key);//查找 key 的前驱
bool Delete(List plist,int key);//删除 key 这个结点
bool IsEmpty(List plist);//是否为空
void Destroy(List plist);//摧毁函数(如果有动态开辟内存)
int GetLength(List plist);//得到单链表的长度
void Show(List plist);//打印单链表

1.初始化单链表

void initList(List plist)
{
	assert(plist != NULL);
	plist->next = NULL;
}

2.得到一个节点

static Node *getNode(int val)
{
  Node *pGet = (Node*)malloc(sizeof(Node));
  assert(pGet != NULL);
  pGet->data = val;
  pGet ->next = NULL;
  return pGet;
}

3.头插法

要注意与放入的数据顺序相反

bool Insert_head(List plist,int val)//头插法
{
   Node *pGet = getNode(val);
   pGet->next = plist->next;
   plist ->next = pGet;
   return true;

}

4.尾插法

操作注意 要用的一个pcur指针指向尾部
与放入的数据顺序相同

bool Insert_tail(List plist,int val)//尾插法
{
   Node *pcur = plist;
   while(pcur -> next!=NULL)
   {
     pcur = pcur->next;
   }
   Node *pGet =getNode(val);
   pGet->next = pcur ->next;
   return true;
}

5.pos位置插入

bool Insert_pos(List plist,int pos,int val)//pos位置插入
{
   assert(plist !=NULL);
   if(pos<0||pos>GetLength(plist))
   {
      return false;
   }
   Node *pGet = getNode(val);
   Node *pcur = plist->next;
   for(int i =0;i<pos;i++)
   {
      pcur =pcur->next;
   }
   pGet->next = pcur->next;
   pcur->next = pGet;
   return true;
}

一.链表的创建

因为我希望在创建结点的时候按照某种方法去排序

typedef struct node{
        int data;
        struct node*next;
}Node;

然后先让我们看看主函数中该怎么写

#include<stdio.h>
#include<stdlib.h>

int main(){
            Node *head;
            heda=NULL;
            int n;//z这里的n代表创建多少个结点
            scanf("%d",&a);
            for(int i = 0;i<n;++i)
            {
               int a;//这里的a代表传给结点的值
               scanf("%d",&a);
               insert(&head,a);//insert增加链表结点函数
             }
             Node *temp = head;
             while(temp != NULL)
             {
                  //输出这个链表
                  printf("%d",temp->next);
             }
             return 0;
            
}

接下来就是inser()函数的写法了
首先我们需要在这个函数里面创建一个结点

void insert(Node **head,int value){//这个参数是取头结点的地址
           Node *temp = (Node*)malloc(sizeof(Node));
           temp->next = NULL;
           temp->data = value;

}

然后怎么利用头结点的头插法把这个链表连起来呢?
我们首先得判断 这个头结点是不是为NULL 因为在定义的时候定义了NULL

if((*head)==NULL)//这里*head 因为head是二级指针 加个*就降了一级.
{*head) = temp;//建议全部带括号*这个运算符的结合律防止出错都带括号把
}

其实这个判断也就是判断是不是第一次创建 头结点有没有东西
头结点要是有了东西呢?

else
{
        Node *t=(*head);//让临时指针的从头开始遍历
        while(t->next != NULL)
        {//这里一定是t->next 如果让t连的话就连接不起来
                t=t->next;
         }
         t->next=temp;//指针域的作用就是连接
}

好了 这就是头插法的创建
但是我们明显发现效率不高 尾插法创建一个就接到链表里面
创建一个就接进去.
但是头插法不行. 必须是创建一个 再从头开始.

一个妙用

我要创建链表并且排序.
这里我们做一个约定 从小到大排列.让我们看看怎么做
还是像刚才创建一样 如果头是空怎么怎么样 否则怎么怎么样对吗?
想一想要改这里吗?

if((*head)==NULL)
{
   (*head) = temp;
}else
{
  
}

答案肯定是不用改因为没数据肯定就把第一个放进去.
那么肯定就是改下一处了
按照我们刚在的想法是不是可以这样写


while(t !=NULL)
{
   if(t->next = temp->data)
   {//如果t的下一个的数据大于了新结点
       temp->next=t->next;//让新结点的指针指向了	t的下一个
       t->next = temp;//再让T指向新结点
       return;//返回就好
   }
      t = t->next;
}

但是这里其实是有两处问题的 先说第一处:
因为是从小到大比较的 我们上面的写法是从头开始
找到比他大的地方就让他插进去.但是如果新的结点就是最大的呢
也就是跑到完都没进到 if 语句中去
所以应该加一个


while(t !=NULL)
{
    if(t->next == NULL)
    {//这一次我们判断下一个是不是空
       t->next = temp;//如果是空了连接一下
       return;//返回就行
     }
     else if(t->next->data>temp->data)
     {
        temp->next = temp;
        return;
     }
     t = t->next;
}

上述不要忘记了返回

还有一个问题就是如果新的结点比头结点小了怎么办
看看我们上面的写法他永远比较的是当前结点的下一个 也就是头结点根本没有比较
所以我们让他在开始的时候比较一下就好了

if(temp->data <(*head)->data)
{
   temp->next = (*head);//新结点的下一个指向头结点
   (*head) = temp;//头结点变成了新结点
   return;//返回
}

好了 这里就写完了 开发的时候具体按照你的方式去创建链表 要比较什么 你自己定
完整代码

#include <stdio.h>
#include <stdlib.h>

typedef struct node
{
  int data;
  struct node*next;
}Node;
void insert(Node **head,int value)
{
Node *temp = (Node*)malloc(sizeof(Node));
temp->next = NULL;
temp->data = value;
if((*head) == NULL)
{
   (*head) = temp;
}
else
{
    Node *t = (*head);
    if(temp->data < (*head)->data)
    {
       temp->nxet = (*head);
       (*head) = temp;
       return;
    }
    while(t !=NULL)
    {
        if(t->next == NULL)
        {
           t->next == temp;
           return;
        }
        while(t !=NULL)
        {
              if(t->next ==NULL)
              {
                 t->next = temp;
                 return;
              }
              while(t !== NULL)
              {
                  if(t->next == NULL)  {
                t->next = temp;
                return;
             } else if(t->next->data > temp->data) {
                temp->next = t->next;
                t->next = temp;
                return;
             }
            t = t->next;
              }
        }
    }
}
}

int main() {
    Node *head;
    head = NULL;
    int n;//这里的n代表创建多少个结点 
    scanf("%d",&n);
    for (int i = 0; i < n; ++i) {
        int a;//这里的a代表传给结点的值 
        scanf("%d",&a);
        insert(&head, a);//insert 增加链表结点函数 
    }
    Node *temp = head;
    while(temp != NULL) { //输出这个链表 
        printf("%d ",temp->data);
        temp = temp->next;
    }
    return 0;
}

头插法讲完了 让我们讲一下尾插法
先看一下 一般的创建方式
首先尾插法的核心代码

2020年08月09

1+2+3+…100

计算100次
int i,sum=0,n=100
for(i=1;i<=n;i++)
{
sum=sum+i;
}
printf("%d",sum);
计算一次
int i,sum=0,n=100
sum=(1+n)*n/2;
printf("%d",sum);

算法时间复杂度

算法时间复杂度的定义:在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,计做:T(n)=Of(n)它表示随问题n的增大,算法执行时间的增长率和F(n)的增长率相同,称作算法的渐进时间复杂度,简称时间复杂度。其中f(n)是问题规模n的某个函数。
一般情况下,随着输入规模n的增大,T(n)增长最慢的算法为最优算法。

如何分析一个算法的时间复杂度?即如何推导大O阶呢?

用常数1取代运行时间中的所有加法常数。
在修改后的运行次数函数中,只保留最高阶项
如果最高阶项存在且不是1,则去除与这个项相乘的常数
得到最后结果就是最大0阶

平方阶

时间复杂度O(n*2)

对数阶

O(logn)
在这里插入图片描述
O(n)

算法的空间复杂

在这里插入图片描述

线性表

线性表:(LIst)由零个或多个数据元素组成的有限序列
在这里插入图片描述

线性表的顺序存储结构

在这里插入图片描述

#define ERROR 0;
#define OK 1//Status是函数的类型
Status GetElem(Sqlist L,int i,ElemType *e)
{
    if(L.length==0||i<1||i<L.length)
    {
        return ERROR;
    }
    *e = L.data[i-1];
    return OK}

Sqlist L线性表
int i索引位置
ElemType *e存放指针

插入操作

ListInsert(*L,i,e),即在L列表中插入个新元素e

Status ListInsert(SqList *L,int i,ElemType e)
{
   int k;
   if(L->length == MAXSIZE)
   {
      return ERROR;
      
   }
   if (i<1 || i>L->length+1)
   {
      return ERROR;
   }
   if(i<=L->length-1;k>=i-1;k--)
   {
      L->data[k+1] = L->data[k];
   }
   L->data[i-1] = e;
   L->length++;
   retrun ok;
}

静态链表的插入操作

首先获取空闲分量的下标

int Malloc_SLL(StaticLinkList space)
{
   int i=space[0].cur;
   if(space[0].cur)
   space[0].cur = space[i].cur;
   //把它下一个分量用来作为备用
   return i;
}

在静态链表L中第i个元素之前插入新的数据元素e

Status ListInsert(StaticLinkList L,int i, ElemType e)
{
    int j,k,l;
    k=MAX_SIZE-1;//数组的最后一个元素
    if(i<1||i>ListLength(L)+1)
    {
        return ERROR;
    }
    j=malloc_SLL(L);
    if(j)
    {
       L(j).data = e;
       for(l=1;l<=i-1;l++)
       {
          k = L(k).cur;
          
       }
       L[j].cur = L[k].cur;
       L[k].cur = j;
       return OK}
    return ERROR;
}

静态链表的删除操作

在这里插入图片描述

Status LisDelete(StaticLinkList L,int i)
{
    int j,k;
    if(i<1||i>ListLength(L){
       return ERROR;
    }
    k = MAX_SIZE-1;
    for(j=1;j<=i-1;j++)
    {
      k= L[k].cur;
      
    }
    j=L[k].cur;
    L[k].cur = L[j].cur;
    Free_SLL(L,j);
    return OK;
    }

    void Free_SLL(l,j);
    {
      space[k]cur=space[0].cur;
      space[0].cur=k;
      
       }
       //返回L中数据元素个数
       int ListLength(staticLinkList L)
       {
         int j=0;
         int i = L[MAXSIZE-1].cur;
         while(i)
         {
         i = L[i].cur;
         j++;
         }
         return j;
}

在这里插入图片描述

%取余,/取整

2/11 =0;2%11=2
6%4=2;(-6)%4=2;6%(-4)=-2
6/3=2;(-6)/3=-2;6/(-3)=-2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值