算法与数据结构基础
一、基础算法思想
二分:
while(guess != price) {
if(guess > price) printf("high\n");
else if(guess < price) printf("low\n");
printf("please guess again\n");
scanf("%d",&guess);
count++;
}
递推:
for(int i = 2;i < 24;i++)
fab[i] = fab[i-1] + fab[i-2];
枚举:
for(i1 = 1;i1 < 10;i1++)
for(i2 = 0;i2 < 10;i2++)
for(i3 = 0;i3 < 10;i3++)
for(i4 = 0;i4 < 10;i4++)
for(i5 = 0;i5 < 10;i5++)
{
count = i1*10000 + i2*1000 + i3*100 + i4*10 +i5;
if(count * i1 = i5 *111111) printf("%d %d %d %d %d\n",i1,i2,i3,i4,i5);
递归:
int main(){
int i;
scanf("&d",&i);
printf("%d fact is:%d\n",i,fact(i));
return 0;
}
int fact(int n){
if(n <= 1) return 1;
else return n*fact(n-1);
}
分治:
void gamecal(int k,int n) {
int i,j;
if(n == 2) {
a[k][1] =k;
a[k][2] = k+1;
a[k+1][1] = k+1;
a[k+1][2] = k;
} else {
gamecal(k,n/2);
gamecal(k+n/2,n/2);
for(i=k;i
贪心:
int exchange(int n){
int i,j;
for(i=0;iparvalue[i]) break;
while(n>0 && i=parvalue[i]){
n -= parvalue[i];
num[i]++;
} else if(n<10 && n>=5)
{
num[MAXN-1]++;
break;
}
return 0;
}
试探:
int main(){
int i[7],j;
for(i[0]=1;i[0]<30;i[0]++){
for(i[1]=1;i[1]<30;i[1]++){
if(i[0] == i[1] ) continue;
for(i[2]=1;i[2]<30;i[2]++){
if(i[0]==i[2] || i[1] == i[2]) continue;
......
for(j=0;j<7;j++)
printf("%3d",i[j]);
printf("\n");
}}}
模拟:
srand(time(NULL));
r=rand()%6 + 1;
二、简单数据结构
线性表:
typedef struct{
char key[15];
char name[20];
int age;
}DATA;
typedef stuct Node{
DATA data;
struct Node* next;
}ChainListType;
ChainListType* ChainListAddEnd(ChainListType* head,DATA data){
ChainListType *node,*h;
if(!(node=(ChainListType*)malloc(sizeof(ChainListType)))){ printf("erron\n"); return NULL;}
node->data = data;
node-next = NULL;
if(head == NULL){ head=node;return head;}
h=head;
while(h->next != NULL) h=h->next;
h->next = node;
return head;
}
ChainListType* ChainListAddFirst(ChainListType* head,DATA data){
ChainListType *node,*h;
if(!(node=(ChainListType*)malloc(sizeof(ChainListType)))){ printf("error\n"); return NULL;}
node->data = data;
node->next = head;
head = node;
return head;
}
ChainListType* ChainListInsert(ChainListType* head,char* findkey,DATA data){
ChainListType *node,*node1;
if(!(node=(ChainListType*)malloc(sizeof(ChainListType)))){ printf("error\n"); return NULL; }
node->data = data;
node1 = ChainListFind(head,findkey);
if(node1) { node->next = node1->next; node1->next = node; }
else { free(node); printf("unfind the position\n"); }
return head;
}
ChainListType* ChainListFind(ChainListType* head,char* key){
ChainListType *h;
h=head;
while(h){
if(strcmp(h->data.key,key) == 0) return h;
h=h->next;
}
return NULL;
}
int ChainListDelete(ChainListType* head,char* key) {
ChainListType *node,*h;
node = h = head;
while(h){
if(strcmp(h->data.key,key) == 0) { node-next = h->next; free(h); return 1;}
else { node = h; h = h->next; }
}
return 0;
}
队列:
typedef struct{
DATA data[QUEUEMAX];
int head;
int tail;
}SeqQueue;
SeqQueue* SeqQueueInit(){
SeqQueue *q;
if(q=(SeqQueue*)malloc(sizeof(SeqQueue))) {
q->head = 0;
q->tail = 0;
return q;
} else return NULL;
}
void SeqQueueFree(SeqQueue *q){
if(q!=NULL) free(q);
}
void SeqQueueIsEmpty(SeqQueue* q){
return q->head == q->tail;
}
void SeqQueue(SeqQueue *q) {
return q->tail - q-> head;
}
int SeqQueueIn(SeqQueue *q,DATA data){
if(q->tail == QUEUEMAX){ printf("the queue full\n"); return 0; }
else { q->data[q->tail++] = data; return 1; }
}
DATA *SeqQueueOut(SeqQueue *q){
if(q->head == q->tail){
printf("the queue empty\n");
} else {
return &(q->data[q-head++]);
}
}
栈:
typedef struct{
char name[15];
int age;
}DATA;
typedef struct stack{
DATA data[SIZE+1];
int top;
}SeqStack;
SeqStack *SeqStackInit() {
SeqStack *p;
if(p=(SeqStack*)malloc(sizeof(SeqStack))) { p->top = 0; return p;}
return NULL;
}
void SeqSTackFree(SeqSTack *s){
if(s) free(s);
}
int SeqStackIsEmpty(SeqStack *s){
return s->top == 0;
}
void SeqStackClear(SeqStack *s){
s->top = 0;
}
void SeqStackIsFull(SeqStack *s){
return s->top == SIZE;
}
int SeqStackPush(SeqStack *s,DATA data){
if((s->top + 1) > SIZE) {printf("stack full\n"); return 0; }
s->data[++s->top] = data;
}
DATA SeqStackPop(SeqStack *s){
if(s->top == 0){ printf("stack empty"); exit(0); }
return (s->data[s->top --]);
}
三、复杂数据结构
树:
满二叉树和完全二叉树的区别
typedef char DATA;
typedef struct ChainTree{
DATA data;
struct ChainTree *left;
struct ChainTree *right;
}ChainBinTree;
ChainBinTree *BinTreeInit(ChainBinTree *node){
if(node != NULL) return node;
else return NULL;
}
int BinTreeAddNode(ChainBinTree *bt,ChainBinTree *node,int n){
if(bt == NULL) {printf("father node not avaliable\n"); return 0; }
switch(n) {
case 1:
if(bt->left) {printf("left son node empty\n"); return 0; }
else bt->left = node;
break;
case 2:
if(bt->right) {printf("right son node not empty\n"); return 0; }
else bt->right = node;
break;
default: printf("parameter wrong\n"); return 0;
ChainBinTree *BinTreeLeft(ChainBinTree *bt){
if(bt) return bt->left;
else return NULL;
}
int BinTreeIsEmpty(ChainBinTree *bt){
if(bt) return 0;
else return 1;
}
int BinTreeDepth(ChainBinTree *bt){
int dep1,dep2;
if(bt == NULL) return 0;
else {
dep1 = BinTreeDepth(bt->left);
dep2 = BinTreeDepth(bt->right);
if(dep1 > dep2) return dep1 + 1;
else return dep2 + 1;
}
}
ChainBinTree *BinTreeFind(ChainBinTree *bt,DATA data){
ChainBinTree *p;
if(bt == NULL) return NULL;
else {
if(bt->data == data) return bt;
else {
if(p=BinTreeFind(bt->left,data)) return p;
else if(p=BinTreeFind(bt->right,data)) return p;
else return NULL;
}
}
}
void BinTreeClear(ChainBinTree *bt) {
if(bt) {
BinTreeClear(bt->left);
BinTreeClear(bt->right);
free(bt);
}
}
void BinTree_DLR(ChainBinTree *bt,void (*oper)(ChainBinTree *p)) {
if(bt) {
oper(bt);
BinTree_DLR(bt->left,oper);
BinTree_DLR(bt->right,oper);
}
}
void BinTree_LDR(ChainBinTree *bt,void (*oper)(ChainBinTree *p)) {
if(bt) {
BinTree_LDR(bt->left,oper);
oper(bt);
BinTree_LDR(bt->right,oper);
}
}
void BinTree_LRD(ChainBinTree *bt,void (*oper(ChainBinTree *p)) {
if(bt) {
BinTree_LRD(bt->left,oper);
BinTree_LRD(bt->right,oper);
oper(bt);
}
}
void oper(ChainBinTree *p){
printf("%c",p->data);
return;
}
ChainBinTree *InitRoot() {
ChainBinTree *node;
if(node = (ChainBinTree*)malloc(sizeof(ChainBinTree))){
printf("input:");
scanf("%s",&node->data);
node->left = NULL;
node->right = NULL;
return node;
}
return NULL;
}
void AddNode(ChainBinTree *bt) {
ChainBinTree *node,*parent;
DATA data;
char select;
if(node=(ChainBinTree*)malloc(sizeof(ChainBinTree))){
scanf("%s",&node->data);
node->left = NULL; node->right = NULL;
scanf("%s",&data);
parent = BinTreeFind(bt,data);
if(!parent) {printf("unfind father node"); free(node); return; }
do{
select = getch(); select -= '0';
if(select == 1 || select == 2)
BinTreeAddNode(parent,node,select)
}while(select != 1 && select != 2);
}
return;
}:
图:
typedef struct{
char Vertex[VERTEX_MAX];
int Edges[VERTEX_MAX][VERTEX_MAX];
int isTrav[VERTEX_MAX];
int VertexNum;
int EdgeNum;
int GraphType;
}MatrixGraph;
void CreateMatrixGraph(MatrixGraph *G){
int i,j,k,weight;
char start,end;
for(i=0;i
for(k=0;k
scanf("%c,%c,%d",&start,&end,&weight);
for(i=0;start!=G->Vertex[i];i++)
for(j=0;end!=G->Vertex[j];j++)
G->Edges[i][j] = weight;
}
}
void OutMatrix(MatrixGraph *G) {
int i,j;
for(j=0;j
printf("\n");
for(i=0;i
printf("%c",G->Vertex[i]);
for(j=0;j
if(G->Edges[i][j] == MAXVALUE) printf("\t=");
else printf9"\n%d",G->Edges[i][j]);
}
printf("\n");
}
}
邻接表存储:
typedef struct edgeNode{
int Vertex;
int weight;
struct edgeNode *next;
}EdgeNode;
typedef struct{
EdgeNode *AdjList[VERTEX_MAX];
int VertexNum,EdgeNum;
int GraphType;
}ListGraph;
void CreateGraph(ListGraph *G) {
int i,weight;
int start,end;
EdgeNode s;
for(i=1;i<=G->VertexNum;i++) G->AdjList[i]=NULL;
for(i=1;i<=G->EdgeNum;i++) {
scanf(%d,%d,%d",&start,&end,&weight);
s=(EdgeNode)malloc(sizeof(EdgeNode));
s->next = G->AdjList[start];
s->Vertex = end;
s->weight=weight;
G->AdjList[start]=s;
if(G->GraphType == 0){
s=(EdgeNode *) malloc(sizeof(EdgeNode));
s->next = G->AdjList[end];
s->Vertex = start;
s->weight = weight;
G->AdjList[end]=s;
}
}
}
void OutList(ListGraph *G){
int i;
EdgeNode *s;
for(i=1;i<=G->VertexNum;i++) {
printf("vertex %d",i);
s=G->AdjList[i];
while(s){
printf9"->%d(%d)",s->Vertex,s->weight);
s=s->next;
}
printf("\n");
}
}
BFS、DFS:
typedef strcut{
int Data[QUEUE_MAXSIZE];
int head;
int tail;
}SeqQueue;
void QueueInit(SeqQueue *Q) {
Q->head = Q->tail = 0;
}
int QueueIsEmpty(SeqQueue Q) {
return Q.head==Q.tail;
}
int QueueIn(SeqQueue *Q,int ch) {
if((Q->tail + 1)%QUEUE_MAXSIZE == Q->head) return 0;
Q->Data[Q-tail] = ch;
Q->tail = (Q->tail + 1)%QUEUE_MAXSIZE;
return 1;
}
int QueueOut(SeqQueue *Q,int *ch) {
if(Q->head == Q->tail) return 0;
*ch = Q->Data[Q->head];
Q->head = (Q->head + 1)%QUEUE_MAXSIZE;
return 1;
}
void BFSTraverse(MatrixGraph *G) {
int i;
for(i=0;i
printf("BFS:");
for(i=0;i
}
void BFSM(MatrixGraph *G,int k) {
int i,j;
SeqQueue Q;
QueueInit(&Q);
G->isTrav[k]=1;
printf("->%c",G->Vertex[k]);
QueueIn(&Q,k);
while(!QueueIsEmpty(Q)) {
QueueOut(&Q,&I);
for(j=0;j
if(G->Edges[i][j]!=MAXVALUE && !G->IsTrav[i]){
printf("->%c",G->Vertex[j]);
G->isTrav[j]=1;
QueueIn(&Q,j);
}
}
}
void DFSTraverse(MatrixGraph *G) {
int i;
for(i=0;i
for(i=0;i
if(!G->isTrav[i]) DFSM(G,I);
}
void DFSM(MatrixGraph *G,int i) {
int j;
G->isTrav[i] = 1;
printf("->%c",G->Vertex[i]);
for(j=0;j
if(G->Edges[i][j]!=MAXVALUE && !G->isTrav[i])
DFSM(G,j);
}
最小生成树Prim算法:从一个顶点出发,然后选权值最小的边,构成边后,依次进行。
define USED 0
define NOADJ -1
void Prim(MatrixGraph G) {
int i,j,k,min,sum=0;
int weight[VERTEX_MAX];
char temvertex[VERTEX_MAX];
for(i=1;i
if(weight[i] == MAXVALUE) temvertex[i] = NOADJ;
else temvertex[i] = G.Vertex[0];
}
temvertex[0] = USED;
weight[0] = MAXVALUE;
for(i=1;i
k=i;
for(j=1;j
sum += min;
printf("(%c,%c),",tmpvertex[k],G.Vertex[k]);
tmpvertex[k] = USED;
weight[k] = MAXVALUE;
for(j=0;j
if(G.Edges[k][j]
printf("\n the sum is:%d\n",sum);
}
最短路径Dijkstra算法:按照从源点到其他各顶点的最短路径的升序依次堆溢出从源点到各顶点的最短路径,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点加入到T中,OK,此时完成一个顶点,然后,我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis中的值。
然后,又从dis中找出最小值,重复上述动作,直到T中包含了图的所有顶点。。
void Dijkstra(MatrixGraph G) {
int weight[VERTEX_MAX];
int path[VERTEX_MAX];
int tmpvertex[VERTEX_MAX];
int i,j,k,v0,min;
printf("\n input origin vertex:");
scanf("%d",&v0);
v0--;
for(i=0;i
weight[i]=G.Edges[v0][i];
if(weight[i]
tmpvertex[i] = 0;
}
tmpvertex[v0] = 1;
weight[v0] = 0;
for(i=0;i
k=v0;
for(j=0;j
for(j=0;j
}
}
printf("\n vertex %c go eigher vertex short length is:\n",G.Vertex[v0];
for(i=0;i
k=i;
while(k != v0) { j=k; printf("%c<",G.Vertex[k]); k=path[k]; }
printf("%c\n",G.Vertex[k]);
} else printf("%c<-%c:no path\n",G.Vertex[i],G.Vertex[v0]);
}
}
四、排序
冒泡排序:
平均和最坏都是O(n平方)。
void BubbleSort(int a[],int n) {
int i,j,t,flat=0;
for(i=0;i
if(flag == 0)
break;
else flag = 0;
}
}
快速排序:
平均O(nlogn)。最坏O(n平方)。
int Division(int a[],int left,int right) {
int base = a[left];
while(left
a[left]=a[right];
while(left
a[right]=a[left];
}
a[left]=base;
return left;
}
void QuickSort(int a[],int left,int right){
int i,j;
if(left
QuickSort(a,left,i-1);
QuickSort(a,i+1,right);
}
}
//简化代码
void quickSort(int a[],int low,int high) {
if(low >= high) return;
int middle = low+(high-low)/2;
int pivot=a[middle];
int i=low,j=high;
while(i<=j) {
while(a[i]
if(i<=j) { int temp=a[i]; a[i]]=a[j]; a[j]=temp; i++; j--; }
}
if(low < j) quickSort(a,low,j);
if(hight > i) quickSort(a,i,high);
}
简单选择排序:
平均和最坏都是O(n平方)。
void SelectSort(int a[],int n) {
int i,j,k,t;
for(i=0;i
for(j=i+1;j
t=a[i]; a[i]=a[k]; a[k]=t;
}
}
堆排序:堆是一个完全二叉树,树中每个结点对应于原始数据的一个记录,并且每个结点应满足以下条件,非叶结点的数据大于或等于其左、右孩子结点的数据。
平均和最坏都是O(nlogn)。
void HeapAdjust(int a[],int s,int n) {
int j,t;
while(2s+1 < n) {
j=2s+1;
if(j+1
}
}
void HeapSort(int a[],int n) {
int t,i,j;
for(i=n/2-1;i>=0;i--) HeapAdjust(a,i,n);
for(i=n-1;i>0;i--) { t=a[0]; a[0]=a[i]; a[i]=t; HeadAdjust(a,0,i); }
}
插入排序:
平均和最坏都是O(n平方)。
void InsertSort(int a[],int n) {
int i,j,t;
for(i=1;i
for(j=i-1;j>=0 && t a[j+1]=t;
}
}
希尔排序:将需要排序的序列划分为若干个较小的序列,对这些序列进行直接插入排序,通过这样的操作可使需要排序的数列基本有序,最后再使用一次直接插入排序。
在希尔排序中首先要解决的是怎样划分子序列。对于子序列的构成不是简单地分段,而是采取相隔某个增量的数据组成一个序列。一般选择增量的规则是:取上一个增量的一半作为此次子序列划分的增量,一般初始值取元素的总数量。
平均O(n的3/2次方),最坏O(n平方)。
void ShellSort(int a[],int n){
int d,i,j,x;
d=n/2;
while(d>=1){
for(i=d;i
j=i-d;
while(j>=0 && a[j]>x){ a[j+d]=a[j]; j=j-d; }
a[j+d]=x;
}
d/=2;
}
}
合并排序:
平均和最坏情况下都是O(nlogn)。
void MergeStep(int a[],int r[],int s,int m,int n){
int i,j,k;
k=s;
i=s;
j=m+1;
while(i<=m && j<=n){
if(a[i]<=a[j]) r[k++]=a[i++];
else r[k++]=a[j++];
}
while(i<=m) r[k++]=a[i++];
while(j<=n) r[k++]=a[j++];
}
void MergePass(int a[],int r[],int n,int len){
int s,e;
s=0;
while(s+len < n){
e=s+2*len-1;
if(e>=n) e=n-1;
MergeSte[(a,r,s,s+len-1,e);
s=e+1;
}
if(s
void MergeSort(int a[],int n){
int p;
int len=1;
int f=0;
if(!(p=(int)malloc(sizeof(int)n))) { printf("wrong\n"); exit(0); }
while(len
else MergePass(a,p,n,len);
len
f=1-f;
}
if(f) for(f=0;f
}
五、常用算法——查找
顺序查找和二分查找
二叉排序树
定义,二叉树或者是一棵空树,或者是一棵具有以下性质的二叉树:若它有左子树,则左子树上所有结点的数据均小于根结点的数据;或它有右子树,则右子树上所有结点的数据均存在于根结点的数据;左右子树本身又各是一棵二叉排序树。
typedef struct bst{
int data;
struct bst *left;
struct bst *right;
}BSTree;
void InsertBST(BSTree t,int key){
BSTree p,parent,head;
if(!(p=(BSTree *)malloc(sizeof(BSTree *)))){ printf("wrong\n"); exit(0); }
p->data=key;
p->left=p->right=NULL;
head=t;
while(head){
parent=head;
if(key < head->data) head=head->left;
else head=head->right;
}
if(key < parent->data) parent->left = p;
else parent->right = p;
}
void CreateBST(BSTree *t,int data[],int n){
int i;
t->data=data[0];
t->left=t->right=NULL;
for(i=1;i
void BST_LDR(BSTree *t){
if(t){
BST_LDR(t->left);
printf("%d ",t->data);
BST_LDR(t->right);
}
return;
}
BSTree *SerarchBST(BSTree *t,int key){
if(!t || t->data==key) return t;
else if(key > t->data) return SearchBST(t->right,key);
else return SearchBST(t->left,key);
}
void BST_Delete(BSTree t,int key){
BSTree p,parent,l,*l1;
int child=0;
if(!t) return;
p=t;
parent=p;
while(p){
if(p->data == key){
if(!p->left && !p->right){
if(p==t) free(p);
else if(child==0) { parent->left == NULL; free(p); }
else { parent->right == NULL; free(p);
}
} else if(!p->left){
if(child==0) parent->left=p->right;
else parent->left = p->left;
free(p);
}else if{
if(child=0) parent->right = p->right;
else parent->right = p->left;
free(p);
} else {
l1=p;
l=p->right;
while(l->left){ l1=l; l=l->left; }
p->data = l->data;
l1->left = NULL;
free(l1);
}
p=NULL;
} else if(key < p->data){
child=0;
parent=p;
p=p->left;
} else{
child=1;
parent=p;
p=p->right;
}
}
}
索引查找
创建索引的基本思想:将一个线性表(主表)按一定的函数关系或条件划分为若干个子表,每个子表创建一个索引项,由这些索引项构成主给的一个索引表。接着,采用线性或链接方式分别保存索引表和各个子表。
typedef struct item{
int index;
int start;
int length;
}INDEXITEM;
long stu[30]={1080101,2938472,2384201,24382......};
INDEXITEM indextable[3]={{10801,0,6},{10802,10,4},{10803,20,4}};
int IndexSearch(int key){
int i,index1,start,length;
index1=key/100;
for(i=0;i<30;i++){
if(indetable[i].index=index1){
start=indextable[i].start;
length=indextable[i].length;
break;
}
}
if(i>=3) return -1;
for(i=start;i
}
return -1;
}
int InsertNode(key){
int i,index1,start,length;
index1=key/100;
for(i=0;i<3;i++){
if(indextable[i].index == index1){
start=indextable[i].start;
length=indextable[i].length;
break;
}
}
for(i=0;i<3;i++){
if(indextable[i].index == index1){
start=omdextable[i].start;
length=indextable[i].length;
break;
}
}
if(i>=3) return -1;
stu[start+length]=key;
indextable[i].length++;
return 0;
}
散列表
基本思想:以线性表中每个元素的关键字key为自变量,通过一定的函数关系h(key)计算出函数的值,把这个值作为数组的下标,将元素存入对应的数组元素中。
构造散列函数:1.直接定址法h(key)=key+C;2.除法取余法,用关键字key除以散列表长度n,得到的余数作为散列地址,n最好为一个素数;3.数字分析法,取关键字中某些比较分散的数字作为散列地址的方法;4.平方取中法,将关键字key求平方后,取中间的几位数字作为散列地址;5.折叠法,先将关键字key按散列地址要求的位数分成长度相等的几段,最后一段长度可能会短些。接着将这几段进行求和,然后去掉最高位的进位,将得到的值作为散列地址。
处理冲突:1.开放地址法,从发生冲突的那个数组元素开始,按一定的次序,从散列表中查出一个空闲的数组元素,把发生冲突的待插入元素存入到该数组元素中;2.链接法,在散列表中的每个存储单元中增设一个指针域,将散列地址相同的元素链接起来。
int data[8]={69,65,90,37,92,6,28,54};
int hash[13]={0};
void InsertHash(int hash[],int m,int data){
int i;
i=data%13;
while(hash[i]) i=(i++)%m;
hash[i]=data;
}
void CreateHash(int hash[],int m,int data[],int n){
int i;
for(i=0;i
int HashSearch(int hash[],int m,int key){
int i;
i=key%13;
while(hash[i] && hash[i]!=key) i=(i++)%m;
if(hash[i]==0) return -1;
else return 1;
}