如何学习数据结构与算法

随谈

为什么要学习数据结构

随着人工智能的发展,人工智能已经渗透到各个行业,算法工程师非常火爆,急缺大量人才,年薪也越来越高。刚毕业30-40万很常见,很多人都想学习算法,那究竟如何下手呢?
遇到一个实际问题,需要解决两个事情:
(1)如何将数据存储到计算机中;
(2)用什么方法策略解决问题;前者是数据结构,后者是算法。只有数据结构没有算法,相当于只把数据存储到计算机中而没有有效的方法去处理,就像一幢只有框架的烂尾楼;若只有算法,没有数据结构,就像沙漠的海市蜃楼,只不过是空中楼阁罢了。
数据 是一切输入到计算机的信息总和,结构是指数据之间的关系,数据结构 就是将数据及其之间的关系有效的储存在计算机中。算法 是指对特定问题求解步骤的一种描述,数据结构和算法并不依赖于语言。
遇到一个实际问题,充分利用所学的数据结构,将数据及其之间的关系有效的储存在计算机中,然后选择合适的算法策略,并用程序高效实现。即数据结构 + 算法 = 程序
通过学习数据结构,更加准确,深刻地理解不同数据结构之间的共性和联系,学会选择和改进数据,高效地设计并实现各种算法,这才是数据结构的精髓。

数据结构的学习秘籍

会数据结构的基本操作

学会各种数据结构的基本操作,取值,查找,插入,删除等。先看图解,理解各种数据结构的定义,操作方法,然后看代码,尝试自己动手上机运行,逐渐掌握基本操作。初学时,要想理解数据结构,一定要学会画图,通过画图形象表达,更能体会其中的数据结构关系。初学阶段的利器:画图,理解,画图 。

会利用数据结构解决实际问题

掌握基础操作之后,就可以尝试利用数据结构解决一些实际问题了,先学会经典应用问题的解决方法,体会数据结构的使用方法,然后在做题,独立设计数据结构解决问题,要想熟练应用就必须大量做题,从做题中体会其中的方法。最好进行专项练习,比如线性表问题,二叉树问题,图问题。该阶段的学习利器:做题,反思,做题 。

熟练使用和改进数据结构,优化算法

最高境界,也是学习数据结构的精髓所在。单独学习数据结构是无法达到的,需要在学习算法的过程中慢慢修炼。在学习算法的同时,逐步熟练应用,改进,慢慢体会不同数据结构和算法策略的复杂性,最终学会利用数据结构改进和优化算法。该阶段已经在数据结构之上,通过在测试系统上刷各种算法题,体会利用数据结构改进优化算法。该阶段的利器:刷题,总结,刷题 。

算法的学习秘籍

多角度,对比学习

学习算法可以先阅读一本简单的入门书,然后综合几本书横向多角度看,例如学习动态规划,拿几本算法书,把动态规划这章找出来,比较学习,多角度对比分析更清晰,或许你会恍然大悟,噢,原来如此简单!

大视野,不求甚解

公式可以看不懂,代码可以不会。不必投入大量精力试图推导每一个公式,也不必探究语法细节。算法的背后可能有高深的数学模型,复杂的推理证明,理解了当然玄妙,不懂拉倒。学算法是学算法本身,首先是算法思想,解题思路,然后是算法实现。先领会算法,写伪代码,遇到不懂的部分,浏览一下或跳过去,读完了还不明白再翻翻别的书。

多交流,见贤思齐

与同学,朋友,教师或者其编程爱好者们一起学习和讨论问题,是取得进步最有效的办法,也是分享知识和快乐的途径。加入论坛交流群,会了解他人在做什么,怎么做,遇到问题可以请教高手,带来醍醐灌顶的喜悦:论坛和群也会分享大量的学习资料,视屏,读数交流,你会发现,不是你一个人在战斗!

勤实战,越挫越勇

不要急切期望“实际的”例子,更不要看不起小实例,“不积跬步无以至千里” 。大规模的成功商业案例所采用的算法,无人驾驶,人工情感,不是我们目前解决的问题。看清脚下的路,比仰望星空更实际,多做一些实战练习,更好的体会算法本质,在错误中不断成长,越挫越勇,终究会成为算法高手。

