复习:
1、什么是数据结构?
专门研究数据关系和操作的学科,而非计算方法 数据结构+算法 = 程序
2、逻辑结构和物理结构
- 逻辑结构:
集合:除了同处于一个集合外数据元素之间没有任何关系
表:数据之间存在一对一的关系
树:数据之间存在一对多的关系
图:数据之间存在多对多的关系
- 物理结构:(存储结构)
顺序结构:数据直接存储在连续不间断的内存中,使用数据的相对位置来表示数据之间的关系
链式结构:数据时分散存储在内存的任何位置,数据项中有一块指针域来表示数据之间的关系
- 物理结构和逻辑结构的对应关系:
表:顺序结构、链式结构 都行
树:优先采用链式结构
图:顺序+链式 才好用
3、数据结构的运算
创建、销毁、清空、添加、删除、查询、修改、排序、遍历、访问、元素个数
4、表结构
顺序表:类似数组
链式表:链表
常考的面试题:链表和数组的优缺点?(自己总结!)
5、功能受限的表
栈:FILO 有且只有一个端口出
问题:如果top == 栈容量是否栈满?不同的栈结构设计导致这个问题无法断定
top初值:0 入栈 top++ 空增栈
top初值:-1 top++ 入栈 满增栈
top初值:cal-1 出栈 top-- 满减栈
top初值:cal top-- 出栈 空减栈
队列:FIFO 一个进一个出
练习:使用两个栈结构模拟队列结构
从栈A到栈B必须一个不留
栈B不空栈时、栈A不能找到栈B
typedef struct Queue
{
ArrayStack* s1;
ArrayStack* s2;
}Queue;
Queue* create_queue(size_t cal)
{
Queue* queue = malloc(sizeof(Queue));
queue->s1 = create_array_stack(cal);
queue->s2 = create_array_stack(cal);
return queue;
}
bool full_queue(Queue* queue)
{
return full_array_stack(queue->s1) && full_array_stack(queue->s2);
}
bool empty_queue(Queue* queue)
{
return empty_array_stack(queue->s1) && empty_array_stack(queue->s1);
}
bool push_queue(Queue* queue,TYPE val)
{
if(full_array_stack(queue->s1))
{
if(!empty_array_stack(queue->s2))
{
return false;
}
while(!empty_array_stack(queue->s1))
{
TYPE top = 0;
top_array_stack(queue->s1,&top);
pop_array_stack(queue->s1);
push_array_stack(queue->s2,top);
}
}
printf("push:%d\n",val);
return push_array_stack(queue->s1,val);
}
bool pop_queue(Queue* queue)
{
if(empty_array_stack(queue->s2))
{
if(empty_array_stack(queue->s1)) return false;
while(!empty_array_stack(queue->s1))
{
TYPE top = 0;
top_array_stack(queue->s1,&top);
pop_array_stack(queue->s1);
push_array_stack(queue->s2,top);
}
}
int top = -1;
top_array_stack(queue->s2,&top);
printf("pop:%d\n",top);
return pop_array_stack(queue->s2);
}
void destroy_queue(Queue* queue)
{
destroy_array_stack(queue->s1);
destroy_array_stack(queue->s1);
}
封装:尾添加的效率低,非法下标的判断效率也很低。
1、单链表
- 节点:数据域 指针域
- 数据项:头指针 尾指针 节点数量
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define TYPE int
typedef struct Node
{
TYPE data;
struct Node* next;
}Node;
typedef struct List
{
Node* head;
Node* tail;
size_t size;
}List;
Node* create_node(TYPE data)
{
Node* node = malloc(sizeof(Node));
node->data = data;
node->next = NULL;
return node;
}
List* create_list(void)
{
List* list = malloc(sizeof(List));
list->head = create_node(0); //only for tool
list->tail = NULL;
list->size = 0;
return list;
}
void add_head_list(List* list,TYPE data)
{
Node* node = create_node(data);
if(0 == list->size)
{
list->head->next = node;
list->tail = node;
}
else
{
node->next = list->head->next;
list->head->next = node;
}
list->size++;
}
void add_tail_list(List* list,TYPE data)
{
Node* node = create_node(data);
if(0 == list->size)
{
list->head->next = node;
list->tail = node;
}
else
{
list->tail->next = node;
list->tail = node;
}
list->size++;
}
bool del_head_list(List* list)
{
if(0 == list->size) return false;
Node* temp = list->head->next;
list->head->next = temp->next;
if(1 == list->size) list->tail = NULL;
free(temp);
list->size--;
return true;
}
bool del_tail_list(List* list)
{
if(0 == list->size) return false;
free(list->tail);
if(1 == list->size)
{
list->head->next =NULL;
list->tail = NULL;
}
else
{
Node* n = list->head->next;
while(n->next!=list->tail) n = n->next;
n->next = NULL;
list->tail = n;
}
list->size--;
return true;
}
bool insert_list(List* list,int index,TYPE data)
{
if(index < 0 || index >= list->size) return false;
Node* node = create_node(data);
Node* prev = list->head;
for(int i=0;i<index;i++)
{
prev = prev->next;
}
node->next = prev->next;
prev->next = node;
list->size++;
return true;
}
bool del_val_list(List* list,TYPE data)
{
if(data == list->head->next->data) return del_head_list(list);
if(data == list->tail->data) return del_tail_list(list);
for(Node* n = list->head->next;n->next != NULL;n= n->next)
{
if(n->next->data == data)
{
Node* temp = n->next;
n->next = temp->next;
free(temp);
list->size--;
return true;
}
}
return false;
}
bool del_index_list(List* list,int index)
{
if(index < 0 || index >= list->size) return false;
if(index == 0) return del_head_list(list);
if(index == list->size-1) del_tail_list(list);
Node* prev =list->head->next;
for(int i=1;i<index;i++)
{
prev = prev->next;
}
Node* temp = prev->next;
prev->next = temp->next;
free(temp);
list->size--;
return true;
}
bool modify_index_list(List* list,int index,TYPE data)
{
if(index < 0 || index >= list->size) return false;
Node* n = list->head->next;
for(int i=1;i<index;i++)
{
n = n->next;
}
n->data = data;
return true;
}
bool modify_val_list(List* list,TYPE old,TYPE data)
{
bool flag = false;
for(Node* n = list->head->next; n ; n = n->next)
{
if(n->data == old)
{
n->data = data;
flag = true;
}
}
return flag;
}
size_t query_list(List* list,TYPE data)
{
int cnt = 0;
for(Node* n = list->head->next;n->next != NULL;n= n->next)
{
if(data == n->data) return cnt;
cnt++;
}
return -1;
}
void sort_list(List* list)
{
for(Node* n = list->head->next;n->next != NULL;n=n->next)
{
for(Node* j=n->next;j;j=j->next)
{
if(n->data > j->data)
{
int temp = j->data;
j->data = n->data;
n->data = temp;
}
}
}
}
bool access_list(List* list,int index,TYPE* val)
{
if(index < 0 || index >= list->size) return false;
Node* n = list->head->next;
for(int i=0;i<index;i++)
{
n = n->next;
}
*val = n->data;
return true;
}
void clean_list(List* list)
{
while(list->tail) del_tail_list(list);
}
void destroy_list(List* list)
{
clean_list(list);
free(list->head);
free(list);
}
void show_list(List* list)
{
for(Node* n=list->head->next;n;n=n->next)
{
printf("%d ",n->data);
}
printf("\n");
}
int main(int argc,const char* argv[])
{
List* list = create_list();
for(int i=0;i<10;i++)
{
add_tail_list(list,i);
}
printf("original\n");
show_list(list);
for(int i=0;i<5;i++)
{
del_head_list(list);
}
printf("afte deling\n");
show_list(list);
insert_list(list,0,1000);
printf("after inserting\n");
show_list(list);
del_val_list(list,1000);
printf("after deling 1000\n");
show_list(list);
del_index_list(list,0);
printf("after deling index:0\n");
show_list(list);
modify_index_list(list,0,888);
printf("modify index:0 value to 888\n");
show_list(list);
modify_val_list(list,888,8888);
printf("modify 888 to 8888\n");
show_list(list);
printf("find index of 7\n");
printf("8888:index%d",query_list(list,7));
sort_list(list);
printf("after sort list\n");
show_list(list);
int num = 0;
access_list(list,0,&num);
printf("access index:0 of list is %d\n",num);
}
2、静态链表
节点:数据域 游标
静态链表的节点存储在连续的内存中,通过游标来访问下一个节点
原因:其他的高级语言没有指针
这种链表在插入删除时只能通过修改游标的值,而不用申请和释放内存来达到链式结构的目的
但是也是牺牲了随机访问的功能,是一种给没有指针的编译实现单链表
3、循环链表
链表的最后一个节点的next不再指向NULL,而是指向头节点,这种链表叫做单向循环链表
它的优点:可以在任何一个节点可以访问到链表中的任意节点,它的好处可以通过任意节点遍历整个链表
4、双向链表
双向循环链表
节点:前趋指针 数据域 后继指针
5、Linux的内核链表
6、通用链表