diff --git a/a.out b/a.out
new file mode 100755
index 0000000..0cf0c21
Binary files /dev/null and b/a.out differ
diff --git a/a.out.dSYM/Contents/Info.plist b/a.out.dSYM/Contents/Info.plist
new file mode 100644
index 0000000..3679a65
--- /dev/null
+++ b/a.out.dSYM/Contents/Info.plist
@@ -0,0 +1,20 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleIdentifier
+ com.apple.xcode.dsym.a.out
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ dSYM
+ CFBundleSignature
+ ????
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+
+
diff --git a/a.out.dSYM/Contents/Resources/DWARF/a.out b/a.out.dSYM/Contents/Resources/DWARF/a.out
new file mode 100644
index 0000000..fb793ef
Binary files /dev/null and b/a.out.dSYM/Contents/Resources/DWARF/a.out differ
diff --git a/thread.c b/thread.c
new file mode 100644
index 0000000..6dd0a64
--- /dev/null
+++ b/thread.c
@@ -0,0 +1,71 @@
+
+
+#include "stdio.h"
+#include "pthread.h"
+
+pthread_mutex_t mutex;
+pthread_cond_t condition;
+
+unsigned int i = 0;
+
+void *threadFunc1(void *arg){
+
+ pthread_mutex_lock(&mutex);
+ pthread_cond_wait(&condition,&mutex);
+ pthread_mutex_unlock(&mutex);
+
+ printf("aaaaaaa %d\n",i);
+ pthread_exit((void *)0);
+
+}
+
+
+void *threadFunc2(void *arg){
+
+ pthread_mutex_lock(&mutex);
+ pthread_cond_wait(&condition,&mutex); //??? 这里人存在问题
+ pthread_mutex_unlock(&mutex);
+
+ printf("vbbbbbbbbbb %d\n",i);
+ pthread_exit((void *)0);
+
+}
+
+
+int main(int argc, char const *argv[])
+{
+
+ pthread_mutex_init(&mutex,NULL);
+ pthread_cond_init(&condition,NULL);
+
+ pthread_t thread1,thread2;
+ pthread_create(&thread1,NULL,threadFunc1,(void *)0);
+ pthread_create(&thread2,NULL,threadFunc2,(void *)0);
+
+ while(1){
+
+ pthread_mutex_lock(&mutex);
+ i++;
+ pthread_mutex_unlock(&mutex);
+
+ if (i==100000000)
+ {
+ //
+ pthread_cond_broadcast(&condition);
+ break;
+
+ }
+
+ }
+
+ pthread_join(thread1,NULL);
+ pthread_join(thread2,NULL);
+
+ pthread_cond_destroy(&condition);
+ pthread_mutex_destroy(&mutex);
+
+
+ return 0;
+}
+
+
diff --git a/多线程.md b/多线程.md
index 7f6dbeb..db1f739 100644
--- a/多线程.md
+++ b/多线程.md
@@ -1,27 +1,160 @@
-多线程有几种实现方法,都是什么?
+### 多线程有几种实现方法,都是什么?
+
+OC中:
+Thread: 使用简单方便,但效率不及下面的几种方式
+NSOperationQueue:可以对thread的状态做精确的控制,gcd做不到
+GCD: 效率做好的方案,且结合block,使用方便
+pthread OS提供的api
+
+
+
+### 多线程同步和互斥有几种实现方法,都是什么?
+
+首先理解线程`同步`和`互斥`的概念。
+
+`同步` 在一个功能调用时,如果没有得到结果,调用就不返回
+
+`死锁` 2个线程访问共享资源,顺序不当造成的。如一个线程锁定了资源A,想访问另一个线程锁定的资源B,而这个线程又在等待A资源。
+
+`线程同步` 线程A和B一块配合,A执行到一定程度需要拷B的结果,于是停下来,等待B的指向结果。
+
+1. 临界区: 任意时刻只允许一个线程访问共享资源
+2. 互斥量: 拥有互斥对象的线程才能访问公共资源
+3. 信号量: 允许多个线程同时访问统一资源??
+4. 事件 : ?
+
+
+结合代码来看看 linux上 3种 线程同步的方式:
+
+#### 互斥锁
+
+pthread_mutex_t
+pthread_mutex_init()
+pthread_mutex_lock() // 在访问共享资源时,加锁,这样别的线程无法访问
+pthread_mutex_unlock() // 解锁,这样别的线程可以访问共享资源了
+pthread_mutex_destroy()// 释放互斥锁
+
+
+互斥锁是如何通知到等待锁的线程的?
+
+我猜内核会维护一个 互斥量对多个等待线程(1对多) 的表,在互斥量解锁后,采用某种方式选择一个等待线程唤醒,让其获得互斥锁,如此往复,直到所有等待线程唤醒执行。(具体待参加linux/kernel/mutex.c)
+
+
+#### 条件变量
+
+条件变量用来等待,阻塞一个线程,等待某个条件发生时触发。条件变量与互斥锁同时使用.
+
+条件变量和互斥量相关联 是一种用于 多线程之间共享数据状态改变的通信机制。
+
+pthread_cond_init()
+pthread_cond_destroy()
+pthread_cond_wait(cond,mutex) // 条件测试为假,线程就会阻塞;
+pthread_cond_signal() // 给出“条件成立”信号
+pthread_cond_broadcast()
+
+
+以生产者消费者问题为例,消费线程在得知队列中没有产品时,将阻塞自己;
+生产者线程生产产品后,没有办法激活消费线程,这个时候生产者还要继续运行生产产品,不能用互斥量来实现;如果消费线程采用轮询的方式,无疑又是对CPU的浪费;最好的方式还是生产线程来唤醒消费线程;
+
+那生产线程如何唤醒另一个线程呢?
-多线程同步和互斥有几种实现方法,都是什么?
+条件变量本身是需要互斥量来保护的,也就是条件的检查实在互斥锁的保护下进行的。 因此pthread_cond_wait(cond,mutex)函数中,传递了一个mutex互斥量用来锁住cond条件变量
+
+
+iOS中又NSCondition
+
+ - wait
+ - signal
+ - broadcast
+
+NSCondition 还实现了 NSLocking协议
+ - lock
+ - unlock
+#### 信号量
+又叫 `信号灯`,本质上是一个计数器。
+
+sem_t
+sem_init() // 初始化一个信号量,需要指定允许的最大资源计数。如果这里最大计数为1,跟互斥量类似了。
+sem_wait() // 给信号量-1 , 如果信号量任然>=0,线程可以继续指向,否则等待
+sem_post() // 给信号量+1
+sem_destroy() // 销毁信号量
-互斥量与临界区比较
+可以理解为,`互斥量` 是 `信号量` 的一种特殊情况(max_sem_count==1)
+
+看下信号量的结构(/usr/src/linux/include/linux/sem.h)
+struct semaphore {
+ spinlock_t lock; // 用来确保对count成员的原子操作
+ unsigned int count;
+ struct list_head wait_list;// 在信号量+1,给wait的线程或进程发送信号量
+};
-生产者消费者问题
+`线程互斥` : 某一资源同时只允许一个访问者访问。上面介绍的 `互斥量` `临界区` 都可以实现线程的互斥
+### 怎么避免死锁?(经验)
+
+A线程
+@synchronized(lockobj){
+ while([datas count==0){...}
+}
+
+B线程
+@synchronized(lockobj){
+ [datas addObject:[Item new]];
+}
+
+A线程一直在while循环上等待,但是B线程有无法获得lockobj锁而等待出现死锁。解决办法是用NSLock来替换@synchronized(lock),在while()中
+
+1). 在使用锁的程序中,不要在程序中间使用return(这个时候还没有解锁,就可能会造成死锁), 而使用goto函数跳转至解锁并退出函数的位置
-多线程同步问题
+1. 线程重排序reordering thread
+2. minimize locking
+3. a bigger loc
+4. try lock
+5. time out for locking
+
+
+
+### 互斥量与临界区比较?
+
+互斥量比临界区复杂,临界区只能完成统一进程内线程直接的同步,互斥量可以实现不同进程的线程的同步,可以跨进程使用。
+
+互斥量,信号量,事件都可以跨进程访问
+
+
+
+### 生产者消费者问题
+
+生产者和消费者之间通常有一个缓冲区作为中介。这个缓冲区有以下作用:
+1. 解耦合
+2. 让 生产者 和 消费者 并发执行
+3. 支持忙闲不均
+
+队列缓冲区
+环形缓冲区
+
+
+
+### 读者写者问题
+这也是一个非常经典的多线程题目,题目大意如下:有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。
+
+
+
+### 几个多线程面试题目
+
主线程启动10个子线程并将表示子线程序号的变量地址作为参数传递给子线程。子线程接收参数 -> sleep(50) -> 全局变量++ -> sleep(0) -> 输出参数和全局变量。
要求:
@@ -30,12 +163,6 @@
-读者写者问题
-这也是一个非常经典的多线程题目,题目大意如下:有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者读时写者也不能写。
-
-
-
-
编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推。
diff --git a/排序算法/README.md b/排序算法/README.md
index ee32828..2139266 100644
--- a/排序算法/README.md
+++ b/排序算法/README.md
@@ -1,4 +1,6 @@
+
+
## 排序算法
**排序的稳定性** 对于相等的元素,排序之后,任然保存2个元素的位置没有变,就是稳定的排序,反之就是不稳定排序。
@@ -19,10 +21,10 @@
递归一次,pivot 左边都比它小,右边都比它大。这是递归,分治的思想。
-对 A[p...r] :
-1. 分解:A[p..q-1] A[q+1..r],使得 A[p...q-1]= a[max])
+ {
+ break;
+ }
+ else
+ {
+ heap_swop(&a[tmp],&a[max]);
+ tmp = 2*tmp+1;
+ }
+
+ }
+
+}
+
+
+// 从第一个非叶子节点a[(length-2)/2],开始做调整, 跟自己的子节点比较,把最大的孩子换上来就是创建最大堆,
+//反之,把最小的孩子换上来就是创建最小堆 一直到a[0]
+void heap_build(int *a,int length){
+
+
+ for (int i = (length-2)/2; i >=0 ; --i)
+ {
+ // 三个数里取最大的一个 a[i],a[2i+1],a[2i+2],跟a[i]交换;然后是 a[(i-1)/2],a[i],a[i+1] .. 一直到a[0]
+ heap_public_adjust(a,i,length);
+
+ }
+
+}
+
+// 自顶向下调整
+void heap_adjust(int *a,int length){
+
+ heap_public_adjust(a,0,length); //对0号调整
+}
+
+
+void heap_sort(int *a, int length){
+
+ // 建立堆 大根堆,递增排序
+ heap_build(a,length);
+
+ for (int i = length-1; i >0; --i)
+ {
+ //交换
+ heap_swop(&a[0],&a[i]);
+
+ //调整
+ heap_adjust(a,i);
+ }
+
+}
+
+///////////////////////////////////////////////
+
+
+#define Max_Number 50
int main(){
- //int a[] = {4,87,2,32,5,41,2,9};
+ int a[] = {4,87,2,32,5,2,9,49,49,23,45,2,41};
// 准备5000个数
- int a[Max_Number];
- for (int i = 0; i < Max_Number; ++i)
- {
- a[i]=rand()%Max_Number;
- }
+ // int a[Max_Number];
+ // for (int i = 0; i < Max_Number; ++i)
+ // {
+ // a[i]=rand()%Max_Number;
+ // }
clock_t start,finish;
start = clock();
-
+ heap_sort(a,sizeof(a)/sizeof(int)); // 有buggggggg
//quicksort(a,0,sizeof(a)/sizeof(int)-1); // 0.01s
//insert_sort(a,sizeof(a)/sizeof(int)); // 3.85s
//select_sort(a,sizeof(a)/sizeof(int)); // 5.3s
diff --git a/算法分析思路/README.md b/算法分析思路/README.md
index d3d2def..c626085 100644
--- a/算法分析思路/README.md
+++ b/算法分析思路/README.md
@@ -4,10 +4,10 @@
是一种不断用旧值递推新值的过程,分精确迭代和近视迭代。是用来求方程和方程组近似根的方法。
-迭代变量
-迭代关系, 迭代关系选择不合理,会导致迭代失败
-迭代过程控制,也就是迭代什么时候结束,不能无休止进行下去
-
+迭代变量
+迭代关系, 迭代关系选择不合理,会导致迭代失败
+迭代过程控制,也就是迭代什么时候结束,不能无休止进行下去
+
@@ -38,17 +38,17 @@
在 `递推` 阶段,将大的问题分解成小的问题
在 `回归` 阶段,获得最简单问题的解后,逐级返回,依次得到稍微复杂情况的解,知道获得最终的结果
-1) 确定递归公司
-2) 确定边界条件
+1) 确定递归公司
+2) 确定边界条件
如
-斐波那契数列 fib(n)=fib(n-1)+fib(n-2)
-阶乘计算
-梵塔问题 (三根针1,2,3表示,1号从小到大n个盘子,先要都移到3号上,不能出现大盘压小盘,找出移动次数最少的方案)
-快速排序
-
+斐波那契数列 fib(n)=fib(n-1)+fib(n-2)
+阶乘计算
+梵塔问题 (三根针1,2,3表示,1号从小到大n个盘子,先要都移到3号上,不能出现大盘压小盘,找出移动次数最少的方案)
+快速排序
+
递归运行效率较低,因为有函数调用的开销,递归多次也可能造成栈溢出。
@@ -80,7 +80,7 @@
案例:
-迷宫问题
+迷宫问题
@@ -92,10 +92,10 @@
-案例
-找回零钱问题
-装箱问题
-赫夫曼编码
+*案例*
+找回零钱问题
+装箱问题
+赫夫曼编码
@@ -106,15 +106,15 @@
将一个难以直接解决的大问题,分割成一些规模较小的相同问题,各个击破,分而治之。
分治算法常用递归实现
-1) 问题缩小的小规模可以很容易解决
-2) 问题可以分解为规模较小相同问题
-3) 子问题的解可以合并为该问题的解
-4) 各个子问题相互独立,(如果这条不满足,转为`动态规划`求解)
-
+1) 问题缩小的小规模可以很容易解决
+2) 问题可以分解为规模较小相同问题
+3) 子问题的解可以合并为该问题的解
+4) 各个子问题相互独立,(如果这条不满足,转为`动态规划`求解)
+
分治法的步骤:
-1. 分解
-2. 解决
-3. 合并
+1. 分解
+2. 解决
+3. 合并
以 `大整数乘法` 为例
@@ -122,10 +122,10 @@
如 26542123532213598*345987342245553677884
-案例:
-快速排序
-归并排序
-最大子数组和
+*案例*
+快速排序
+归并排序
+最大子数组和