数据结构概述 
数据结构的定义 
如何把现实生活中大量而且复杂的问题,以特定的数据类型和存储结构保存到主存储器(内存)中 ,为了实现某个功能而执行的相关操作,该操作称之为算法。
数据结构=个体+个体之间的关系,数据结构研究的是如何把个体以及个体之间的关系表示出来然后存进内存的过程。
算法是对数据结构的操作过程。
算法:
算法的定义:解题的方法和步骤
算法的衡量标准
数据结构预备知识 
指针 
指针变量声明的时候需要指定指针所指地址中存储的数据类型,赋值的时候默认是该数据在内存中所占用第一个字节的地址,整个指针的范围是从该数据所占的第一个字节到数据的最后一个字节,即该数据类型的大小。 
定义:
指针是C语言的灵魂。 
1 2 3 4 5 6 7 8 9 10 11 12 13 #include  <stdio.h>  int  main (void ) {     int  * p;       int  i=10 ;     int  j;     p=&i;     j=*p;     printf ("i=%d,j=%d,*p=%d" ,i,j,*p);     return  0 ;      } 
指针与一维数组 
a[i]==*(a+i) a是数组,也是数组第一个数据的指针,指针加上中括号以及下标,表示获取该地址后移存储类型的i倍大小的地址存储的数据 
数组名:
字节:硬件所能读取的最小单位,单位为B,1K=1024B 
不同类型数据的大小不同,占的字节也就不同,同一个类型的数据所占的字节大小是固定的。而指针所指向的数据地址一般为数据所占的所有字节的第一个字节或者最后一个字节的地址。 
int、long、float占四个字节      short战两个字节       double占八个字节
指针变量存放数据的地址,地址都是四个字节,所以指针变量都是四个字节大小。 
指针的指针 声明指针相关的时候只需要看最后一个*号,该符号之前表示的是指针指向位置存储的数据类型。 
结构体 
结构体是用户根据实际需要自己定义的复合数据类型,自己定义的数据类型 。是Java中类的前身,但是结构体中没用方法,都是成员,成员类比属性。
1 2 3 4 5 6 7 8 9 10 11 struct  Student  {  int  sid; char  name[200 ]; int  age; }; struct  Student  st =1000 ,”zhagnsan”,20 }; struct  Student *pst =
malloc()函数的使用 
malloc函数用于动态获取内存 
1 2 3 4 int  *p=(int  *)malloc (sizeof (int )*5 );
普通函数使用过程的内存在函数结束之后就会自动释放,而通过malloc申请的内存不会自动释放,需要手动通过free函数就行释放 
数据结构详解 
数据结构分为线性结构和非线性结构。 
线性结构 
把所有结点用一根线串起来而定数据结构成为线性结构,线性结构的存储方式有顺序存储和离散存储两种。
顺序存储-数组 
动态数组指针实现 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 #include  <stdio.h>  #include <malloc.h>  #include  "stdlib.h"  struct  myarry {    int  size;     int  * Arry;     int  count; }; void  init (struct  myarry * myarry,int  len) { myarry->Arry=(int  *)malloc (sizeof  (int )*len);  if (myarry->Arry==NULL ){      printf ("分配失败" );      exit (-1 );  } else {      myarry->count=0 ;      myarry->size=len;  }     return ; } int  isempty (struct  myarry * myarry) {    if (myarry->count==0 ){                  return  1 ;     } else          return  0 ; } void  show (struct  myarry * myarry) {if (isempty( myarry)==1 ){    printf ("arry is null" );     return ; } else {     for (int  i=0 ;i<myarry->count;++i){         printf ("%d" ,myarry->Arry[i]);     }     printf ("\n" ); } } int  isfull (struct  myarry * myarry) {    if (myarry->count==myarry->size)         return  1 ;     else          return  0 ; } int  append (struct  myarry * myarry,int  value) {    if (isfull(myarry)==1 ){         printf ("arry is full,append fail" );         return  0 ;     } else {         myarry->Arry[(myarry->count)]=value;         (myarry->count)++;         return  1 ;     } } int  insert (struct  myarry * myarry,int  value,int  position) {    if (isfull(myarry)==1 ){         printf ("arry is full,insert fail" );         return  0 ;     } else {         if (position<0 ||position>myarry->size){             printf ("out of inedx for insert" );             return  0 ;         }         for (int  i=myarry->count;i>=position;i--) {                 myarry->Arry[i]=myarry->Arry[i-1 ];         }         myarry->Arry[position]=value;         (myarry->count)++;         return  1 ;     } } int  delete (struct  myarry * myarry,int  position,int  * value) {    if (isempty(myarry)==1 ){         printf ("arry is null,delete fail" );         return  0 ;     } else {         if (position<0 ||position>myarry->size){             printf ("out of inedx for delete" );             return  0 ;         }         *value=myarry->Arry[position];         for (int  i=position;i<myarry->count;i++) {             myarry->Arry[i]=myarry->Arry[i+1 ];         }         (myarry->count)--;         return  1 ;     } } int  inversion (struct  myarry * myarry) {    if (isempty(myarry)==1 ){         printf ("arry is null,delete fail" );         return  0 ;     } else {         int  i=0 ,j=myarry->count-1 ,temp;         while  (i<j){             temp=myarry->Arry[i];             myarry->Arry[i]=myarry->Arry[j];             myarry->Arry[j]=temp;             i++;             j--;         }         return  0 ;     } } int  sort (struct  myarry * myarry) {    if (isempty(myarry)==1 ){         printf ("arry is null,delete fail" );         return  0 ;     } else {         int  temp;         for (int  i=0 ;i<myarry->count;i++){             for (int  j=i+1 ;j<myarry->count;j++){                 if (myarry->Arry[i]>myarry->Arry[j]){                     temp=myarry->Arry[i];                     myarry->Arry[i]=myarry->Arry[j];                     myarry->Arry[j]=temp;                 }             }         }         return  1 ;     } } int  main (void )  {   struct  myarry   myarry ;    int  deletevalue;    init(&myarry,6 );        append(&myarry,1 );    append(&myarry,2 );    append(&myarry,3 );    append(&myarry,4 );    append(&myarry,5 );    append(&myarry,6 );    delete(&myarry,2 ,&deletevalue);     show(&myarry);    insert(&myarry,100 ,2 );    show(&myarry);    inversion(&myarry);     show(&myarry);     sort(&myarry);     show(&myarry); } 
typedef的使用 
typedef用于给已有的数据类型起一个别名。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 typedef  int  myint;typedef  int  * myintpoint;typedef  int  * myintpoint,myint;typedef  struct  Student {    int  id;     int  age; }  mystudent; typedef  struct  Student {    int  id;     int  age; } *  mystudentpoint; typedef  struct  Student {    int  id;     int  age; } *  mystudentpoint,mystudent; 
离散存储-链表 
链表 
链表的相关定义 
定义: 
离散存储的——n个节点离散分配 
线性结构——节点之间通过指针相连; 
每一个节点只有一个前驱结点和后继节点,除了首节点和尾节点,首节点为前驱,尾节点无后继; 
 
