Fork me on GitHub

《数据结构与算法分析》学习笔记-第一章-引论

自述

自从工作之后,就没有再写博客了,一方面是因为自己初入职场还不能很好的适应职场生活。另一方面也是对前途有些不知所措。现在工作已经快三年了,我慢慢找到了自己的节奏,也许还是有很多不成熟的地方,但是我已经想开啦。做自己真正喜欢的事就好了,遵循自己的内心。在职场的这些年我写了很多笔记,但是没有时间整理出来,后面慢慢都会发表出来分享给大家。感觉自己在技术上还是有很多不足,有很多基础的东西掌握的还是不好呀。所以想踏踏实实的重新学习这些基本知识。包括C语言基础、数据结构与算法、操作系统。还希望能更进一步,掌握python、java。学习并整理设计模式、网络、文件系统、内存管理、多线程开发等等。请大家敬请期待吧。好了,话不多说。
我,CrazyCatJack又回来啦!

1.1 本书讨论的内容

  • 一个可以运行的程序并不够,如果在巨大的数据集运行,运行时间就变成了相当重要的问题。
  • 学习如何估计程序的运行时间,尤其是在未编码的情况下预估两个算法的运行时间。
  • 学习彻底改进程序速度和确定程序瓶颈的方法,这些方法使我们能够找到需要大力优化的代码段

书上上来就提出了一个算法问题,并提出了两个解决方案,我实现了具体的代码,大家可以尝试将这两个文件编译后,查看打印了解具体的执行过程。还可以在linux命令行下使用time ./a.out 命令查看两个程序的执行时间,进行比较。我将代码上传到了github上。https://github.com/CrazyCatJack/structureAlgorithm

设有一组N个数而要确定其中第K个最大的数。两种方法实现如下:

  • 法1:将N个数读进一个数组,再通过冒泡排序进行递减排序,最后返回k位置上的元素
// SPDX-License-Identifier: GPL-2.0-only
/*
 * sort1.c
 *
 * Copyright (C) 2020 xuri.All rights reserved.
 */
 
#include <stdio.h>
#define ARRAY_SIZE 1000
#define MAXKNUM	500

int sortK(int *array, int arraySize, int MaxKnum)
{
	if (array == NULL || arraySize <= 0 || MaxKnum <= 0) {
		return -1;
	}

	int subscript, sortTimes;
	for (sortTimes = 0; sortTimes < arraySize - 1; sortTimes++) {
		for (subscript = 1; subscript < arraySize - sortTimes; subscript++) {
			if (array[subscript] > array[subscript - 1]) {
				int temp;
				temp = array[subscript];
				array[subscript] = array[subscript - 1];
				array[subscript - 1] = temp;
			}
		}
#if 0
		printf("NO %d sort:", sortTimes); 
		int prtCnt;
		for (prtCnt = 0; prtCnt < arraySize; prtCnt++) {
			printf("%d ", array[prtCnt]);
		}
		printf("\n"); 
#endif
	}

	return array[MaxKnum - 1]; 
}

void main()
{
	int array[ARRAY_SIZE];
	int assignCnt;
	for (assignCnt = 0; assignCnt < ARRAY_SIZE; assignCnt++) {
		array[assignCnt] = assignCnt;
	}
	int K = sortK(array, ARRAY_SIZE, MAXKNUM);
	printf("K = %d\n", K);	
}
  • 法2:可以先把前K个元素读入数组并以递减的顺序进行排序。再将剩下的元素逐个读入,用新元素与当前数组中第K个元素进行比较,如果它小于则忽略,如果它大于,则将它放到数组中正确的位置上,同时挤出一个元素。当算法终止,第k个元素就是正确答案
// SPDX-License-Identifier: GPL-2.0-only
/*
 * sort2.c
 *
 * Copyright (C) 2020 xuri.All rights reserved.
 */
 
#include <stdio.h>
#define ARRAY_SIZE 1000
#define MAXKNUM	500

void MaoPaoSort(int *localArray, int MaxKnum)
{
	int subscript, sortTimes;
	for (sortTimes = 0; sortTimes < MaxKnum - 1; sortTimes++) {
		for (subscript = 1; subscript < MaxKnum - sortTimes; subscript++) {
			if (localArray[subscript] > localArray[subscript - 1]) {
				int temp;
				temp = localArray[subscript];
				localArray[subscript] = localArray[subscript - 1];
				localArray[subscript - 1] = temp;
			}
		}
#if 0
		printf("NO %d sort:", sortTimes); 
		int prtCnt;
		for (prtCnt = 0; prtCnt < MaxKnum; prtCnt++) {
			printf("%d ", localArray[prtCnt]);
		}
		printf("\n"); 
#endif
	}
}