看电影,洞察未来

可以看看科幻电影,如《人工智能》,《记忆裂变》,《未来战士》,《她》等等。奇妙的是这些科幻东西正在一步步的实现,靠的是什么?人工智能。计算机的终极是人工智能,人工智能的核心是算法。

如何学好数据结构与算法

“一心两本” 学习法:一颗好奇心,两个记录本。
怀着一颗好奇心去学习,才能不断解决问题,获得满足感,很多科学大牛都是永远保持着一颗好奇心。一个记录本记录学习重点难点;一个记录本记录日记或周记,记录一天或一周来学习了什么,有什么经验教训,需要注意什么,计划下一周或下一天该做些什么。不断总结反思过去,计划未来,每天都有事情做,心中正能量满满。

几个常见算法的回顾

1,冒泡排序

要点:
1,两两注意是相邻的两个元素的意思;
2,如果有 n 个元素需要比较 n-1 次,每一轮减少一次比较;
3,既然叫冒泡排序,那就是从下往上两两比较,所以看上去就像泡泡往上冒一样。
经典的冒泡排序:

# include  
void BubbleSort(int k[],int n)  
{
  int i,j,temp,cout1=0,cout2=0;
  for(i=0;i<n-1;i++)
  {
    for(j=i+1;j<n;j++)
    {
      cout1++;
      if(k[i]>k[j])
      {
        cout2++;
        temp=k[j];
        k[j]=k[i];
        k[i]=temp;
      }
    }
  }
   printf("总共进行了%d次比较,进行了%d次移动!",cout1,cout2);
}
int main()  
{
  int i,a[10]={5,2,6,0,3,9,1,7,4,8};
  BubbleSort(a,10);
  printf("排序后的结果
  for(j=i+1是:");
  for(i=0;i<10;i++)
  {
    printf("%d ",a[i]);
  }
  printf("\n");
  return 0;
}

正宗的冒泡排序:

# include  
void BubbleSort(int k[],int n)  
{
  int i,j,temp,cout1=0,cout2=0;
  for(i=0;i<n-1;i++)
  {
    cout1++;
    for(j=n-1;j>i;j--)
    {
      if(k[j-1]>k[j])
      {
        cout2++
        temp=k[j-1];
        k[j-1]=k[i];
        k[i]=temp;
      }
    }
  }
  printf("总共进行了%d次比较,进行了%d次移动!",cout1,cout2);
}
int main()  
{
  int i,a[10]={5,2,6,0,3,9,1,7,4,8};
  BubbleSort(a,10);
  printf("排序后的结果是:");
  for(i=0;i<10;i++)
  {
    printf("%d ",a[i]);
  }
  printf("\n");
  return 0;
}

2,选择排序

要点:
选择排序算法就是通过 n-i 次关键字间的比较,从 n-i+1 个记录中选出关键字最小的记录,并和第i (1<=i<=n)个记录交换。
代码演示

#include
void SelectSort(int k[],int n)
{
  int i,j,min,temp;
  for(i=0;i<n-1;i++)
  {
    min=i;
    for(j=i+1;j<n;j++)
    {
      if(k[j]<k[min])
      {
        min=j;
      }
    }  
    if(min!=i)
    {
      temp=k[min];
      k[min]=k[i];
      k[i]=temp;
    }
  }
}  
int main()
{
  int i,a[10]={5,2,6,0,3,9,1,7,4,8};
  SelectSort(a,10);
  printf("排序后的结果是:");
  for(i=0;i<10;i++)
  {
    printf("%d ",a[i]);
  }
  printf("\n");
  return 0;
}

3,直接插入排序

要点:
直接插入排序算法的基本操作是将一个记录插入到已经排好的有序表中,从而得到一个新的,记录数增加1的有序表。
代码实现:

#include
void InsertSort(int k[],int n)
{
  int i,j,temp;
  for(i=1;i<n;i++)
  {
    if(k[i]<k[i-1])
    {
      temp=k[i];
      for(j=i-1;k[j]>temp;j--)
      {
        k[j+1]=k[j];
      }
      k[j+1]=temp;
    }
  }
}
int main()
{
  int i,a[10]={5,2,6,0,3,9,1,7,4,8};
  InsertSort(a,10);
  printf("排序后的结果是:");
  for(i=0;i<10;i++)
  {
    printf("%d ",a[i]);
  }
  printf("\n");
  return 0;
}

4,希尔排序

要点:
希尔排序又称缩小增量排序法,是直接插入排序的改进,是一种基于插入思想的排序方法,它利用了直接插入排序的最佳性质,首先,将待排序的关键字序列分成若干个较小的子序列,对子序列直接进行插入排序,使整个待排序序列排好序。在时间耗费上,较直接插入排序法的性能有较大的改进。

算法思想
先将待排序记录序列分割成若干个“较稀疏的”子序列,分别进行直接插入排序。经过上述粗略调整,整个序列中的记录已经基本有序,最后再对全部记录进行一次直接插入排序。①首先选定记录间的距离为di(i=1),在整个待排序记录序列中将所有间隔为d1的记录分成一组,进行组内直接插入排序。

②然后取i=i+1,记录间的距离为di(di<di-1),在整个待排序记录序列中,将所有间隔为di 的记录分成一组,进行组内直接插入排序。

重复步骤②多次,直至记录间的距离di=1,此时整个只有一个子序列,对该序列进行直接排序,完成整个排序过程。
代码实现:

#include
void InsertSort(int k[],int n)
{
  int i,j,temp;
  int gap=n;
  do
  {
    gap=gap/3+1;
  for(i=gap;i<n;i++)
  {
    if(k[i]<k[i-gap])
    {
      temp=k[i];
      for(j=i-gap;k[j]>temp;j-gap)
      {
        k[j+gap]=k[j];
      }
      k[j+gap]=temp;
    }
  }
  }while(gap>1);
}
int main()
{
  int i,a[10]={5,2,6,0,3,9,1,7,4,8};
  InsertSort(a,10);
  printf("排序后的结果是:");
  for(i=0;i<10;i++)
  {
    printf("%d ",a[i]);
  }
  printf("\n");
  return 0;
}

5,堆排序

要点
堆排序是在排序过程中,将向量中存储的数据看成一棵完全二叉树,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择关键字最小的记录,即待排序记录任采用向量数组的方式存储,并非采用树的存储结构,而仅仅是采用完全二叉树的顺序结构的特征进行分析而已。

基本思想

堆排序的过程需要解决两个问题:一是堆定义建立初堆;二是去掉最大元之后重建堆,得到次大元,依次类推。
首先将待排序的序列构造成一个大定顶堆(或小顶堆);此时,整个序列的最大值就是堆顶的根结点。将它移走(就是将其与堆数组的末尾元素互换,此时末尾元素就是最大值);然后,将剩余的n-1 个序列重新构造成一个堆,这样就会得到 n 个元素的次大值;最后反复执行,便能得到一个有序序列了。

代码实现

#include
void swap(int k[],int i,int j)
{
  int temp;
  temp=k[i];
  k[i]=k[j];
  k[j]=temp;
}
void HeapAdjust(int k[],int s,int n)
{
  int i,temp;
  temp=k[s];
  for(i=2*s;i<=n;i*=2)
  {
    if(i<n&&k[i]<k[i+1])
    {
      i++;
    }
    if(temp>=k[i])
    {
      break;
    }
    k[s]=k[i];
    s=i;
  }
  k[s]=temp;
}
void HeapSort(int k[],int n)
{
  int i;
  for(i=n/2;i>0;i--)
  {
    HeapAdjust(k,i,n);
  }
  for(i=n;i>1;i--)
  {
    swap(k,1,i);
    HeapAdjust(k,1,i-1);
  }
}
int main()
{
  int i,a[10]={-1,5,3,6,7,8,9,0,4,2};
  HeapSort(a,9);
  printf("排序后的结果是:")for(i=1;i<10;i++)
  {
    printf("%d",a[i]);
  }
  printf("\n");
  return 0;
}

总结

知识在于积累,学习需要耐力。学习就像挖金矿,或许一开始毫无头绪,一头雾水,但换个角度,换换工具,时间久了总会找到一个缝隙。成功就是你比别人多走了一段路,或许是那么一小步。

你可能感兴趣的:(c&c++,数据结构,数据结构,算法)