首节点:链表中的第一个节点,也是第一个存放有效数据的节点; 
尾节点:链表中最后一个存放有效数据节点; 
头结点:首节点前面指向首节点的一个节点,不存放有效数据,头结点的作用主要是方便对链表的操作;头结点和首节点的数据类型相同。 
头指针:指向头结点的指针变量 
尾指针:指向尾节点的指针变量 
当对一个链表进行操作的时候,需要的数据只有————头指针,通过头指针可以得到整个链表而定所有信息。
链表里的相关数据 
链表里的每一个数据的数据类型是相同的,通常用结构体进行表示。
1 2 3 4 typedef  struct   node {    int  data;     struct  node  * pnext ; } * pnode,node;   
链表的分类 
单向链表 
双向链表——两个指针域分别指向前一个数据和后一个数据; 
循环链表——首尾节点相连,能通过任何一个节点找到任意一个节点; 
非循环链表 
 
链表某一数据的插入和删除 
在q之后插入p 
1 2 3 4 5 6 7 temp=q->pnext; q->next=p; p->next=temp; p->pnext=q->pnext; q->next=p; 
删除q之后的数据 
1 2 3 4 5 6 7 8 q->pnext=q->pnext->pnext; temp=q->pnext; q->pnext=q->pnext->pnext; free (temp);
链表的初始化 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 typedef  struct  node  {    int  value;     struct  node  * pnext ; } node,*pnode; pnode init (void ) {     pnode phead=(pnode)malloc (sizeof  (node));     if (phead==NULL ){         printf ("init fail!!! " );         exit (-1 );     }     pnode plast=phead;     plast->pnext=NULL ;     int  number;     int  value;     printf ("enter your number:" );     scanf ("%d" ,&number);     for (int  i=0 ;i<number;i++){         printf ("enter the NO %d:" ,i+1 );         scanf ("%d" ,&value);         pnode pnew=(pnode)malloc (sizeof  (node));         if (phead==NULL ){             printf ("init fail!!! " );             exit (-1 );         }         plast->pnext=pnew;         pnew->value=value;         pnew->pnext=NULL ;         plast=pnew;     }     return  phead; } 
链表的遍历 
针对链表的遍历,只需要判断每一个数据的指针域是否为空即可遍历到最后一个节点。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 typedef  struct  node  {    int  value;     struct  node  * pnext ; } node,*pnode; void  travelList (pnode phead) {    pnode  ptemp=phead->pnext;     while  (ptemp!=NULL ){         printf ("%d\t" ,ptemp->value);         ptemp=ptemp->pnext;         i++;     }     printf ("\n" ); } 
链表的排序 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 int  len_list (pnode phead) {    int  i=0 ;     pnode  ptemp=phead->pnext;     while  (ptemp!=NULL ){         ptemp=ptemp->pnext;         i++;     }     return  i; } void  sort_list (pnode phead) {    int  len=len_list(phead);     int  i,j,t;     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->value>q->value){                t=p->value;                p->value=q->value;                q->value=t;            }        }     }                     for ( p=phead->pnext;p!=NULL ;p=p->pnext){         for (q=p->pnext;q!=NULL ;q=q->pnext){             if (p->value>q->value){                 t=p->value;                 p->value=q->value;                 q->value=t;             }         }     } } 
狭义上的算法与数据类型以及存储方式有关,广义上的算法与数据类型和存储方式无关; 
链表的插入 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void  insert (pnode phead,int  position,int  value) {    pnode p=phead;     int  i=0 ;     for (i;i<position,p->pnext!=NULL ;i++)     p=p->pnext;      } if (i>position||p->pnext==NUL){    return  0 ; } pnode pnew=(pnode)malloc (sizeof (pnode)); if ( pnew==NULL ){   printf ("fail" ); } pnew->pnext=p->pnext; pnew->value=value; p->pnext=pnew; 
链表的删除 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void  delete (pnode phead,int  position,int  * temp) {    pnode p=phead;     int  i;     for  ( i = 0 , p; i <position ; ++i) {         p=p->pnext;     }     if (i>position||p->pnext==NUL){     return  0 ; }    *temp=p->pnext->value;     pnode pnode1=p->pnext;     p->pnext=p->pnext->pnext;     free (pnode1); } 
栈 
栈分为静态栈和动态栈,静态栈基于数组实现,动态栈是基于链表实现的 
静态栈 
静态栈的实现靠数组
动态栈的实现 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 typedef  struct  Node {    int  data;     struct  Node  * pnext ; }node,* pnode; typedef  struct  stack {    pnode  ptop;     pnode pbottom; }stack ,*pstack; int   init (pstack pstack) {    pstack->pbottom=(pnode)malloc (sizeof  (pnode));     if ( pstack->pbottom==NULL ){         printf ("distribution fail!" );         return  0 ;     }     pstack->pbottom->pnext=NULL ;     pstack->ptop=pstack->pbottom;     return  1 ; } void  push (pstack pstack,int  value) {    pnode pnew=(pnode)malloc (sizeof  (pnode));     pnew->pnext=pstack->ptop;     pnew->data=value;     pstack->ptop=pnew; } int  pop (pstack pstack,int * pvalue) {    if (pstack->ptop==pstack->pbottom){         printf ("delete fail,stack is null!" );         return  0 ;     }     pnode p=pstack->ptop;     *pvalue=p->data;     pstack->ptop=p->pnext;     free (p);     return  1 ; } void  travel (pstack pstack) {    pnode p=pstack->ptop;     while  (p!=pstack->pbottom){         printf ("%d\n" ,p->data);         p=p->pnext;     } } int  clear (pstack pstack) {    pnode p=pstack->ptop;     pnode q=NULL ;     while  (p!=pstack->pbottom){      q=p->pnext;      free (p);      p=q;     }     pstack->ptop=pstack->pbottom;     return  1 ; } 
队列 
链式队列 
静态队列 静态队列通常必须是循环队列
静态队列实现思想 
如何实现队列的插入——入队
 