int sortK(int *array, int arraySize, int MaxKnum)
{
	if (array == NULL || arraySize <= 0 || MaxKnum <= 0) {
		return -1;
	}

	// assign MaxKnum number in localArray
	int localArray[MaxKnum];
	int assignCnt;
	for (assignCnt = 0; assignCnt < MaxKnum; assignCnt++) {
		localArray[assignCnt] = array[assignCnt];
	}
	
	// sort localArray
	MaoPaoSort(localArray, MaxKnum);

	// get remain number in array add to in localArray for sort
	for (assignCnt = MaxKnum; assignCnt < arraySize; assignCnt++) {
		if (array[assignCnt] > localArray[MaxKnum - 1]) {
			int temp = 0;
			temp = array[assignCnt];
			array[assignCnt] = localArray[MaxKnum - 1];
			localArray[MaxKnum - 1] = temp;
			MaoPaoSort(localArray, MaxKnum);
		}
	}

	return localArray[MaxKnum - 1]; 
}

void main()
{
	int array[ARRAY_SIZE];
	int assignCnt;
	for (assignCnt = 0; assignCnt < ARRAY_SIZE; assignCnt++) {
		array[assignCnt] = assignCnt;
	}
	int K = sortK(array, ARRAY_SIZE, MAXKNUM);
	printf("K = %d\n", K);	
}

1.2 数学知识复习

因为数学格式很难打出来,所以干脆手写啦,这里委屈大家看我的丑字了-_-||
好记性不如烂笔头,CCJ也建议大家亲自演算一下,自己演算出来的才算是自己的东西。





1.2.5 证明方法

1)归纳法

  1. 基准情形:确定某些小值得正确性
  2. 归纳假设:假设定理对于小于有限数k的所有情况成立,用这个定理证明k+1也是成立的

2) 反证法

通过假设定理不成立,然后证明该假设导致某个已知的性质而不成立,从而说明原假设是错误的




1.3 递归简论

  1. 当一个函数用它自己来定义时,就称为是递归的。不是所有的数学递归函数都能有效的(或正确的)由C的递归模拟来实现。
  2. C中的递归函数若无基准情况,也是毫无意义的
  3. 跟踪挂起的函数调用(即这些调用已经开始但是正等待着递归调用来完成)以及它们中变量的记录工作都是由计算机自动完成的。递归调用将反复进行直到基准情形出现
  4. 递归组成
    • 基准情形:不用递归就能求解的情形
    • 不断推进:对于需要递归求解的情形,递归调用必须总能朝着产生基准情形的方向推进
    • 设计法则:假设所有的递归调用都能运行。不必追踪所有的递归调用,很困难且没必要。使用递归能简化算法设计并设计出简洁的代码
    • 合成效益法则: 在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性的工作。例如计算斐波那契数列用递归就不是很好的选择
// 本书例程
#include <stdio.h>

int F(int x)
{
    if (0 == x) {
        return 0;
    } else (0 > x) {
        return (2 * F(x-1) + x * x);
    }
}

void main()
{
    printf("F(1)=%d, F(2)=%d, F(3)=%d\n", F(1), F(2), F(3));
}

打印输出数

// 本书例程
#include <stdio.h>

int printDigit(int x)
{
        if (x >= 10) {
                printDigit((x / 10));
        }
        printf("%d", (x % 10));
}

void main()
{
        int a = 123456789;
        printDigit(a);
}

敬告:

本文原创,欢迎大家学习转载_

转载请在显著位置注明:

博主ID:CrazyCatJack

原始博文链接地址:https://www.cnblogs.com/CrazyCatJack/p/12545591.html


第一章到此结束,接下来会进行课后习题的讲解。希望能给正在学习数据结构与算法的朋友带来帮助。我们一起来构筑一个更好的世界!
觉得好的话请帮忙点个推荐,谢谢大家的支持!嘿嘿~

CrazyCatJack
posted @ 2020-03-24 23:35  CrazyCatJack  阅读(694)  评论(0编辑  收藏  举报