时间复杂度表达的是代码执行时间随数据规模增长的变化趋势。
时间复杂度分析:
O(1)表示代码执行时间不会随着n的变化而变化,无论n多大;只要代码中不存在循环语句和递归语句;即为O(1);
O(logn)分析:
i=1;
while(i i=i*2; } 算代码的执行次数,即2的x次方为n的时候停止计算,那么x=log2N,故复杂度为O(log2N);不用管底数是什么,所有的复杂度都是O(logn);为什么呢?因为对数都是可以互相转换的, log3N=log32*log2N,所以O(log3N)=O(C*log2N),其中C为常数,可以忽略系数;按照乘法法则可以计算出O(nlogn); O(m+n):有两个输入的数据时,加法法则不再适用,但是乘法依然可以; 空间复杂度表示算法的存储空间与数据规模之间的增长关系; 常见的空间复杂度是O(1) O(n) O(n2) question:为什么数组下标从0开始计算? answer:下标的定义是相对于首地址的偏移量offset,否则在计算的过程中CPU会多一次减法的运算; 寻址方式:a[k]_address = base_address + k * type_size Topic:GCC中的编译器堆栈保护技术 栈区的增长方向是从高地址到低地址-栈顶地址<栈底地址; question:循环链表解决约瑟夫问题? answer:https://blog.csdn.net/wenhai_zh/article/details/9620847(c语言) question:数组与链表的选择? answer:以空间换时间或者以时间换空间。 数组为连续存储空间,可以借助CPU缓存机制预读数据,访问效率高; (解释:CPU在从内存读取数据的时候,会先把读取到的数据加载到CPU的缓存中。而CPU每次从内存读取数据并不是只读取那个特定要访问的地址,而是读取一个数据块,并保存到CPU缓存中,然后下次访问内存数据的时候就会先从CPU缓存开始查找,如果找到就不需要再从内存中取。这样就实现了比内存访问速度更快的机制,也就是CPU缓存存在的意义:为了弥补内存访问速度过慢与CPU执行速度快之间的差异而引入。) 链表在内存中不是连续存储,对链表进行频繁额插入删除操作,会导致频繁的内存申请和释放,容易产出内存碎片,java中容易GC。 Java中ArrayList虽然支持动态扩容,但是数据需要重新拷贝消耗时间; question:反转单链表问题? answer: https://blog.csdn.net/fx677588/article/details/72357389 question:回文链表问题? answer:1.利用快慢指针找到中点 question:快慢指针问题 answer: https://www.cnblogs.com/songdechiu/p/6686520.html https://blog.csdn.net/l294265421/article/details/50478818 http://www.cnblogs.com/xudong-bupt/p/3667729.html 思想:先找到相遇点; question:写链表代码的技巧 answer: 1.理解指针和引用,实际的意义就是存储所指对象的内存地址; p->next=q p节点中的next指针存储了q节点的内存地址; 2.警惕指针丢失和内存泄露 插入节点的时候需要注意操作的顺序,警惕next的指向地址发生变化; 3.利用哨兵简化实现难度(引入哨兵节点) 当插入头结点和删除尾节点的时候代码需要注意;哨兵节点不存储数据,head时钟指向哨兵节点 4.重点留意边界位置 栈的应用-函数调用栈 操作系统给每个线程分配了一块独立的内存空间,这块内存被组织成栈结构,用来存储函数调用时的临时变量。没进入一个函数,就会将临时变量作为一个栈帧入栈,当被调用函数执行完成,返回后,这个函数对应的栈帧出栈。 栈的应用-表达式求值的应用 栈的应用-括号匹配中的应用 question:向固定大小线程池中请求一个线程时,如果线程没有空闲资源,如何处理请求,排队还是拒绝? answer:策略一:非阻塞处理方式,直接拒绝任务请求; 策略二:请求排队,先进者先服务 question:对比基于链表和基于数组的实现方式 answer:基于链表支持无限排队的无界队列,但是可能导致过多的请求排队等待,请求处理时间长;基于数组的队列代销有限,当超过数组大小时请求会被拒绝。 队列:操作受限的线性表数据结构 去的过程叫做递,回来的过程叫做归。 满足递归的三个条件: attention:递归要避免堆栈溢出; 通过限制递归调用最大深度的方式(在最大深度较小的情况下可以使用); attention:递归代码要避免重复计算; 可以通过数据结构表(例如散列表)来保存求解过的值 归并排序采用分治合成的思想,复杂度O(nlogn)但不是原地算法,需要额外的空间,所以适用于小数据量; 快排更适合大数据量; 复杂度为线性的O(n),不涉及比较的操作。桶排序,计数排序,基数排序。 针对快速排序——因为选择点的原因,最差情况为O(n2),可以采用分区算法; 1. 三数取中法; 2. 随机发; 局限性:顺序列表依赖数组;针对有序数据;数据量太小不适合;数据量太大因为空间不连续也不适合; 二分法和牛顿迭代求平方根“: 课程5:
课程6 and 7: 链表
//判断是否为回文链表
public static boolean isPalindrome(Node head) {
Node slow = head;
Node fast = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
fast = head;
slow = reverseList(slow);
while(slow != null) {
if(fast.data != slow.data) {
return false;
}
slow = slow.next;
fast = fast.next;
}
return true;
}
课程8:栈
课程9:队列
课程10:递归Recursion
课程12:归并排序与快速排序
// 递归调用函数
private static void mergeSortInternally(int[] a, int p, int r) {
// 递归终止条件
if (p >= r) return;
// 取p到r之间的中间位置q,防止(p+r)的和超过int类型最大值
int q = p + (r - p)/2;
// 分治递归
mergeSortInternally(a, p, q);
mergeSortInternally(a, q+1, r);
// 将A[p...q]和A[q+1...r]合并为A[p...r]
merge(a, p, q, r);
}
private static void merge(int[] a, int p, int q, int r) {
int i = p;
int j = q+1;
int k = 0; // 初始化变量i, j, k
int[] tmp = new int[r-p+1]; // 申请一个大小跟a[p...r]一样的临时数组
while (i<=q && j<=r) {
if (a[i] <= a[j]) {
tmp[k++] = a[i++]; // i++等于i:=i+1
} else {
tmp[k++] = a[j++];
}
}
// 判断哪个子数组中有剩余的数据
int start = i;
int end = q;
if (j <= r) {
start = j;
end = r;
}
// 将剩余的数据拷贝到临时数组tmp
while (start <= end) {
tmp[k++] = a[start++];
}
// 将tmp中的数组拷贝回a[p...r]
for (i = 0; i <= r-p; ++i) {
a[p+i] = tmp[i];
}
}
def quick_sort(array, left, right):
if left < right:
index = partion(array, left, right)
quick_sort(array, left, index)
quick_sort(array, right, index + 1)
def partition(array, left, right):
key = array[left]
while left < right:
while left < right and array[right] >= key:
right-=1
if left < right:
array[left] = array[right]
while left < right and array[left] <= key:
left+=1
if left < right:
array[right] = array[left]
array[left] = key
return left
课程13:线性排序
课程14:排序的优化
课程15-16:二分法
// 二分查找的递归实现
public int bsearch(int[] a, int n, int val) {
return bsearchInternally(a, 0, n - 1, val);
}
private int bsearchInternally(int[] a, int low, int high, int value) {
if (low > high) return -1;
int mid = low + ((high - low) >> 1);//这里注意优先级以及不能直接加数据溢出的问题
if (a[mid] == value) {
return mid;
} else if (a[mid] < value) {
return bsearchInternally(a, mid+1, high, value);
} else {
return bsearchInternally(a, low, mid-1, value);
}
}
def sqrt_binary(num):
x=sqrt(num)
y=num/2.0
low=0.0
up=num*1.0
count=1
while abs(y-x)>0.00000001:
print count,y
count+=1
if (y*y>num):
up=y
y=low+(y-low)/2
else:
low=y
y=up-(up-y)/2
return y
def sqrt_newton(num):
x=sqrt(num)
y=num/2.0
count=1
while abs(y-x)>0.00000001:
print count,y
count+=1
y=((y*1.0)+(1.0*num)/y)/2.0000
return y
---------------------
作者:ycf74514
来源:CSDN
原文:https://blog.csdn.net/ycf74514/article/details/48996383
版权声明:本文为博主原创文章,转载请附上博文链接!