1. 栈操作
(1)栈特点: 先进后出, 后进先出
(2)实现: 顺序表 链表
(3)基础概念:
栈底
栈底: 入栈、出栈都是从栈底操作的
ps: 栈不可以在中间做插入或者删除的操作
(1)栈的初始化
struct stack
{
int *space; //栈空间的起始地址
int len; //总的数据个数
int count; //实际存储数据的个数
};
//栈的初始化
void stack_init(struct stack *ps, int n)
{
ps->space = (int *)malloc(sizeof(int)*n);
assert((ps->space) != NULL);
ps->len = n;
ps->count = 0;
return ;
}
//栈的大小(使用的元素个数)
int stack_size(struct stack s)
{
return s.count;
}
//判断栈是否为空
bool is_empty(struct stack s)
{
if(s.count == 0)
{
return true;
}
else
{
return false;
}
}
//判断栈是否已满
bool is_full(struct stack s)
{
if(s.count == s.len)
{
return true;
}
else
{
return false;
}
}
(2)入栈
//入栈
//成功返回0 失败返回-1
int stack_push(struct stack *ps, int data)
{
//判断栈是否已满
if(is_full(*ps))
{
printf("栈已满,入栈失败!\n");
return -1;
}
ps->space[ps->count] = data;
(ps->count) ++;
return 0;
}
(3) 出栈
//出栈
int stack_pop(struct stack *ps, int *presult)
{
//判断栈是否为空
if(is_empty(*ps))
{
printf("栈为空,出栈失败!\n");
return -1;
}
if(presult != NULL)
{
*presult = ps->space[(ps->count)-1];
}
(ps->count) --;
return 0;
}
(3)主函数验证:
int main()
{
struct stack s1;
stack_init(&s1, 5);
stack_push(&s1, 1);
stack_push(&s1, 2);
stack_push(&s1, 3);
stack_push(&s1, 4);
stack_push(&s1, 5);
int data;
stack_pop(&s1,&data);
printf("data: %d\n", data);
stack_pop(&s1,&data);
printf("data: %d\n", data);
stack_pop(&s1,&data);
printf("data: %d\n", data);
stack_pop(&s1,&data);
printf("data: %d\n", data);
stack_pop(&s1,&data);
printf("data: %d\n", data);
stack_pop(&s1,&data);
return 0;
}
2. 队列
(1)特点: 先进先 出, 后进后出
(2) 实现: 顺序表 链式
(3) 队头 队尾
ps: 不允许在中间做插入或者删除的操作!
(1)队列初始化
//表示队列节点的类型
struct node
{
int data;
struct node *next;
};
//表示队列的基本信息
struct queue
{
int len; //设置队列的总长度
int count; //当前节点的个数
struct node *first; //保存第一个节点的地址
struct node *tail; //保存最后一个节点的地址
};
//初始化
void queue_init(struct queue *pq, int n)
{
pq->len = n;
pq->count = 0;
pq->first = NULL;
pq->tail = NULL;
return ;
}
//判断队列是否已满
bool is_full(struct queue q)
{
if(q.count == q.len)
{
return true;
}
else
{
return false;
}
}
//判断队列是否为空
bool is_empty(struct queue q)
{
if(q.count == 0)
{
return true;
}
else
{
return false;
}
}
(2)入队
//入队 (尾部追加)
//成功返回0 失败-1
int queue_push(struct queue *pq, int data)
{
//判断队列是否已满
if(is_full(*pq))
{
printf("队列已满,入队失败!\n");
return -1;
}
//正确流程
struct node *pnew = NULL;
pnew = (struct node *)malloc(sizeof(struct node));
assert(pnew!=NULL);
pnew->data = data;
pnew->next = NULL;
if(pq->first == NULL) //空链表
{
pq->first = pnew;
pq->tail = pnew;
}
else //非空链表 让最后一个节点的next保存新的节点地址
{
pq->tail->next = pnew;
pq->tail = pnew;
}
pq->count ++;
return 0;
}
(3)出队
//出队 (头部删除)
int queue_pop(struct queue *pq, int *presult)
{
//判断队列是否为空
if(is_empty(*pq))
{
printf("队列为空 ,出队失败!\n");
return -1;
}
//正确流程
struct node *pdel = NULL;
//1)保存第一个节点的地址,将第一个节点从链表中移下来
pdel = pq->first;
pq->first = pq->first->next;
// 2)返回出队的数据
if(presult != NULL)
{
*presult = pdel->data;
}
//3)释放内存
free(pdel);
//4)判断是否是空链表
if(pq->first == NULL) //设置tail的值
{
pq->tail = NULL;
}
//5)设置count值
pq->count --;
return 0;
}
(4)主函数验证
int main()
{
struct queue q1;
queue_init(&q1, 5);
queue_push(&q1, 1);
queue_push(&q1, 2);
queue_push(&q1, 3);
queue_push(&q1, 4);
queue_push(&q1, 5);
int data;
queue_pop(&q1,&data);
printf("data: %d\n", data);
queue_pop(&q1,&data);
printf("data: %d\n", data);
queue_pop(&q1,&data);
printf("data: %d\n", data);
queue_pop(&q1,&data);
printf("data: %d\n", data);
queue_pop(&q1,&data);
printf("data: %d\n", data);
queue_pop(&q1,&data);
return 0;
}
3. 二叉树
完全二叉树
- 若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
- 一维数组可以作为完全二叉树的存储结构,堆排序使用的数据结构就是完全二叉树
满二叉树
国际标准定义是除了叶结点外每一个结点都有左右子结点的二叉树
(1)创建二叉树
//表示节点的类型
struct node
{
int data;
struct node *left;
struct node *right;
};
struct node* create_tree()
{
struct node *root = NULL;
struct node *pnew = NULL;
int x;
scanf("%d", &x);
while(getchar() != '\n');
while(x)
{
//1、创建新的节点,并且赋值
pnew = (struct node*)malloc(sizeof(struct node));
assert(pnew!=NULL);
pnew->data = x;
pnew->left = NULL;
pnew->right = NULL;
//2、加入有序二叉树
if(NULL == root)
{
root = pnew;
}
else
{
struct node *p = root;
struct node *q = NULL;
while(p != NULL)
{
q = p;
if(pnew->data < p->data)
{
p = p->left;
}
else
{
p = p->right;
}
}
if(pnew->data < q->data)
{
q->left = pnew;
}
else
{
q->right = pnew;
}
}
scanf("%d", &x);
while(getchar()!='\n');
}
return root;
}
(2)遍历二叉树
#if 0
先序遍历
先访问根节点
然后先序遍历左子树
最后先序遍历右子树
#endif
void pre_print(struct node *root)
{
if(root != NULL)
{
printf("%d ", root->data);
pre_print(root->left);
pre_print(root->right);
}
}
#if 0
中序遍历
先中序遍历左子树
再访问根节点
最后中序遍历右子树
#endif
void mid_print(struct node *root)
{
if(root != NULL)
{
mid_print(root->left);
printf("%d ", root->data);
mid_print(root->right);
}
}
#if 0
后序遍历
先后序遍历左子树
再后序遍历右子树
最后访问根节点
#endif
void tail_print(struct node *root)
{
if(root != NULL)
{
tail->print(root->left);
tail->print(root->right);
printf("%d", root->data);
}
}
(2)主函数
int main()
{
struct node *root = NULL;
root = create_tree();
pre_print(root);
printf("\n");
return 0;
}
4. 哈希表
hash函数就是根据key计算出应该存储地址的位置,而哈希表是基于哈希函数建立的一种查找表
(1)除留余数法
H(key)=key % p
5. 排序
快速排序
在一个无序数组中取一个数key,每一趟排序的最终目的是:让key的左边的所有数小于key,key的右边都大于key(假设排升序)
代码实现
#include <stdio.h>
int find_pos(int a[], int low, int high)
{
int key = a[low];
while(low<high)
{
while(low<high && a[high]>=key)
{
high --;
}
a[low] = a[high];
while(low<high && a[low] <= key)
{
low ++;
}
a[low] = a[high];
}
a[low] = key;
return low;
}
void quick_sort(int a[], int low, int high)
{
if(low < high)
{
int pos = find_pos(a, low, high);
quick_sort(a, low, pos-1);
quick_sort(a, pos+1,high);
}
}
int main()
{
int a[5] = {9, 8, 2, 5, 1};
quick_sort(a, 0, 4);
for(int i=0; i<5; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}