如何实现队列的删除——出队
 
判断队列是否为空
 
 
当然,当一个循环队列rear==front时候,可能为空也可能是满的,这时候就需要判断。 
判断队列是否已满有两种方法:
静态队列实现 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 typedef  struct  Queue {    int  *Pbase;     int  front;     int  rear; }Queue,* Pqueue; void  init (Pqueue pqueue) {    pqueue->Pbase=(int )malloc (sizeof  (int )*6 );     pqueue->front=0 ;     pqueue->rear=0 ; } int  isfull (Pqueue pqueue) {    if (pqueue->front==(pqueue->rear+1 )%6 ){         return  1 ;     } else          return  0 ; } int  input_queue (Pqueue pqueue,int  value) {    if (isfull(pqueue)) {         printf ("queue is full!\n" );         return  0 ; }     pqueue->Pbase[pqueue->rear]=value;     pqueue->rear=(pqueue->rear+1 )%6 ;     printf ("input success!\n" );     return  1 ; } int  output_queue (Pqueue pqueue,int * pvalue) {    if (pqueue->front==pqueue->rear)     {         printf ("queue is empty!" );         return  0 ;     }     *pvalue=pqueue->Pbase[pqueue->front];     pqueue->front=(pqueue->front+1 )%6 ;     return  1 ; } void  travle_list (Pqueue pqueue) {    int  i=pqueue->front;     while  (i!=pqueue->rear){         printf ("%d\n" ,pqueue->Pbase[i]);         i++;     } } 
函数的调用 
当在一个函数的运行期间调用另一个函数时,在运行被调函数之前,系统需要完成三件事: 
从被调函数返回主调函数之前,系统也要完成三件事 
当有多个函数相互调用时,按照“后调用先返回”的原则,上述函数之 间信息传递和控制转移必须借助”栈”来实现,即系统将整个程序运行时所需的数据空间安排在一个栈中, 每当调用一个函数时,就在栈顶分配一个存储区,进行压栈操作,每当一个函数退出时,就释放它的存储 区,就行出栈操作,当前运行的函数永远都在栈顶位置 .
非线性结构 
树 
树的定义 
专业定义:即整个树的构成依赖于子树,子树构成又依赖于子树的子树; 
通俗的定义:
相关属性 :
深度:  根节点到最底层节点的层数,根节点所在层数是第一层;**度:**树中子节点最多的节点的子节点个数; 
**叶子节点:**没有子节点的节点;当只有一个根节点的时候根节点也是叶子节点; 
非终端节点(非叶子节点) :不是叶子节点的节点,当根节点有子节点的时候就是非叶子节点; 
树的分类 
一般树 二叉树:  树中包含的各个节点的度不能超过 2,即只能是 0、1 或者 2;且子节点的顺序不可更改;**森林:**n个不相交的树的集合; 
 
