1、顺序表( 数组,在内存当中连续存储,数据元素个数固定 )
1、顺序存的储的遍历以及、增、删、改、查 ( 在代码中 )
#include<stdio.h>
#include<stdlib.h>
#define N 100
typedef struct
{
int data[N];
int last;
}seqlist_t;
///
********************申请空间***********************
//
seqlist_t* createSeqlist_t()
{
seqlist_t* p = malloc(sizeof(seqlist_t));//申请一个堆空间
if(p == NULL)//判断是否申请成功
{
printf("malloc failed!!");
return NULL;
}
return p;
}
///
*********判断顺序表是否为满或者为空****************
//
int isFullEmptyseqlist(seqlist_t* p,int x)
{
return p->last == x;
}
///
********************插入元素***********************
//
int insertIntoSeqlist(seqlist_t* p,int post,int x)
{
int i;
if(isFullEmptyseqlist(p,N) || post < 1 || post > p->last + 1)//容错判断
{
printf("insert failed!!");
return -1;
}
for(i = p->last; i >= post; i--)//移动到要插入的位置
p->data[i] = p->data[i-1];//元素向后移动
p->data[post-1] = x;//插入元素
p->last++;//插入后下标加一
return 0;
}
///
********************删除元素***********************
//
int deleteFromSeqlist(seqlist_t* p,int post)
{
int i;
if(post < 1 || post > p->last || isFullEmptyseqlist(p,0))//容错判断
{
printf("delete failed!!");
return -1;
}
for(i = post; i < p->last; i++)//在要删除的位置
p->data[i-1] = p->data[i];//要删除的元素被后面的覆盖
p->last--;//下标减一
return 0;
}
///
********************查找元素***********************
//
int searchDataSeqlist(seqlist_t* p,int x)
{
int i;
for(i = 0; i < p->last; i++)//循环遍历
{
if(p->data[i] == x)
{
return i + 1; //返回所在位置
}
}
return 0; //没有这个元素
}
///
********************遍历顺序表*********************
//
void showSeqlist(seqlist_t* p)
{
int i;
for(i = 0; i < p->last; i++)
printf("%d ",p->data[i]);
printf("\n");
}
///
********************顺序表长度*********************
//
int getLenthlist(seqlist_t* p)
{
return p->last;
}
///
********************清空顺序表*********************
//
void clearSeqlist(seqlist_t* p)
{
p->last = 0;
}
int main(int argc,const char* argv[])
{
seqlist_t* p = createSeqlist_t();
insertIntoSeqlist(p,1,400); //在第一个位置插入400
insertIntoSeqlist(p,1,300); //在第一个位置插入300
insertIntoSeqlist(p,1,200); //在第一个位置插入200
insertIntoSeqlist(p,1,100); //在第一个位置插入100
printf("表长是:%d\n",getLenthlist(p));//计算表长
showSeqlist(p); //遍历顺序表
printf("%d\n",searchDataSeqlist(p,100)); //返回所在位置
printf("%d\n",searchDataSeqlist(p,1));
deleteFromSeqlist(p,1); //删除第一个元素
deleteFromSeqlist(p,2); //删除第二个元素
printf("表长是:%d\n",getLenthlist(p));//计算表长
showSeqlist(p); //遍历顺序表
clearSeqlist(p);//清空顺序表
showSeqlist(p); //遍历顺序表
}
2、链表 ( 内存中不连续存储,通过指针将每个节点连接在一起 )
1、无头单向链表
#include<stdio.h>
#include<stdlib.h>
typedef struct node_t
{
int data;
struct node_t* next;
}seqLinknode_t;
/*****************无头遍历链表**********************/
void showSeqLinklist(seqLinknode_t* p)
{
while(p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
/********************主函数************************/
int main(int argc,const char* argv[])
{
seqLinknode_t a = {10,NULL};
seqLinknode_t b = {20,NULL};
seqLinknode_t c = {30,NULL};
seqLinknode_t d = {40,NULL};
seqLinknode_t e = {50,NULL};
a.next = &b;
b.next = &c;
c.next = &d;
d.next = &e;
seqLinknode_t* p = &a;
WshowSeqLinklist(p);
}
2、有头单向链表
有头链表与无头链表的区别就是差一个结构体,有头链表第一个结构体的数据域是无效的,而无头链表没有无效的数据域。
#include<stdio.h>
#include<stdlib.h>
typedef struct node_t
{
int data;
struct node_t* next;
}seqLinknode_t;
/********************申请空间***********************/
seqLinknode_t* createSeqLinknode_t()
{
seqLinknode_t* p = malloc(sizeof(seqLinknode_t));//申请一块堆空间
if(p == NULL)//判断是否申请成功
{
printf("malloc failed!!");
return NULL;
}
p->next = NULL;
return p;
}
/*****************有头遍历链表**********************/
void showSeqLinklist(seqLinknode_t* p)
{
while(p->next != NULL)
{
p = p->next;
printf("%d ",p->data);
}
printf("\n");
}
/****************判断链表是否为空*******************/
int isEmptySeqLinklist(seqLinknode_t* p)
{
return p->next == NULL;
}
/*******************链表长度************************/
int getLenthLinklist(seqLinknode_t* p)
{
int i;
for(i = 0; p->next != NULL; i++)
p = p->next;
return i;
}
/********************插入元素***********************/
int insertIntoSeqLinklist(seqLinknode_t* p,int post,int x)
{
int i;
if(post < 1 || post > getLenthLinklist(p) + 1)//容错判断
{
printf("插入失败!!");
return -1;
}
for(i = 1; i < post; i++)//移动到要插入的节点位置
p = p->next;
seqLinknode_t* pnew = createSeqLinknode_t();//插入节点
pnew->data = x;//对数据域进行赋值
pnew->next = p->next;//先让新节点的指针域指向要插入位置的下一个节点
p->next = pnew;//然后让插入位置的前一个节点的指针域指向新节点
return 0;
}
/********************删除元素***********************/
int deleteFromSeqLinklist(seqLinknode_t* p,int post)
{
int i;
if(isEmptySeqLinklist(p) || post < 1 || post > getLenthLinklist(p))//容错判断
{
printf("删除失败!!");
return -1;
}
for(i = 1; i < post; i++)//移动到要删除节点的前一个位置
p = p->next;
p->next = p->next->next;//将要删除的前一个节点的指针域 指向 要删除节点的指针域
free(q);
q = NULL;
return 0;
}
/********************清空链表**********************/
void clearSeqLinklist(seqLinknode_t* p)
{
seqLinknode_t* q;
while(p->next != NULL)
{
q = p->next;
p->next = p->next->next;//流水线切东西
free(q);
q = NULL;
}
}
/********************查找元素***********************/
int searchDataSeqLinklist(seqLinknode_t* p,int x)
{
int i;
for(i = 0; p->next != NULL; i++)
{
p = p->next;
if(p->data == x)
return i + 1;
}
return -1;
}
/********************主函数************************/
int main(int argc,const char* argv[])
{
seqLinknode_t* p = createSeqLinknode_t();
insertIntoSeqLinklist(p,1,400);
insertIntoSeqLinklist(p,1,300);
insertIntoSeqLinklist(p,1,200);
insertIntoSeqLinklist(p,1,100);
showSeqLinklist(p);
deleteFromSeqLinklist(p,1);
deleteFromSeqLinklist(p,3);
showSeqLinklist(p);
printf("%d\n",searchDataSeqLinklist(p,300));
clearSeqLinklist(p);
showSeqLinklist(p);
}
3、单向循环链表
单向循环链表解决约瑟夫问题
#include<stdio.h>
#include<stdlib.h>
typedef struct node_t
{
int data;
struct node_t* next;
}seqLinknode_t;
/*****************无头遍历链表**********************/
void showSeqLinklist(seqLinknode_t* p)
{
while(p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
/********************主函数************************/
int main(int argc,const char* argv[])
{
seqLinknode_t a = {10,NULL};
seqLinknode_t b = {20,NULL};
seqLinknode_t c = {30,NULL};
seqLinknode_t d = {40,NULL};
seqLinknode_t e = {50,NULL};
a.next = &b;
b.next = &c;
c.next = &d;
d.next = &e;
seqLinknode_t* p = &a;
WshowSeqLinklist(p);
}
4、双向链表
3、栈
思想:先进后出,后进后出。
1、顺序栈
#include<stdio.h>
#include<stdlib.h>
#define N 100
typedef struct
{
int data[N];
int top;
}seqtack_t,*seqTackList_t;
int insertIntotack(seqTackList_t p,int x)
{
if(p->top == N)
{
printf("插入失败,栈满!!!\n");
return -1;
}
p->data[p->top] = x;
p->top++;
return 0;
}
int deleteFromtack(seqTackList_t p)
{
if(p->top == 0)
{
printf("删除失败,栈空!!!\n");
return -1;
}
p->top--;
return p->data[p->top];
}
void showSeqtack_list(seqTackList_t p)
{
int i;
for(i = 0; i < p->top; i++)
printf("%d ",p->data[i]);
printf("\n");
}
int main(int argc,const char* argv[])
{
seqTackList_t p = malloc(sizeof(seqtack_t));
if(p != NULL)
{
int i;
insertIntotack(p,100);
insertIntotack(p,200);
insertIntotack(p,300);
insertIntotack(p,400);
insertIntotack(p,500);
showSeqtack_list(p)
for(i = 0; i < 5;i++ )
printf("%d\n",deleteFromtack(p));
return 0;
}
else
{
return -1;
}
}
2、链栈
#include<stdio.h>
#include<stdlib.h>
typedef struct node_t
{
int data;
struct node_t* next;
}seqtacknode_t,*seqnodelist_t;
seqnodelist_t createEmptylist()
{
seqnodelist_t p = malloc(sizeof(seqtacknode_t));
if(p == NULL)
{
printf("malloc failed!!");
return NULL;
}
p->next = NULL;
return p;
}
void insertIntoSeqtacknode_t(seqnodelist_t p,int x)
{
seqnodelist_t pnew = createEmptylist();
pnew->data = x;
pnew->next = p->next;
p->next = pnew;
}
int deleteFromtack(seqnodelist_t p)
{
int count;
if(p->next == NULL)
{
printf("删除失败,栈空!!");
return -1;
}
seqnodelist_t q = p->next;
count = q->data;
p->next = p->next->next;
free(q);
q = NULL;
return count;
}
void showSeqTacklist(seqnodelist_t p)
{
while(p->next != NULL)
{
p = p->next;
printf("%d ",p->data);
}
printf("\n");
}
int main(int argc,const char* argv[])
{
seqnodelist_t p = createEmptylist();
insertIntoSeqtacknode_t(p,100);
insertIntoSeqtacknode_t(p,200);
insertIntoSeqtacknode_t(p,300);
insertIntoSeqtacknode_t(p,400);
insertIntoSeqtacknode_t(p,500);
showSeqTacklist(p);
while(p->next != NULL)
printf("%d ",deleteFromtack(p));
printf("\n");
return 0;
}
4、队列
思想:先进先出,后进后出。
1、 顺序队列
#include<stdio.h>
#include<stdlib.h>
#define N 100
typedef struct
{
int data[N];
int rear;
int front;
}sequeuelist_t;
sequeuelist_t* createSequeuelist()//申请空间
{
sequeuelist_t* p = malloc(sizeof(sequeuelist_t));
if(p == NULL)
{
printf("malloc failed!!!");
return NULL;
}
p->rear = p->front = 0;
return p;
}
int insertIntoSequeuelist(sequeuelist_t* p,int x)//插入,排队操作操作
{
if(getLenthSequeuelist(p,N))
{
printf("插入失败,队列满");
return -1;
}
p->data[p->rear] = x;
p->rear++;
}
int getLenthSequeuelist(sequeuelist_t* p,int x)
{
return (p->rear - p->front + N)%N == x;
}
int deleteFromSequeuelist(sequeuelist_t* p)//删除,买完东西走操作
{
int count;
if(p->rear == p->front)
{
printf("队列为空!!!");
return -1;
}
count = p->data[p->front];
p->front++;
return count;
}
void showSequeuelist(sequeuelist_t* p)
{
int i;
for(i = p->front; i < (p->rear + N)%N; i++)
{
printf("%d\n",p->data[i]);
}
}
int main(int argc,const char* argv[])
{
int i;
sequeuelist_t* p = createSequeuelist();
insertIntoSequeuelist(p,100);
insertIntoSequeuelist(p,200);
insertIntoSequeuelist(p,300);
insertIntoSequeuelist(p,400);
insertIntoSequeuelist(p,500);
showSequeuelist(p);
//printf("----------------------------------------\n");
for(i = 0; i < 3; i++)
{
printf("%d\n",deleteFromSequeuelist(p));
}
//printf("-------------------------------------------\n");
showSequeuelist(p);
return 0;
}
2、链队列
#include<stdio.h>
#include<stdlib.h>
typedef struct node_t
{
int data;
struct node_t* next;
}sequeue_node_list_t,*sequeue_node_t;
sequeue_node_t createEmptySequeuelist()
{
sequeue_node_t p = malloc(sizeof(sequeue_node_list_t));
if(p == NULL)
{
printf("malloc failed!!");
return NULL;
}
return p;
}
void insertIntoSequeuelist(sequeue_node_t* p,int x)
{
sequeue_node_t pnew = createEmptySequeuelist();
pnew->data = x;
pnew->next = (*p)->next;
(*p)->next = pnew;
*p = (*p)->next;
}
int deleteFromSequeuelist(sequeue_node_t p)
{
if(p->next == NULL)
{
printf("删除失败,队列为空!!");
return -1;
}
sequeue_node_t q = p->next;
int count = q->data;
p->next = p->next->next;
free(q);
q = NULL;
return count;
}
void showSequeuelist(sequeue_node_t p)
{
while(p->next != NULL)
{
p = p->next;
printf("%d ",p->data);
}
printf("\n");
}
int main(int argc,const char* argv[])
{
int i;
sequeue_node_t phead = createEmptySequeuelist();
sequeue_node_t ptail = phead;
insertIntoSequeuelist(&ptail,100);
insertIntoSequeuelist(&ptail,200);
insertIntoSequeuelist(&ptail,300);
insertIntoSequeuelist(&ptail,400);
insertIntoSequeuelist(&ptail,500);
showSequeuelist(phead);
for(i = 0; i < 5; i++)
printf("%d ",deleteFromSequeuelist(phead));
printf("\n");
return 0;
}
5、查找方法(哈希(散列)、二分、分块(索引)、顺序)
查找速度:哈希查找 > 二分法查找 > 分块法查找 > 顺序查找
1、哈希查找(散列)
int hashFun(int key)
{
int post = key*key % 100000 / 100;
return post;
}
//存储数据
void saveNum(int *hash_list, int key)
{
int post = hashFun(key);
hash_list[post] = key;
}
//取数据
int getNum(int *hash_list,int key)
{
int post = hashFun(key);
return hash_list[post];
}
int main(int argc, const char *argv[])
{
int i;
int a[] = {100,110,1010,1001,111}; //key
int hash_list[1000] = { 0 };//哈希表
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
saveNum(hash_list,a[i]);
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
printf("post:%3d --- %d\n",hashFun(a[i]),getNum(hash_list,a[i]));
return 0;
}
2、二分法查找
只能查找排好序的,递增序列或者递减序列
int findByHalf(int* p, int n, int x)
{
int how = 0;
int high = n - 1;
int midled;
while(low <= high)
{
midled = (low + high) / 2;
if(p[midled] == x)
return midled;
else if(p[midled] < x)
low = midled + 1;
else if(p[midled] > x)
high = midled - 1;
}
return -1
}
3、分块查找(索引)
typedef struct
{
int max; //每一块的最大值
int post;//每一块在数组中的起始下标
}index_t; 块数 元素个数
int findByBlock(int* a, index_t* b, int x,int n,int m)
{
int start,end;//用来保存起始位置和终止位置的下标
//1.先通过索引表,快速确定x可能在哪一块中
int i;
for(i = 0; i < n; i++)
{
if(x <= b[i].max)//如果x比第i块的最大值小,说明可能在这一块中
break;//没有必要继续和下一块的最大值做比较
}
if(i == n)//说明是自然结束,没有break,说明这个数x,比所有块的最大值还大
return -1;//不存在
//2.在这一块中顺序查找是否有x
//锁定这块的起始位置和终止位置的下标
start = b[i].post;
if(i == n-1)//说明在最后一块,因为最后一块,没有下一块
end = m-1;//元素个数n-1
else
end = b[i+1].post - 1;//后一块的起始位置的下标 - 1 的到当前第i块的终止下标
//有了这一块的起始和终止位置的下标,就可以顺序查找
for(i = start; i <= end; i++)
{
if(a[i] == x)
return i;
}
return -1;
}
int main(int argc, const char *argv[])
{
//源数据表 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
int a[19] = {18, 10, 9, 8, 16, 20, 38, 42, 19, 50, 84, 72, 56, 55, 76, 100, 90, 88, 108};
//索引表,索引表的目的就是快速的锁定,你可能在哪一块中
index_t b[4] = {{18,0},{50,5},{84,10},{108,15}};
int i;
for(i = 0; i < 19; i++)
{
int ret = findByBlock(a,b,a[i]);
if(ret == -1)
printf("not find!!\n");
else
printf("%d的位置是%d\n",a[ret],ret);
}
printf("%d\n",findByBlock(a,b,51));
return 0;
}
4、顺序查找
int searchDataSeqlist(seqLinknode_t* p,int x)
{
int i;
for(i = 0; p!= NULL; i++)
{
if(p->data == x)
return i;
p = p->next;
}
return -1;
}
6、树
1、二叉树
(1)性质
(1)二叉树第k(k>=1) 层上的节点最多 2^(k-1) 个。//2的k-1次幂
(2)深度为k(k>=1)的二叉树最多有 2^k - 1 个节点。//2的k次幂再-1
(3)在任意一棵二叉树中,树叶的数目比度数为2的节点的数目多一。(度数为2的 = 度数为0的 - 1)
(4)满二叉树: 深度为k(k>=1)时节点为2^k - 1(2的k次幂-1)
(5)完全二叉树:在满二叉树的最后一层,自右向左连续缺失若干个节点,保证最后一层剩余的节点都在左侧(深度为k(k>=1)时节点为2^(k - 1) (2的k-1次幂) )
(2) 二叉树的遍历
前序遍历: 根 左 右
中序遍历: 左 根 右
后序遍历: 左 右 根
前序遍历:A B D F E C G H I
中序遍历:D B E F A G H C I
后序遍历:D E F B H G I C A
由遍历推图的方法:由前序遍历的第一个元素(或后序遍历的最后一个元素)可知他是跟节点,然后去中序遍历中找到这个跟节点,在这个跟节点左面的所有元素就是这个跟节点左分支上的元素,右面的所有元素就是这个跟节点右分支上的,然后在回到前序遍历中找离跟节点最近的元素,然后再去中序遍历中分元素。(循环这个操作,操作如下)
前序遍历:A B D F E C G H I
中序遍历:D B E F A G H C I //跟节点是 A,A左面为A左分支上的节点,A右面为右分支的节点
前序遍历:A B D F E C G H I
中序遍历:D B E F A G H C I //根据前序遍历确认A节点的左儿子 B 作为新的跟节点
能确定B的左儿子是 D
前序遍历:A B D F E C G H I
中序遍历:D B E F A G H C I //根据前序遍历确认B节点的右儿子 F 作为新的跟节点
能确定F的左儿子是 E
前序遍历:A B D F E C G H I
中序遍历:D B E F A G H C I //根据前序遍历确认A节点的右儿子 C 作为新的跟节点
能确定C的右儿子是 I
前序遍历:A B D F E C G H I
中序遍历:D B E F A G H C I //根据前序遍历确认C节点的右儿子 G 作为新的跟节点
能确定G的右儿子是 H
(3)赫夫曼树(最短路径)
1、 由权值分别为 3,8,6,2 的叶子生成一棵哈夫曼树,它的带权路径长度为 ( 35 ) 。
//对元素进行排序,然后把最小的两个元素加起来形成个小树,在排序在生成树(循环这个过程)
2、 哈夫曼编码
A,B,C,D,E五个字符,出现的频率(即权值)分别为 5,4,3,2,1 所以各字符对应的编码为?
左 0 右 1 (或左 1 右 0 )
A::11 A:00
B::10 B:01
C: 01 C:10
D:001 D:110
E:000 E:111
7、排序方法(快排、选择、插值、冒泡)
1、 快速排序
void quickSort(int* p, int low, int high)
{
int i = low;
int j = high;
int flag = p[low];
while(i < j)
{
while(p[j] >= flag&&i < j)
j--;
if(i < j)
{
p[i] = p[j];
i++;
}
while(p[i] <= flag&&i < j)
i++;
if(i < j)
{
p[j] = p[i];
j--;
}
}
p[i] = flag;
if(low < i-1)
{
quickSort(p,low,i-1);
}
if(i+1 < high)
{
quickSort(p,i+1,high);
}
}
2、插值排序
void zhicha(int* p,int n)
{
int i,j,temp;
for(i = 1; i < n; i++)
{
for(j = i; j > 0; j--)
{
if(p[j] < p[j-1])
{
temp = p[j];
p[j] = p[j-1];
p[j-1] = temp;
}
else
{
break;
}
}
}
}
3、冒泡排序
void maopao(int* p,int n)
{
int i,j,temp;
for(i = 0; i < n-1; i++)
{
for(j = 0; j < n-1-i; j++)
{
if(p[j] > p[j+1])
{
temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
}
}
4、 选择排序
void xuanze(int* p,int n)
{
int i,j,temp;
for(i = 0; i < n-1; i++)
{
for(j = i+1; j < n; j++)
{
if(p[i] > p[j])
{
temp = p[i];
p[i] = p[j];
p[j] = temp;
}
}
}
}
/************************//*************************************
升级版选择排序/
************************//************************************/
void xuanze(int* p,int n)
{
int i,j,min,temp;
for(i = 0; i < n-1; i++)
{
min = i;
for(j = i+1; j < n; j++)
{
if(p[min] > p[j])
min = j;
}
if(i != min)
{
temp = p[i];
p[i] = p[min];
p[min] = temp;
}
}
}