《数据结构》初学者笔记
来源:互联网 发布:刘宇的喜欢lofter乐乎 编辑:程序博客网 时间:2024/06/06 08:25
一.数据结构绪论
1.概述
定义:我们如何把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能而执行的相应操作,这个相应的操作也叫算法。
数据结构:个体+个体的关系
算法=对存储数据的操作
算法
衡量算法的标准:
①时间复杂度:程序执行的次数,非执行的时间
②空间复杂度:算法执行过程中大概所占用的最大内存。
③难易程度
④健壮性
2.预备知识
指针(所有的指针变量只占4个字节)
①重要性:指针是C语言的灵魂
②定义:地址:内存单元的编号 从0开始的非负整数 范围:0-FFFFFFFFF(4G-1) CPU和内存联系有三根线:地址线,控制线和数据线
指针:指针就是地址,地址就是指针 指针变量是存放内存单元地址的变量。指针的本质是一个操作受限的非负整数。
③分类:
基本类型的指针
#include <stdio.h>
int main()
{
int*p;
int i=10;
int j;
p=&i;
j=*p;
printf("p=%d,i=%d,j=%d\n",*p,i,j);
return 0;
}
例:通过被调函数修改主函数的值
#include<stdio.h>
void f(int* p)
{
*p=100;
return;
}
int main()
{
int i=1;
f(&i);
printf("i=%d\n",i);
return 0;
}
指针和数组的关系
a[3]=*(a+3);
例:输出数组
#include<stdio.h>
void shuchu(int* p,int q)
{
int i;
for(i=0;i<q;++i)
{
printf("%d\n",*(p+i));
}
return;
}
int main()
{
int a[5]={1,2,3,4,5};
shuchu(a,5);
return 0;
}
④结构体
为什么会出现结构体:为了表示一些复杂的数据,而普通的基本类型变量无法满足其要求
什么叫结构体:结构体是用户根据实际需要自己定义的复合数据类型
如何使用结构体
#include<stdio.h>
#include<string.h>
struct student
{
char name[100];
int age;
int id;
};
void shuchu(struct student* pst)
{
printf("%s,%d,%d\n",pst->name,pst->age,pst->id);
return;
}
int main()
{
struct student st1={"张三",18,001 };
struct student st2;
st2.age=17;
st2.id=002;
strcpy(st2.name,"李四");
struct student st3;
struct student* pst;
pst=&st3;
pst->age=18;
pst->id=003;
strcpy(pst->name,"朱智睿");
shuchu(&st1);
shuchu(&st2);
shuchu(&st3);
return 0;
}
注意事项:
结构体变量不能加减乘除,但可以相互赋值;普通结构体变量和结构体指针变量作为函数传参的问题
⑤动态内存的分配和释放
#include<stdio.h>
#include<malloc.h>
int main()
{
int len,i,j;
printf("请输入数组长度\n");
scanf("%d",&len);
int* parr;
parr=(int*)malloc(sizeof(int)*len);
for(j=0;j<len;++j)
{
scanf("%d",&parr[j]);
}
printf("数组输出如下\n");
for(i=0;i<len;++i)
{
printf("%d\n",parr[i]);
}
return 0;
}
二.模块一:线性结构(把所有的结点用一根直线穿起来)
1.连续存储【数组】
① 什么叫做数组:元素类型相同,大小相等
②数组的优缺点:
优点:存取速度很快
缺点:插入、删除元素很慢。空间通常有限制的。
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
struct arr
{
int* pbase;
int len;
int cnt;
};
void init(struct arr* parr,int length)
{
parr->pbase=(int*)malloc(sizeof(int)*length);
if(NULL==parr->pbase)
{
printf("动态内存分配失败\n");
exit(-1);
}
else
{
parr->len=length;
parr->cnt=0;
}
return;
}
int is_empty(struct arr* parr)
{
if(0==parr->cnt)
return 0;
else
return 1;
}
void show(struct arr* parr)
{
int i;
if(0==is_empty(parr))
{
printf("该数组为空\n");
}
else
{
for(i=0;i<parr->cnt;++i)
{
printf("%d\n",parr->pbase[i]);
}
}
}
int main()
{
struct arr arr;
init(&arr,6);
show(&arr);
return 0;
}
typedef的用法举例:
#include<stdio.h>
#include<string.h>
typedef struct student
{
char name[100];
int age;
}* pst,st;
int main()
{
st st1;
strcpy(st1.name,"朱智睿");
st1.age=18;
printf("%s %d\n",st1.name,st1.age);
st st2;
pst pst2= &st2;
strcpy(pst2->name,"张三");
pst2->age=17;
printf("%s %d\n",pst2->name,pst2->age);
return 0;
}
2.离散存储【链表】
优点:空间没有限制;插入、删除元素很快
缺点:存取速度很慢
①定义:n个节点离散分配,彼此通过指针相连,每个节点只有一个前驱结点,每个节点只有一个后续节点。首节点没有前驱结点,尾节点没有后续节点
专业术语:
首节点:第一个有效的节点
尾节点:最后一个有效节点
头结点:并不存放有效数据,目的在于方便对链表的操作 头结点的数据类型和首节点类型一样
头指针:指向头结点的指针变量
尾指针:指向尾节点的指针变量
确定一个链表需要几个参数:头指针,因为我们通过头指针我们可以推算出链表的其他所有信息
②分类
单链表
双链表:每一个节点有两个指针域
循环链表:通过任何一个节点找到其他所有节点
非循环链表
③算法:狭义的算法是与数据的存储方式密切相关,广义的算法是与存储方式无关。
泛型:利用某种技术达到的效果就是:不同的存储方式,执行的操作是一样的。
遍历:
void travelse_list(pNode pHead)
{
pNode p=pHead->pNext;
while(p!=NULL)
{
printf("%d\n",p->data);
p=p->pNext;
}
printf("链表遍历结束\n");
return;
查找
清空
销毁
是否为空与求长度:
void is_empty(pNode pHead)
{
if(NULL==pHead->pNext)
printf("链表为空\n");
else
printf("链表不为空\n");
return;
}
void length_is(pNode pHead)
{
pNode p=pHead->pNext;
int i=0;
while(p!=NULL)
{
++i;
p=p->pNext;
}
printf("链表的长度为%d\n",i);
return;
}
排序:
函数例
void sort_list(pNode pHead)
{
int len=0;
pNode a=pHead;
while(a!=NULL)
{
++len;
a=a->pNext;
}
int i,j,k;
pNode p,q;
for(i=0,p=pHead->pNext;i<len-1;++i,p=p->pNext)
{
for(j=i+1,q=p->pNext;j<len-1;++j,q=q->pNext)
{
if((p->data)>(q->data))
{
k=p->data;
p->data=q->data;
q->data=k;
}
}
}
return;
}
删除节点(伪算法):r=p->pnext; p->pnext=p->pnext->pnext; free(r);
函数例:
void delete_list(pNode pHead,int pos)
{
pNode p=pHead;
int i=0;
int val;
while(i<pos-1 && p->pNext!=NULL)
{
p=p->pNext;
++i;
}
if(i>pos-1 || p->pNext==NULL)
{
printf("创建待删除节点前的指针失败\n");
exit(-1);
}
pNode q=p->pNext;
q->data=val;
printf("您删除节点的数据为%d\n",val);//显示错误!
p->pNext=p->pNext->pNext;
free(q);
q=NULL;
}
插入节点(伪算法): q->pnext=p->pnext; p->pnext=q r=p->pnext; p->pnext=q; q->pnext=r;
函数例:
void insert_list(pNode pHead,int pos,int val)
{
pNode p=pHead;//初始化
int i=0;
while(i<pos-1 && p!=NULL)
{
p=p->pNext;
++i;
}
if(i>pos-1 || p==NULL)
{
printf("在待插入节点前创建指针失败\n");
exit(-1);
}
pNode pNew=(pNode)malloc(sizeof(Node));
if(NULL==pNew)
{
printf("创建插入节点失败\n");
exit(-1);
}
pNew->data=val;//谨记
pNode q=p->pNext;
p->pNext=pNew;
pNew->pNext=q;
}
①单链非循环链表 功能:遍历
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node
{
int data;
struct Node* pNext;
}Node,*pNode;
pNode create_list()
{
int len,i,val;//len代表结点的个数,val临时存放每个结点的数据域
pNode pHead=(pNode)malloc(sizeof(Node));//创建头结点
if(NULL==pHead)
{
printf("链表创建失败\n");
exit(-1);
}
pNode pTail=pHead;//使pTail永远指向尾节点
pTail->pNext=NULL;
printf("请输入将要创建结点的个数\n");
scanf("%d",&len);
for(i=1;i<=len;++i)
{
printf("请输入第%d个节点存放的数据\n",i);
scanf("%d",&val);
pNode pNew=(pNode)malloc(sizeof(Node));
if(NULL==pNew)
{
printf("数据存放失败\n");
exit(-1);
}
pNew->data=val;
pTail->pNext=pNew;
pNew->pNext=NULL;
pTail=pNew;
}
return pHead;
}
void travelse_list(pNode pHead)
{
pNode p=pHead->pNext;
while(p!=NULL)
{
printf("%d\n",p->data);
p=p->pNext;
}
printf("链表遍历结束\n");
return;
}
int main()
{
pNode pHead=NULL;
pHead=create_list();
travelse_list(pHead);
return 0;
}
② 单链非循环链表 全功能
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node
{
int data;
struct Node* pNext;
} Node,*pNode;
pNode create_list()
{
int len,i,val;
printf("请输入将要创建结点的个数\n");
scanf("%d",&len);
pNode pHead=(pNode)malloc(sizeof(Node));
if(pHead==NULL)
{
printf("链表创建失败\n");
exit(-1);
}
pNode pTail=pHead;
pTail->pNext=NULL;
for(i=1;i<=len;++i)
{
printf("请输入第%d个节点将要存储的数据\n",i);
scanf("%d",&val);
pNode pNew=(pNode)malloc(sizeof(Node));
if(pNew==NULL)
{
printf("存储数据失败\n");
exit(-1);
}
pNew->data=val;
pTail->pNext=pNew;
pNew->pNext=NULL;
pTail=pNew;
}
printf("程序结束\n");
return pHead;
}
void traverse_list(pNode pHead)
{
pNode p=pHead->pNext;
while(p!=NULL)
{
printf("%d\n",p->data);
p=p->pNext;
}
return;
}
void is_empty(pNode pHead)
{
if(NULL==pHead->pNext)
printf("链表为空\n");
else
printf("链表不为空\n");
return;
}
void length_is(pNode pHead)
{
pNode p=pHead->pNext;
int i=0;
while(p!=NULL)
{
++i;
p=p->pNext;
}
printf("链表的长度为%d\n",i);
return;
}
void sort_list(pNode pHead)
{
int len=0;
pNode a=pHead;
while(a!=NULL)
{
++len;
a=a->pNext;
}
int i,j,k;
pNode p,q;
for(i=0,p=pHead->pNext;i<len-1;++i,p=p->pNext)
{
for(j=i+1,q=p->pNext;j<len-1;++j,q=q->pNext)
{
if((p->data)>(q->data))
{
k=p->data;
p->data=q->data;
q->data=k;
}
}
}
return;
}
void insert_list(pNode pHead,int pos,int val)
{
pNode p=pHead;//初始化
int i=0;
while(i<pos-1 && p!=NULL)
{
p=p->pNext;
++i;
}
if(i>pos-1 || p==NULL)
{
printf("在待插入节点前创建指针失败\n");
exit(-1);
}
pNode pNew=(pNode)malloc(sizeof(Node));
if(NULL==pNew)
{
printf("创建插入节点失败\n");
exit(-1);
}
pNew->data=val;//谨记
pNode q=p->pNext;
p->pNext=pNew;
pNew->pNext=q;
}
void delete_list(pNode pHead,int pos)
{
pNode p=pHead;
int i=0;
int val;
while(i<pos-1 && p->pNext!=NULL)
{
p=p->pNext;
++i;
}
if(i>pos-1 || p->pNext==NULL)
{
printf("创建待删除节点前的指针失败\n");
exit(-1);
}
pNode q=p->pNext;
q->data=val;
printf("您删除节点的数据为%d\n",val);//显示错误!
p->pNext=p->pNext->pNext;
free(q);
q=NULL;
}
int main()
{
pNode pHead=NULL;
pHead=create_list();
traverse_list(pHead);
is_empty(pHead);
length_is(pHead);
sort_list(pHead);
traverse_list(pHead);
int i,j;
printf("请输入要插入的节点数与将要插入的数据\n");
scanf("%d %d",&i,&j);
insert_list(pHead,i,j);
traverse_list(pHead);
int k;
printf("请输入将要删除的节点\n");
scanf("%d",&k);
delete_list(pHead,k);
traverse_list(pHead);
return 0;
}
3.线性结构的两种常见应用——栈(先进后出)
定义:一种可以实现“先进后出”的存储结构(局部变量,静态存储)
分类:静态栈 动态栈
动态栈举例:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node
{
int data;
struct Node* pNext;
}Node,*pNode;
typedef struct Stack
{
pNode Top;
pNode Bottom;
}Stack,*pStack;
void init(pStack stack)
{
stack->Top=(pNode)malloc(sizeof(Node));
if(stack->Top==NULL)
{
printf("创建空栈失败\n");
exit(-1);
}
stack->Bottom=stack->Top;
stack->Top->pNext=NULL;
return;
}
void push(pStack stack,int val)
{
pNode pNew=(pNode)malloc(sizeof(Node));
if(pNew==NULL)
{
printf("数据入栈失败\n");
exit(-1);
}
pNew->data=val;
pNew->pNext=stack->Top;//谨记,位置交换亦不可行。
stack->Top=pNew;
return;
}
void traverse_stack(pStack stack)
{
pNode p=stack->Top;
while(p!=stack->Bottom)
{
printf("%d\n",p->data);
p=p->pNext;
}
return;
}
void pop(pStack stack)
{
if(stack->Top==stack->Bottom)
{
printf("空栈无法出栈\n");
exit(-1);
}
else
{
pNode p=stack->Top;
stack->Top=p->pNext;
printf("出栈的数字为%d\n",p->data);
free(p);
p=NULL;
}
return;
}
void clear(pStack stack)
{
if(stack->Top==stack->Bottom)
{
printf("已是空栈,无需清空\n");
exit(-1);
}
else
{
pNode p=stack->Top;
pNode q;
while(p!=stack->Bottom)
{
q=p->pNext;
free(p);
p=q;
}
printf("栈已清空\n");
}
return;
}
int main()
{
Stack stack;
init(&stack);
int len,val,i;
printf("您想要入栈几个数据?\n");
scanf("%d",&len);
for(i=1;i<=len;++i)
{
printf("请输入第%d个数据 ",i);
scanf("%d",&val);
push(&stack,val);
}
traverse_stack(&stack);
pop(&stack);
printf("出栈一次后的栈遍历为\n");
traverse_stack(&stack);
clear(&stack);
return 0;
}
算法:
出栈
压栈
应用:函数调用 中断 表达式求值 内存分配 缓冲处理 走迷宫
4.线性结构的两种常见应用——队列(先进先出)
定义:一种可以实现先进先出的存储结构(排队)
分类:
链式队列【链表】
静态队列【数组】
静态队列通常都必须是循环队列
循环队列的讲解:
①静态队列为什么必须是循环队列
②循环队列需要几个参数来确定:front rear
不同场合有不同含义:
队列初始化:front和rear的值为零
队列非空 :front代表队列第一个元素,rear代表的是最后一个有效元素的下一个元素
队列空:front和rear的值相等,但不一定为零
③循环队列入队伪算法讲解
将值存入rear所代表的位置->rear=(rear+1)%数组的长度
④出队伪算法讲解
front=(front+1)%数组的长度
⑤如何判断循环队列是否为空:front与rear相等则为空
⑥如何判断循环队列是否已满:
多增加一个标志参数
少用一个元素(front和rear紧挨着,则已满): (rear+1)%数组长度==front
队列算法:入队 出队
举例:基础功能
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Queue
{
int* pBase;
int front;
int rear;
} Queue,*pQueue;
void init(pQueue queue)
{
queue->front=queue->rear;
queue->front=NULL;
queue->rear=NULL;
printf("已建立初始队列\n");
return;
}
void in_queue(pQueue queue,int len)
{
if((queue->front+1)%len==queue->rear)
{
printf("队列已满,无法输入\n");
exit(-1);
}
else
{
queue->pBase=(int*)malloc(len*sizeof(int));
int i,val;
for(i=0;i<len-1;++i)//数据的个数只能是容量-1
{
printf("请输入第%d个入队的数据 ",i+1);
scanf("%d",&val);
queue->pBase[queue->rear]=val;
queue->rear=(queue->rear+1)%len;
}
}
return;
}
void traverse_queue(pQueue queue,int len)
{
int a=queue->front;
while(a!=queue->rear)//谨记,判定方法的不一样
{
printf("%d ",queue->pBase[a]);
++a;
}
return;
}
void out_queue(pQueue queue,int len)
{
if(queue->front==queue->rear)
{
printf("空队列无法出队\n");
exit(-1);
}
else
{
int p=queue->front;
int val,i,a;
printf("在%d个数据中出队几个?",len-1);
scanf("%d",&a);
for(i=0;i<a;++i)
{
val=queue->pBase[p];
printf("第%d个出队的数据为%d\n",(i+1),val);
++p;
}
}
return;
}
int main()
{
Queue queue;
init(&queue);
int len;
printf("输入该队列的容量\n");
scanf("%d",&len);
in_queue(&queue,len);
traverse_queue(&queue,len);
out_queue(&queue,len);
return 0;
}
应用:所有和时间有关的操作都与队列有关
5.递归
递归满足的三个条件:
①必须有个明确的终止条件
②该函数所处理的数据规模必须在递减
③这个转化必须是可解的
定义:一个函数自己直接或间接调用自己(用栈来实现)
①1+2+3+4+。。。+100的和(稍加进化)
#include<stdio.h>
long recursion(int n)
{
int sum;
if(1==n)
return 1;
else
{
sum=n+recursion(n-1);
}
return sum;
}
int main()
{
int n;
printf("请输入逐一相加到的数字 ");
scanf("%d",&n);
printf("逐一相加的和为%d",recursion(n));
return 0;
}
②求阶乘
#include<stdio.h>
long recursion(int i)
{
int fac;
if(1==i)
{
return 1;
}
else
{
fac=i*recursion(i-1);
}
return fac;
}
int main()
{
int i;
printf("请输入想要阶乘的数字 ");
scanf("%d",&i);
printf("%d的阶乘为%d",i,recursion(i));
return 0;
}
③汉诺塔
伪算法:
if(n>1)
先把A柱子上的前n-1个盘子从A借助C移到B
将A柱子上的第n个盘子直接移到C
再将B柱子上的n-1个盘子借助A移到C
#include<stdio.h>
void hnt(int n,char A,char B,char C)//变量A接收放置盘子的柱子,变量B接收借助的柱子 ,变量C是目的柱子
{
if(1==n)
{
printf("将编号为%d的盘子从%c柱挪动到%c柱\n",n,A,C);
}
else
{
hnt(n-1,A,C,B);//接下来为汉诺塔伪算法的三个步骤 ,A柱与B柱在递归中相互转换,故用形参表示
printf("将编号为%d的盘子从%c柱挪动到%c柱\n",n,A,C);
hnt(n-1,B,A,C);
}
return;
}
int main()
{
char ch1='A';
char ch2='B';
char ch3='C';
int n;
printf("请输入挪用盘子的个数 ");
scanf("%d",&n);
hnt(n,'A','B','C');
return 0;
}
④走迷宫
循环和递归:
递归:易于理解,速度慢,存储空间较大
循环:不易理解,速度很快,存储空间小
递归的应用:树和森林就是以递归的方式定义的,树和图的很多算法都是以递归来实现的
很多数学公式就是以递归的方式定义的。
三.模块二:非线性结构
1.树
定义:有且只有一个称为“根”的节点,有若干个互不相交的子树,这些子树本身也是一棵树。
(树是由节点和边组成;每个节点只有一个父节点,但可以有多个子节点;根节点例外,没有父节点)
专业术语:
节点 父节点 子节点
子孙 堂兄弟
深度:从根节点到最底层节点的层数称之为深度,根节点是第一层
叶子节点:没有子节点的节点
非终端节点:实际就是非叶子节点
度:子节点的个数
分类
一般树:任意一个节点的子节点的个数都不受限制
二叉树:任意一个节点的子节点个数最多两个、且子节点的位置不可更改
分类:
一般二叉树
满二叉树:在不增加树的层数的前提下,无法再多添加一个节点的二叉树【完全二叉树的特例】
完全二叉树:如果只是删除了满二叉树最底层最右边的连续若干个节点后形成的二叉树
森林:n个互不相交的树的集合
树的存储
二叉树的存储
连续存储【完全二叉树】
优点:查找某个节点的父节点和子节点(包括各种判断)速度很快
缺点:耗用内存空间过大
链式存储(一个数据域,两个指针域)
一般树的存储
双亲表示法(左侧存放真正数据,右侧存放的是父节点的下标)
孩子表示法(左侧存放数据,右侧为指针域指向所有孩子节点)
双亲孩子表示法(左侧存放数据,中间存放父节点下标,右侧为指针域指向所有孩子节点)
二叉树表示法
把一个普通树转化成二叉树来存储
设法保证任意一个节点左指针域指向它的第一个孩子,右指针域指向它的兄弟节点
一个普通树转化成的二叉树一定没有右子树
森林的存储(与一般树的存储中的二叉树表示法相仿)
有关操作
遍历
先序遍历:先访问根节点,再先序访问左子树,再先序访问右子树
中序遍历:中序遍历左子树,再访问根节点,再中序遍历右子树
后序遍历:后序左子树,再后序遍历右子树,最后访问根节点
已知两种遍历序列求原始二叉树(按照递归原则):通过先序和中序,中序和后序可以还原原始二叉树,但是通过先序和后序无法还原
CSDN关于二叉树遍历的文章http://zcheng.ren/2016/08/01/%E3%80%90%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95%E3%80%91%E5%85%A8%E9%9D%A2%E5%89%96%E6%9E%90%E6%A0%91%E7%9A%84%E5%90%84%E7%B1%BB%E9%81%8D%E5%8E%86%E6%96%B9%E6%B3%95/?ref=myread
应用:
树是数据库中数据组织一种重要形式
操作系统父子进程的关系本身就是一颗树
面向对象语言中类的继承关系本身就是一棵树
赫夫曼树
链式二叉树代码(静态存储):
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Binary
{
char data;
struct Binary* pLchild;
struct Binary* pRchild;
} Binary,*pBinary;
pBinary create_binary()
{
pBinary pA=(pBinary)malloc(sizeof(Binary));
if(NULL==pA)
{
printf("创建A结点失败\n");
exit(-1);
}
pBinary pB=(pBinary)malloc(sizeof(Binary));
if(NULL==pB)
{
printf("创建B结点失败\n");
exit(-1);
}
pBinary pC=(pBinary)malloc(sizeof(Binary));
if(NULL==pC)
{
printf("创建C结点失败\n");
exit(-1);
}
pBinary pD=(pBinary)malloc(sizeof(Binary));
if(NULL==pD)
{
printf("创建D结点失败\n");
exit(-1);
}
pBinary pE=(pBinary)malloc(sizeof(Binary));
if(NULL==pE)
{
printf("创建E结点失败\n");
exit(-1);
}
pA->data='A';
pA->pLchild=pB;
pA->pRchild=pC;
pB->data='B';
pB->pLchild=pB->pRchild=NULL;
pC->data='C';
pC->pLchild=pD;
pC->pRchild=NULL;
pD->data='D';
pD->pLchild=NULL;
pD->pRchild=pE;
pE->data='E';
pE->pLchild=pE->pRchild=NULL;
return pA;
}
void pretraverse(pBinary pT)//先序遍历
{
if(NULL!=pT)
{
printf("%c\n",pT->data);
if(NULL!=pT->pLchild)
{
pretraverse(pT->pLchild);
}
if(NULL!=pT->pRchild)
{
pretraverse(pT->pRchild);
}
}
return;
}
void intraverse(pBinary pT)//中序遍历
{
if(pT!=NULL)
{
if(pT->pLchild!=NULL)
{
pretraverse(pT->pLchild);
}
printf("%c\n",pT->data);
if(pT->pRchild!=NULL)
{
intraverse(pT->pRchild);
}
}
return;
}
void posttraverse(pBinary pT)//后序遍历
{
if(pT!=NULL)
{
if(pT->pLchild!=NULL)
{
posttraverse(pT->pLchild);
}
if(pT->pRchild!=NULL)
{
posttraverse(pT->pRchild);
}
printf("%c\n",pT->data);
}
return;
}
int main()
{
pBinary pHead=create_binary();
int n;
printf("1.先序遍历 2.中序遍历 3.后序遍历\n");
scanf("%d",&n);
if(n==1)
{
printf("先序遍历为\n");
pretraverse(pHead);
}
else if(n==2)
{
printf("中序遍历为\n");
intraverse(pHead);
}
else
{
printf("后序遍历为\n");
posttraverse(pHead);
}
return 0;
}
2.图
四.模块三:查找和排序
查找:折半查找
排序:冒泡
插入
选择
快速排序(递归思想)
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
int findsort(int* array,int low,int high)
{
int val=array[low];
while(low<high)//需要循环
{
while(low<high && array[high]>=val)
--high;
array[low]=array[high];
while(low<high && array[low]<=val)
++low;
array[high]=array[low];
}
array[low]=val;//谨记
return low;
}
void quicksort(int* array,int low,int high)
{
int pos;
if(low<high)
{
pos=findsort(array,low,high);
quicksort(array,low,pos-1);
quicksort(array,pos+1,high);
}
return;
}
int main()
{
int len,i,n;
printf("您想要排序几个数字?\n");
scanf("%d",&len);
int* array=(int*)malloc(len*sizeof(int)) ;
if(array==NULL)
{
printf("创建排序数组失败\n");
exit(-1);
}
for(i=0;i<len;++i)
{
printf("请输入第%d位数据 ",i+1);
scanf("%d",&(array[i]));
}
quicksort(array,0,len-1);//谨记
for(n=0;n<len;++n)
{
printf("%d\n",array[n]);
}
return 0;
}
归并排序
排序和查找的关系:排序是查找的前提,排序是重点
Java中容器和数据结构相关知识
Iterator接口
Map
哈希表
0 0
- 《数据结构》初学者笔记
- 初学者笔记
- 初学者笔记
- 初学者学数据结构(一)
- 初学者学数据结构(二)
- 初学者学数据结构(三)
- wap初学者笔记
- Linux 初学者笔记
- linux 初学者笔记
- DWR初学者笔记
- C#初学者的笔记
- Oracle初学者笔记(一)
- 初学者笔记:dropdownlist
- 初学者的算法笔记
- Linux初学者笔记
- Linux初学者笔记 续
- Java初学者笔记
- Android初学者 小小笔记
- iOS layoutSubviews的作用和调用机制
- Android Studio基本设置
- Java IO(五):FileOutputStream
- 奇偶规则和非零环绕数规则
- ORACLE系统表静态数据字典,常用user视图表及其常用用法
- 《数据结构》初学者笔记
- 向下转型之简介
- C语言注意点总结
- poj 2506 Tiling
- 几种导入文件的区别
- 关于 状态机中的组合逻辑
- 将Java代码重构为Java8 Stream 风格三则示例
- poj 3461 Oulipo (KMP||hash)
- Cocos2d creator js 使用javascript制作扑克游戏