二叉树分类 
完全二叉树 : 如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布 ,则此二叉树被称为完全二叉树。满二叉树 : 如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。  
树的存储 
二叉树的存储:
**顺序存储:**顺序存储必须把二叉树转换为完全二叉树,采用数组进行存储,存储树的数据,通过转化为完全二叉树来存储树的结构。最后达到通过存储的顺序结构就能够得到树的整体结构;
优点:可以迅速的查找某个节点的父节点和子节点;
缺点:占用内存过大;
**链式存储:**指针域指向子节点地址即可
树的存储表示: 
双亲表示法:在数组中,数据的指针域指向父节点数据的索引;
孩子表示法:在数组中,数据的指针域指向子节点数据的链表表示;
双亲孩子表示法:两个指针域分别指向父节点和子节点;
**二叉树表示法(孩子兄弟表示法):需要先将树装换为二叉树,在进行存储表示;转换方法:从根节点开始,左子节点指向第一个子节点,右子节点指向第一个兄弟节点;  转换的二叉树都没有右子树; 
二叉树遍历 
先序遍历 
针对一个二叉树,首先访问根节点,再访问根节点的左节点,最后访问根节点的右节点,访问中遇到的每一个节点都需要先访问对应子树的根节点,子树的左节点,子树的右节点;
先序遍历二叉树为: A-B-D-E-H-C-F-G-J 
中序遍历 
对于一个二叉树,首先访问左节点,再访问根节点,最后访问子节点,中途的每一个节点都需要按照左-中-右的顺序访问;
中序遍历二叉树为:D-B-H-E-A-F-C-G-J 
后序遍历 
对于一个二叉树,首先访问左节点,再访问右节点,最后访问根节点,中途每个节点的访问顺序相同;
后序遍历二叉树为:D-H-E-B-F-J-G-C-A 
所谓的前中后就是在哪一个位置放根节点,前序首先访问根节点,中序中间访问,后序最后访问; 
遍历的程序实现 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 typedef  struct  Btree {    int  data;     struct  Btree  * Lchildern ;     struct  Btree  * Rchildern ; }Btree,* pbtree; pbtree init (void  ) {     pbtree p1=(pbtree)malloc (sizeof  (struct  Btree));     pbtree p2=(pbtree)malloc (sizeof  (struct  Btree));     pbtree p3=(pbtree)malloc (sizeof  (struct  Btree));     pbtree p4=(pbtree)malloc (sizeof  (struct  Btree));     pbtree p5=(pbtree)malloc (sizeof  (struct  Btree));     p1->data=1 ;     p2->data=2 ;     p3->data=3 ;     p4->data=4 ;     p5->data=5 ;     p1->Lchildern=p2;     p1->Rchildern=p4;     p2->Lchildern=NULL ;     p2->Rchildern=p3;     p3->Lchildern=NULL ;     p3->Rchildern=NULL ;     p4->Lchildern=NULL ;     p4->Rchildern=p5;     p5->Lchildern=NULL ;     p5->Rchildern=NULL ;     return  p1; } void  travel (pbtree p) {    if (p!=NULL ){         printf ("%d" ,p->data);         if (p->Lchildern!=NULL )             travel(p->Lchildern);                  if (p->Rchildern!=NULL )             travel(p->Rchildern);              } }