数据结构
数据结构分为三个方面逻辑结构、存储结构、数据运算
逻辑结构分为:线性结构和非线性结构
线性结构---(线性表)(栈)(队)
非线性结构--(树结构)(图形结构)
数据存储结构-(顺序存储)(链表存储)(索引存储)(散列存储)数据运算----(排序)(插入)(删除)(修改)等
一、线性表
顺序存储:(优点)通过动态分配的一段连续地址进行存储,方法简单易实现
(缺点)在进行插入和删除的时候,移动的元素很多,如果插入或删除的元素较大的时候,效率低
链表存储:(优点)在链表中相邻的两个元素,物理地址不一定相邻,是通过动态分配的,运算快,效率高
(缺点) 要占用额外的存储空间存储元素之间的关系
1.顺序表(顺序存储)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct
{
int * data;//存放数组第一个元素
int cnt;//有效元素个数
int len;//数组长度
}sx,*sx_p;
void show_sx(sx_p s);//遍历
void init_sx(sx_p s,int len);//开辟空间
void delete_sx(sx_p s,int pos,int *val);//删除
bool insert_sx(sx_p s,int pos,int val);//插入
bool add(sx_p s,int val);//添加
bool empty(sx_p s);//是否为空
bool full(sx_p s);//是否满
#include "sx.h"
void init_sx(sx_p s,int len)
{
s->data = (int *)malloc(sizeof(int)*len);
if(s->data == NULL)
{
printf("分配失败!\n");
exit(-1);
}
else
{
s->cnt = 0;
s->len = len;
printf("分配成功--开辟了%d个字节\n",len);
}
return;
}
bool empty(sx_p s)
{
if(s->cnt == 0)
{
printf("empty!\n");
return true;
}
else
return false;
}
bool full(sx_p s)
{
if(s->cnt == s->len)
{
printf("Full!\n");
return true;
}
else
return false;
}
bool add(sx_p s,int val)
{
if(full(s));
s->data[s->cnt]=val;
(s->cnt)++;
}
bool insert_sx(sx_p s,int pos,int val)
{
if(full(s));
if(pos<1 || pos>s->cnt+1)
{
printf("没找到该元素!\n");
return false;
}
else
{
for(int i=s->cnt-1;i>=pos-1;i--)
{
s->data[i+1]=s->data[i];
}
s->data[pos-1]=val;
(s->cnt)++;
}
}
void delete_sx(sx_p s,int pos,int *val)
{
if(empty(s));
if(pos < 1 || pos >s->cnt)
{
printf("没找到要删除的元素\n");
exit(-1);
}
else
{
*val=s->data[pos-1];
for(int i=pos;i<s->cnt;i++)
{
s->data[i-1]=s->data[i];
}
(s->cnt)--;
return;
}
}
void show_sx(sx_p s)
{
if(empty(s));
else
{
for(int i=0;i<s->cnt;++i)
{
printf("%d ",s->data[i]);
}
puts("");
}
}
#include "sx.h"
int main()
{
sx s;
int val;
init_sx(&s,6);
add(&s,1);
add(&s,2);
add(&s,3);
add(&s,4);
add(&s,5);
show_sx(&s);
insert_sx(&s,1,100);
show_sx(&s);
delete_sx(&s,1,&val);
printf("删除的是:%d \n",val);
}
2.顺序表(离散存储/链表)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct n
{
int data;//数据域
struct n * next;//指针域
}node,*pnode;
pnode create_node();//创建节点
void print(pnode p);//输出数据
void empty(pnode p);//判断是否空
int len_lb(pnode p);//有几个节点
bool insert(pnode p,int pos,int val);//插入
bool delete_lb(pnode p,int pos,int *val);//删除
#include "lb.h"
pnode create_node()
{
int len,val;
//创建头节点
pnode head = (pnode)malloc(sizeof(node));
if(head == NULL)
{
printf("头节点创建失败!\n");
exit(-1);
}
//尾节点始终指向最后一个节点
pnode last = head;
last->next = NULL;
//开始创建节点
printf("您需要创建多少个节点: ");
scanf("%d",&len);
for(int i=0;i < len;++i)
{
printf("请输入第%d个节点的数据: ",i+1);
scanf("%d",&val);
pnode pnew = (pnode)malloc(sizeof(node));
if(pnew == NULL)
{
printf("新节点分配失败!\n");
}
pnew->data = val;
last->next = pnew;
pnew->next = NULL;
last = pnew;
}
printf("---------------\n");
//返回头节点
return head;
}
void print(pnode phead)
{
pnode head = phead->next;
if(head == NULL)
{
printf("没有创建节点\n");
}
while(head != NULL)
{
printf("%d ",head->data);
head=head->next;
}
puts("");
}
void empty(pnode p)
{
if(p->next == NULL)
{
printf("链表为空\n");
exit(-1);
}
}
int len_lb(pnode p)
{
int len = 0;
while(p->next != NULL)
{
len++;
p=p->next;
}
return len;
}
bool insert(pnode p,int pos,int val)
{
int i = 0;
while(p->next != NULL && pos-1 > i)
{
p=p->next;
i++;
}
if(p->next == NULL || pos-1 < i)
{
printf("没找到该节点\n");
return false;
}
pnode pnew = (pnode)malloc(sizeof(node));
if(pnew == NULL)
{
printf("分配失败\n");
}
pnew->data = val;
pnode old = p->next;
p->next = pnew;
pnew->next = old;
return true;
}
bool delete_lb(pnode p,int pos ,int *val)
{
int i = 0;
while(p->next != NULL && pos-1 > i)//指向pos的这个位置
{
p=p->next;
i++;
}
if(p->next == NULL || pos-1 < i)
{
printf("没找到该节点\n");
return false;
}
pnode old = p->next;
*val=old->data;
p->next=p->next->next;
free(old);//防止内存泄漏
old = NULL;//防止野指针
return true;
}
#include "lb.h"
int main()
{
int cnt;
int val = 0;
pnode head;
head=create_node();
if(insert(head,2,100))
{
printf("插入成功\n");
}
print(head);
if(delete_lb(head,1,&val))
{
printf("删除成功,删除的是: %d \n",val);
}
print(head);
cnt = len_lb(head);
printf("有%d个有效元素\n",cnt);
return 0;
}
3.栈(栈也是一种存储方式,它采用的是先进后出原则)比如函数调用就运用的栈的方法
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node
{
int data;
struct node* next;
}node,*pnode;
typedef struct stack
{
pnode top;
pnode bottom;
}z,*sta;
void init_create(sta s);
void push(sta s,int val);
void print(sta s);
void pop(sta s,int *val);
void clear(sta s);
void init_create(sta s)
{
s->top = (pnode)malloc(sizeof(node));
if(s->top == NULL)
{
printf("分配内存失败\n");
exit(-1);
}
s->bottom = s->top;
return;
}
void push(sta s,int val)
{
pnode pnew = (pnode)malloc(sizeof(node));
if(pnew == NULL)
{
printf("分配内存失败\n");
exit(-1);
}
else
{
pnew->data = val;
pnew->next = s->top;
s->top = pnew;
}
return;
}
void print(sta s)
{
if(s->top == s->bottom)
{
printf("栈空\n");
exit(-1);
}
pnode p = s->top;
while(p != s->bottom)
{
printf("%d ",p->data);
p=p->next;
}
puts("");
return;
}
void pop(sta s,int *val)
{
if(s->top == s->bottom)
{
printf("empty\n");
exit(-1);
}
pnode p = s->top;
*val = p->data;
s->top = p->next;
free(p);
}
void clear(sta s)
{
if(s->top == s->bottom)
{
printf("empty\n");
exit(-1);
}
pnode p = s->top;
pnode q = NULL;
while(p != s->bottom)
{
q=p->next;
free(p);
p = q;
}
s->top = s->bottom;
}
#include "z.h"
void main()
{
z s;
int val;
init_create(&s);
push(&s,1);
push(&s,2);
push(&s,3);
push(&s,4);
push(&s,5);
push(&s,6);
print(&s);
pop(&s,&val);
printf("出站的是: %d \n",val);
print(&s);
printf("栈已清除\n");
clear(&s);
print(&s);
}
4.队列(队列特点是先进先出,可以分为动态队列,和静态)一般应用于关于时间的地方
静态队列必须用循环队列来实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct que
{
int *data;
int front;
int back;
}QUE;
void init(QUE * p);
void print(QUE * p);
void add(QUE *p,int val);
void out(QUE * p,int *val);
#include "que.h"
void main()
{
QUE que;
int val;
init(&que);
add(&que,1);
add(&que,2);
add(&que,3);
add(&que,4);
add(&que,5);
print(&que);
out(&que,&val);
printf("出队的是:%d \n",val);
print(&que);
}
#include "que.h"
void init(QUE * p)
{
p->data = (int *)malloc(sizeof(int )*6);
if(p->data == NULL)
{
printf("分配失败\n");
exit(-1);
}
else
{
p->front = 0;
p->back = 0;
}
return;
}
void print(QUE * p)
{
if(p->front == p->back)
{
printf("空的\n");
exit(-1);
}
else
{
int i = p->front;
while( i != p->back)
{
printf("%d ",p->data[i]);
i = (i +1)%6;
}
puts("");
}
return;
}
void add(QUE * p,int val)
{
if(p->front == (p->back + 1)%6)
{
printf("满的\n");
exit(-1);
}
else
{
p->data[p->back] = val;
p->back = (p->back+1 )%6;
}
return;
}
void out(QUE * p,int *val)
{
if(p->front == p->back)
{
printf("空的\n");
exit(-1);
}
else
{
*val = p->data[p->front];
p->front = (p->front + 1)% 6;
}
}
链式队列
#include <stdio.h>
typedef struct stu
{
int data;
struct stu * next;
}*pnode,node;
typedef struct
{
pnode front;
pnode rear;
}*p;
void init(p p1)
{
p1->rear = p1->front = NULL;
}
void rudui(p p1,int data)
{
p new = (pnode)malloc(sizeof(node));
if(new == NULL)
{
printf("创建节点失败\n");
exit(-1);
}
new->data = data;
new->next = NULL;
if(p1->rear == NULL)
{
p1->rear = new;
p1->front = new;
}
else
{
p1->rear->next = new;
p1 = new;
}
}
void chudui(p p1,int * val)
{
if(p1->rear == NULL)
{
printf("队列是空得\n");
}
pnode tmp = p1->front;
*val = tmp->data;
free(p1->front);
p1->front = tmp->next;
}
void print(p p1)
{
if(p1->rear == NULL)
{
printf("队列为空\n");
}
while(p1->rear)
{
printf("%d\n",p1->rear->data);
p1->rear = p1->rear->next;
}
}
void clear(p1 p)
{
if(p1->rear == NULL)
{
printf("队列为空\n");
}
pnode tmp = p1->rear;
pnode ttmp = NULL;
while(p1->rear)
{
ttmp = tmp->next;
free(tmp);
tmp = ttmp;
}
}
5.递归
递归的定义:自己调用自己
递归的应用:用于树,图,和一些数学算法,斐波那契数列
递归的方法:
1.必须有条件限制
2.必须数据规模是在递减
3.可以循环的代码一定可以用递归,但是递归的代码不一定用于循环
调用函数时:先把实际参数和下一个要执行的指令地址传给被调函数,被调函数的形参分配内存,返回运算的结果,并执行下一条指令,释放内存
#include <stdio.h>
/*阶乘*/
int jc(int i)
{
if(i == 1)
{
return 1;
}
else
{
return i*jc(i-1);
}
}
void main()
{
int i;
int s;
printf("请输入你需要求的阶乘数字: ");
scanf("%d",&i);
s = jc(i);
printf("%d的阶乘是%d\n",i,s);
}
6.二叉树
通过先序(根左右),中序(左根右),后序(左右根)遍历,一般是用先序进行创建,一个二叉树至少有一个节点(树),每个节点都有两个分支叫做满二叉树,一个分支是完全二叉树,二叉树用于存放非线性得数据,比如Linux的文件系统。
先中序遍历
#include <stdio.h>
typedef struct node
{
char data;
struct node * left;
struct node * right;
}*ptree,tree;
ptree init()
{
char ch;
printf("创建你的树\n");
scanf("%d",&ch);
if(ch == '#')
{
return NULL;
}
ptree s;
if((s = (tree)malloc(sizeof(tree))) == NULL)
{
printf("创建树失败\n");
return NULL;
}
s->data = ch;
s->left = init();
s->right = init();
return r;
}
void xianxu(ptree p1)
{
if(p1 == NULL)
{
printf("没有树\n");
}
printf("%d\n",p1->data);
xianxu(p1->left);
xianxu(p1->right);
}
void zhongxu(ptree p1)
{
if(p1 == NULL)
{
printf("没有树\n");
}
zhongxu(p1->left);
printf("%d\n",p1->data);
zhongxu(p1->right);
}
void hoxun(ptree p1)
{
if(p1 == NULL)
{
printf("没有树\n");
}
hoxun(p1->left);
hoxun(p1->right);
printf("%d\n",p1->data);
}
层次遍历(要用到队列)每次访问一个入队列,在出队列~(创建同上)
#include <stdio.h>
typedef struct stu
{
int data;
struct stu * next;
}*pnode,node;
typedef struct
{
pnode front;
pnode rear;
}*p;
void init(p p1)
{
p1->rear = p1->front = NULL;
}
void rudui(p p1,ptree p2)
{
p new = (pnode)malloc(sizeof(node));
if(new == NULL)
{
printf("创建节点失败\n");
exit(-1);
}
new->data = p2->data;
new->next = NULL;
if(p1->rear == NULL)
{
p1->rear = new;
p1->front = new;
}
else
{
p1->rear->next = new;
p1 = new;
}
}
void chudui(p p1)
{
if(p1->rear == NULL)
{
printf("队列是空得\n");
}
pnode tmp = p1->front;
//*val = tmp->data;
free(p1->front);
p1->front = tmp->next;
}
int empty(p p2)
{
if(p2->rear == NULL)
return null;
}
//层次遍历
void cenci(ptree p1)
{
p p2 = init(p2);
printf("%d\n",p1->data);
rudui(p2,p1);
while(!empty(p2))
{
chudui(p1);
if(p1->left)
{
printf("%d\n",p1->left->data);
rudui(p2,p1);
}
if(p1->right)
{
printf("%d\n",p1->right->data);
rudui(p2,p1);
}
}
}
7.快速排序
快速排序先找一个基准,使基准左边比基准小,基准右边比基准大,一般拿第一个元素作为基准;
规则:j 找 比 基准小的放到 i 中
i 找 比 基准大的放到 j 中
i = j,把基准放到空位
#include <stdio.h>
void main()
{
int arry[5] = {5,4,3,2,1};
sort(arry,0,4);
}
void sort(int arry[],int i,int j)
{
if(i > j)
{
return;
}
int p = arry[0];
while(i < j)
{
while(i < j && arry[j] >= p)
j--;
arry[i] = arry[j];
while(i < j && arry[i] <= p)
i++;
arry[j] = arry[i];
}
arry[i] = p;
sort(arry,i,i-1);
sort(arry,i+1,j);
}
8.哈希表(数组+链表)
哈希表是一中查找的方法,通过一个key快速找到数据对应的位置,就比如通讯录,你想找一个王二,那就可以通过w来锁定位置,而w就是哈希函数,可以通过除数取余法得到 key = key % n, n<=p (p为表长),但是假如找一个王三的人,他们都是w,那就形成了哈希冲突,通过链地址法就行处理,也就是把相同的进行从小到大排列。
#include <stdio.h>
#define N 15
typedef struct node
{
int data;//存放数据
inte key;//键值
struct node * next;
}*pnode,node;
typedef struct hx
{
node data[N];
}*pht,ht;
pht create()
{
pht hx = (pht)malloc(sizeof(ht));
if(hx == NULL)
{
printf("创建哈希表失败\n");
}
memset(hx,0,sizeof(ht))
return hx;
}
void insert(pht hx,int data)//插入
{
if(hx == NULL)
return;
pnode q;
pnode new = (pnode)malloc(sizeof(node));
new->data = data;
new->key = key % 13;
new->next = NULL;
q = &(hx->data[key % 13]);//指向哈希key地址
while(q->next && q->next->data < new->data)//解决哈希冲突
{
q = q->next;
}
new->next = q->next;
q->next = new;
}
pth search(pth hx,int data)
{
if(hx == NULL)
return;
while(hx->next && hx->next->data != data)
{
hx = hx->next;
}
if(hx->next == NULL)
{
return;
}
else
{
printf("found!\n");
return hx->next;
}
}