数据结构基础

目录

数据结构

常用的数据结构

数据结构的基本运算:增、删、改、查

算法的基本概念:

程序与算法的区分

如何判定算法的好坏

时间复杂度

顺序表

顺序表优缺点

单链表(不循环)

单向链表(循环)

链表的插入

双向链表

顺序栈和链式栈:先进后出

顺序队列和链式队列

顺序队列:

链式队列:

树的性质:

二叉树

二叉树性质:

二叉树的存储方式:

链式存储:

顺序存储:

遍历方式:

先序遍历:(递归)

中序遍历(递归)

后序遍历(递归)

层次遍历

特殊二叉数列

完全二叉树:

二叉查找树

平衡二叉树:

红黑树

总结

最优二叉树

构造最优二叉树

图的遍历方式

图的存储方式

深度优先 DFS

广度优先

排序

快速排序

非递归方式遍历二叉树:

先序:

中序


数据结构

数据结构指:数据的逻辑结构和存储结构及操作
数据:信息的载体
    数值型数据:整型、字符型、浮点型等
    非数值型数据:图像、视频、声音等
数据项:数据元素由若干个数据项组成,数据项是数据的最小单位
​

常用的数据结构

逻辑结构:
    1、集合:除了同属一个集合,再无其他关系
    2、线性结构: 一个对一个,如线性表、栈、队列。数据元素是一对一的关系,每一个节点之间存在前驱和后继的关系,当然除去第一个(没有前驱)和最后一个(没有后继)。
      线性结构按照存储类型可以分为:顺序表、顺序栈、顺序队列;链表、链栈、链队列。
    3、树状结构:一个对多个,如树。数据元素之间是一对多的关系,每一个元素都只能有一个前驱,可以有多个后继。前驱也叫父节点,后继也叫子节点。
    4、图:多个对多个
​
存储结构:顺序存储、链式存储、索引存储、散列存储
    

数据结构的基本运算:增、删、改、查

算法的基本概念:

1、程序:一组有序二进制指令、存储在磁盘、可以执行、静态(不会占用系统资源:cpu 内存等)
2、进程:运行起来的程序
3、算法:是一个有穷规则的有序集合

程序与算法的区分

算法特性:
    1、有穷性:算法执行步骤有限
    2、确定性:每个计算步骤无二义性
    3、可行性:每个计算步骤都可以在有限时间内完成
    4、输入:  算法有零个或多个外部输入
    5、输出:  算法有一个或多个输出
​
算法和程序既有联系既有不同
    相同:二者都是为了完成某个任务,或解决某个问题而编制而成的有序集合。
    区别:
        1、算法与计算机无关,程序依赖于具体的计算机语言
        2、算法必须是又穷尽的,但程序可以是无穷的
        3、算法可以忽略一些语法细节,重点在解决问题的思路上,但程序必须严格遵循语言工具的语法。算法必须转换成程序后才能在计算机上运行。

如何判定算法的好坏

1、消耗空间多少
2、消耗时间多少
3、容易理解、编程、调试、维护
​

时间复杂度

问题的规模 :输入数据量的大小,用n来表示。
算法消耗时间,它是问题规模的函数 T(n)。
​
时间复杂度:
1. 根据频度写出语句表达式
2. 常数项化为1
3. 保留最高阶,去除其余项
4. 最高阶如果乘数不为1,化为1
​

顺序表

顺序表本质上是程序员基于结构体构造的一种新的类型。
结构体中以一个数组作为顺序表身,一个下标标识。
​
特别的: 在顺序表中,typedef int data_t。用datd_t 代表整型。
        下标lsat 值为-1表示,表中无数据,last+1 表示数据长度。
数据表特点:内存空间连续存储

顺序表优缺点

优点:查询和修改快速方便
缺点:
    1、需要一片连续的空间
    2、增加和删除时涉及大量数据移动、耗时
    3、当数据表大小确定后不能再次修改。
    
不适合数据量的时候使用,对表的插入和删除等运算时间复杂度较差。
​
​
​
1、创建顺序表,last = -1
2、判空
3、判满
4、求长度
5、插入
6、删
7、改
8、清空
9、销毁
​
#define max 16
typedef int data_t;
typedef struct data_t{
    data_t data[max];
    int last;
}seqlist;
​
​
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 10
​
typedef int data_t;
typedef struct seq{  //构造顺序表类型
    data_t data[SIZE];
    int last;
}seqlist;
​
seqlist* creat_list(); 
int seqlist_is_empty(seqlist*);
int seqlist_is_full(seqlist*);
int seqlist_len(seqlist*);
int seqlist_initialise(seqlist*,int);
int seqlist_outpit(seqlist*);
int seqlist_add(seqlist* , int , int);
int seqlist_del(seqlist* , int );
data_t find_by_post(seqlist* , int );
data_t * find_by_data(seqlist* , data_t );
​
int main()
{
    int post,val,i,j;
    int data =0 ;
    seqlist* head =  creat_list(); //调用函数创建顺序表。
    if(NULL == head)
    {
        printf("申请空间失败。\n");
        exit(-1);
    }else{
        printf("申请空间成功。\n");
    }
    
    puts("输入赋值节点post <=9 :");
    scanf("%d",&post);
    int ret = seqlist_initialise(head,post); //给顺序表赋值
    if(0 == ret )
    {
        printf("赋值成功。\n");
    }else 
    {
        printf("赋值失败。ret = %d\n",ret);
        exit(-1);
    }
    seqlist_outpit(head);//打印
​
    
    printf("需要插入节点个数:\n");
    scanf("%d",&i);
    while(i--)
    {
    printf("输入节点 pos < 9,以及插入数据。用空格隔开。\n");
    scanf("%d%d",&post,&val);
    ret = seqlist_add( head,  post, val);//插入节点
    if(-1 == ret || -2 == ret || -3 == ret )
    {
        printf("程序出错,退出。ret = %d\n",ret);
        exit(-1);
    }
    seqlist_outpit(head);//打印
    }
​
    printf("输入需要删除的节点 post\n");
    scanf("%d",&post);
    seqlist_del(head, post);//删除节点
    seqlist_outpit(head);
    puts("输入需要查找的数值,data");
    scanf("%d",&data);
    data_t* postl = find_by_data(head,data);
    int len_post =postl[0];
    for( i = 1 ; i <= len_post ; i++)
    {
        printf("data = %d  post = %d \n",data,postl[i]);
    }
    return 0;
}
​
​
seqlist* creat_list()
{
    seqlist* head = (seqlist*)malloc(sizeof(seqlist));
    if(NULL == head)
        return NULL;
    memset(head->data,0,SIZE);
    head->last = -1;
    return head;
}
​
//判空
int seqlist_is_empty(seqlist* head)
{
    if(NULL == head)
        return -1;
    return ((head->last == -1)?1:0);
}
​
//判满
int seqlist_is_full(seqlist* head)
{
    if(NULL == head)
        return -1;
    return ((head->last +1 == SIZE)?1:0);
}
​
//求表长(实际元素个数)
int seqlist_len(seqlist* head)
{
    if(NULL == head)
        return -1;
    return head->last +1;
}
​
//赋初值
int seqlist_initialise(seqlist* head, int post)
{
    int i = 0;
    if(post < 0 || post > (SIZE-1))
        return -1;
    for(i = 0; i <= post ; i++)
    {
        head->data[i] = i;
    }
    head->last = post;
    return 0;
}
​
//打印当前顺序表
​
int seqlist_outpit(seqlist* head)
{
    if(NULL == head)
        return -1;
    int i = 0;
    for(i = 0; i <= head->last; i++)
    {
        printf("data[%d] = %d  ",i,head->data[i]);
    }
    puts("");
    return 0;
}
​
​
//增
int seqlist_add(seqlist* head, int post, int val)
{
    int i = 0 ;
    if(NULL == head)
        return -1;
    if(1 ==  seqlist_is_full(head) )
    {
        printf("表已经满,无法插入数据。");
        return -2;
    }
    if(post < 0 || post > head->last+1)
        return -3;
    for(i = head->last ; i >= post ; i--)
    {
        head->data[i+1] = head->data[i];
    }
    head->data[post] = val;
    head->last++;
    return 0;
}
​
//删
int seqlist_del(seqlist* head, int post)
{
    int i ;
    if(NULL == head )
        return -1;
    if(post < 0 || post > head->last)
        return -2;
    if( 1 == seqlist_is_empty(head))
    {
        printf("顺序表空,无法删除");
        return -3;
    }
​
    for(i = post ; i < head->last ; i++  )
    {
        head->data[i] = head->data[i+1];
    }
​
    head->last--;
​
    return 0;
}
​
//查
​
data_t find_by_post(seqlist *head , int post)
{
    if(NULL == head)
        return -1;
    if(1 == seqlist_is_empty(head))
        return -2;
    if(post < 0 || post > head->last )
        return -3;
​
    return head->data[post];
}//位置查询
​
data_t * find_by_data(seqlist* head, data_t data)
{
    int i ,j;
    if(NULL == head)  return NULL;
    if(1 == seqlist_is_empty(head)) return NULL;
    j=0; 
    for(i = 0; i < head->last; i++ )
    {
        if(head->data[i] == data)
        {
            j++;
        }
    }
    data_t *post = (data_t*)malloc(sizeof(data_t)*j+1);
    memset(post,0,sizeof(data_t)*j+1);
    j = 0 ;
    for(i = 0; i < head->last; i++ )
    {
        if(head->data[i] == data)
        {
            post[j+1] = i;
            j++;
        }
    }
    post[0] = j; 
    return post;
}//值查询
​
​
//清空表
int clean_seqlist(seqlist* head)
{
    if(NULL == head)
        return -1;
    head->last = -1;
    return 0;
}
​
//销毁表
int destroy_seqlist(seqlist** seq)
{
    if(NULL == *seq) return -1;
    free(*seq);
    *seq =  NULL;
}
​

单链表(不循环)

head->next = NULL

1、创建头节点
2、判空
3、求长度
4、插入:节点插入,头插
5、删
6、改
7、查
8、清空
9、销毁

typedef int data_t;
typedef struct data_t{
	data_t data;
	struct data_t* next;
}linklist;

linklist* head = (linklist*)malloc(sizeof(linklist));

head->data = -1;
head->next =NULL;

单向链表(循环)

typedef int data_t;
typedef struct data_t{
	data_t data;
	struct data_t* next;
}linklist;

linklist* head = (linklist*)malloc(sizeof(linklist));

head->data = -1;
head->next =head;
与单向不循环链表区别在于:循环链表 head->next = head;

链表的插入

链表插入节点,一般有头插、尾插。
其中头插能够倒置一个链表

双向链表

typedef struct list{
	data_t data;
	struct list* next; 
	struct list* prior;
}dlinklist;

    在结构上与单向链表区别在于:双向链表的每一个节点有两个结构体指针,分别指向上一个、下一个节点。
    

顺序栈和链式栈:先进后出

栈:限制在一端进行插入和删除的线性表,允许操作的一端称为“栈顶”,另一固定端称为“栈底”,当栈中没有元素时称为“空栈”。


顺序栈:特殊的顺序表

typedef int data_t
typedef strcut {
	data_t data[max];
	int top;
}seqstack_t;
top =-1;  清空栈


链式栈:头插法

顺序队列和链式队列

顺序队列:

队列:队列是限制在两端进行插入和删除操作的线性表,允许进行插入操作的一端称为“队尾“,允许进行删除操作的一端称为”队头“,当线性表中没有元素时,称为”空队“。

顺序队列:特殊的顺序表
typedef int date_t;
typedef struct {
	data_t data[max];
	int front;
	int rear;
}sequeue_t;
front :头下标(头元素);
rear:尾下标(尾元素下一个);


判断空:front = rear (空)
判断满:front = (rear+1)%size
长度: (rear - front+siez)%size

入队:
	head->data[head->real] = val;
    head->real = (head->real+1)%SIZE; 

出队:
 	data_t val =  head->data[head->front] ;
    head->front = (head->front+1)%SIZE; 




#include <stdio.h>
#include<stdlib.h>
#define MAX 80
#include<string.h>

typedef int data_t;
typedef struct data{
    data_t data[MAX];
     data_t front;//指向头
     data_t rear;//指向尾
}sequeue;



sequeue* create_seq();//创建顺序队列
int seqlist_is_empty(sequeue * seqlist);//判空
int seqlist_is_full(sequeue* seqlist);// 判满
int add_data_into_list(sequeue*seqlist ,int data);//加入队列
int del_data_list(sequeue* seqlist);//输出队列

int main(int argc, char *argv[])
{ 
    sequeue* seqlist = create_seq();
    
    /*int i =0,num ;
    for(i = 0; i< 5;i++)
    {
       num =  add_data_into_list(seqlist,i);
    }
    for(i =0 ;i< 5 ;i++)
    {
        printf("%d\n",del_data_list(seqlist));
    }*/


    tree_node* tree = create_tree();//创建二叉树
    level_print(tree,seqlist);//层次遍历二叉树


    return 0;
} 

sequeue* create_seq()//创建顺序队列
{
    sequeue* seqlist = (sequeue*)malloc(sizeof(sequeue));
    if(NULL == seqlist)
        return NULL;
    memset(seqlist->data,0,sizeof(seqlist->data));
    seqlist->front = 0;
    seqlist->rear = 0;
        
    return seqlist;
}

int seqlist_is_empty(sequeue * seqlist)//判空
{
    if(NULL == seqlist)
        return -1;
//    printf("seq->front = %d , reer = %d\n",seqlist->front,seqlist->rear);
    return ((seqlist->front == seqlist->rear)?1:0);
}

int seqlist_is_full(sequeue* seqlist)// 判满
{
    if(NULL == seqlist)
        return -1;
    return (((seqlist->rear+1)%MAX == seqlist->front)?1:0);
}

int add_data_into_list(sequeue*seqlist ,int data)//加入队列
{
    if(NULL == seqlist)
        return -1;
    if(1 == seqlist_is_full(seqlist))
        return -2;
    seqlist->data[seqlist->rear] =  data;
    seqlist->rear = (seqlist->rear+1)%MAX;
    return 0;
}


int del_data_list(sequeue* seqlist)//输出队列
{

    if(NULL == seqlist)
        return -1;
    if(1 == seqlist_is_empty(seqlist))
        return -1;
   int val =  seqlist->data[seqlist->front];
   seqlist->front = (seqlist->front+1)%MAX;
    return val;
}



链式队列:

typedef int data_t;
typedef struct node{
    data_t data;
    struct node* next;
}linklist;  //链表节点类型

typedef struct{
    linklist* front, *rear;  //和链表节点类型一致

}lqueue;  //构造链式队列结构

lqueue *create_lqueue()
{
    lqueue *lq = (lqueue*)malloc(sizeof(lqueue)); //创建链式队列头节点指针
    if(NULL == lq)
        return NULL;
   // linklist *front  = (linklist*) malloc(sizeof(linklist));  如果没有构造链式队列 应该这样创建两个指针 
    lq->front = (linklist*) malloc(sizeof(linklist)); //给链表头节点 空间并初始化
    lq->rear = lq->front;
   
    lq->rear->data  = -1;
    lq->rear->next  = NULL;
    return lq; 
}
//判空
int lqueue_is_empty(lqueue* lq)
{
    if(NULL ==lq)
        return -1;
    return((lq->front->next== lq->rear->next )?1:0);
}
//求链式队列长度
int get_length_lqueue(lqueue* lq)
{
    if(NULL == lq)
        return -1;
    int  num = 0;
    linklist* p=lq->front->next; 
    while(p!=NULL)
    {
        num++;
        p=p->next; 
    }
    return num;
}
//入队
int enlqueue(lqueue* lq,data_t vlu)
{
    if(NULL == lq)
        return -1;
    linklist *new = (linklist* )malloc(sizeof(linklist));
    new->data = vlu;
    new->next = NULL;

    lq->rear->next = new;  //把新节点接如链表
    lq->rear = new;        //尾指针往后偏移到新的尾节点
}
//出队
int delqueue(lqueue* lq)
{
    if(NULL == lq)
        return -1;
    if(lqueue_is_empty(lq) == 1)
        return -1;
    
    data_t data = lq->front->next->data;   // 第一个节点的数据

    linklist *p = lq->front->next;  // 备份 第一个节点地址
    lq->front->next   = p->next ;   // 重新连接第二个节点到队头
    
    free(p);
    return data; 
}
int main(int argc,const char *argv[])
{
    lqueue *lq = create_lqueue();
    if(NULL == lq)
        return -1;

    enlqueue(lq, 11);
    enlqueue(lq, 22);
    enlqueue(lq, 33);

    printf("%d\n", delqueue(lq));
    printf("%d\n", delqueue(lq));
    printf("%d\n", delqueue(lq));
    printf("%d\n", delqueue(lq));

    return 0;
}

概念:是一种非线性结构,数据之间的关系“一对多”,节点只能有一个前驱,可以没有或多个后继。

树的性质:

1、根节点:树的起始节点,没有前驱节点。
2、叶节点:没有后继节点,也被称为终端节点。
3、父节点与子节点:节点的直接后继节点称为该节点的子节点,该节点称为子节点的父节点。
4、树的层数:从根节点开始,从1开始依次往下计数
5、树的高度:最后一层的层数为该数的高度
6、树的度数:节点的子节点个数就是该节点的度数,树的度数是树中最大节点度数

二叉树

定义:树中每个节点度数不能大于2

二叉树性质:

1、第i层最多2^(i-1)  个节点
2、高度为n的树,最多(2^n)-1个节点
3、任意二叉树中,树叶的个数比度数为2 的节点多一个。
n0 :表示叶节点个数
n1:表示度数为1的节点个数
n2:表示度数为2的节点数
任意二叉树有:
		n0 = n2 +1

二叉树的存储方式:

顺序存储或链式存储

链式存储:

//利用递归思想创建一个任意形态的二叉树(具体形态取决于输入的情况:输入-1 代表无子节点)

typedef int datatype;
typedef struct node{    
    datatype data;
    struct node* left, *right;
}tree_node;              
            
tree_node* create_tree()
{
    int num = 0;
    tree_node* p = NULL; 
    puts("输入节点数据:");
    scanf("%d",&num);
    if(num == -1) 
    {   
        return NULL;
    }else{
        p = (tree_node*)malloc(sizeof(tree_node));
        if( NULL == p ) 
        return NULL;
        p->data = num;
        p->left = create_tree();
        p->right = create_tree();
    }   
    return p;
}

顺序存储:

非完全二叉树使用顺序存储,可能会浪费空间。

遍历方式:

先序遍历:(递归)

先遍历根节点,再遍历左子树,最后右子树。
int look_node_xianxu(tree_node* tree)
{
    if(NULL == tree)
        return -1; 
    printf("%d\n",tree->data);
    look_node_xianxu(tree->left); 
    look_node_xianxu(tree->right);
 return  0;  
}

中序遍历(递归)

中序遍历:先遍历左子树,再遍历根节点,最后右子树。
int look_node_houxu(tree_node *tree)
{   
    if( NULL == tree)
        return -1; 
    look_node_houxu(tree->left);
     printf("%d\n",tree->data);
    look_node_houxu(tree->right);
    return 0;
}

后序遍历(递归)

后序遍历:先遍历左子树,再遍历右子树,最后根节点。
int look_node_houxu(tree_node *tree)
{   
    if( NULL == tree)
        return -1; 
    look_node_houxu(tree->left);
    look_node_houxu(tree->right);
    printf("%d\n",tree->data);
    return 0;
}

层次遍历

从第一层开始依次往下,从左往右遍历。(借助队列遍历)

int cengci_bianli(tree_node *tree)
{   
    int num = 0;
    tree_node* data[MAX];
 int   front = 0;
   int rear = 0;
    data[rear++] = tree;
    while(rear != front)
    {   
       if(data[front]->left != NULL )
       {
           data[rear++] = data[front]->left;
       }
       if(data[front]->right != NULL)
       {
           data[rear++] = data[front]->right;
       }
        num = data[front++]->data;
        printf("%d ",num);
    }   
}

已知先序 与中序 求后序( 先序第一个为头节点,中序头节点前为树左半边)。

已知后序与 中序 求先序(后序最后一个节点为头节点)。

特殊二叉数列

满二叉树:每一层都是2^(i-1)个节点

完全二叉树:

1、只有最下两层有度数小于2的节点
2、最下面一层叶节点集中于最左侧
3、具有n个节点的完全二叉树的深度:
((向下取整:(log2 N))+1) 或  向上取整(log2 (n+1))

    
    
    
tree_node* create_list(int i, int num)//完全二叉树
{
    tree_node* tree = (tree_node*)malloc(sizeof(tree_node));
    if(NULL == tree)
        return NULL;
    tree->data = i;
    if(2*i < num)
    {   
      tree->left = crete_tree(2*i,num);
    }else{
        tree->left = NULL;
    }   
    
    if(2*i+1 < num)
    {   
       tree->right= crete_tree(2*i+1,num);
    }else{
        tree->right = NULL;
    }
         
    return tree;
}

二叉查找树

又称:二叉排序树
中序遍历,数据为升序排列

每一颗子树左节点数据需要小于根节点,右节点数据大于根节点。

优点:查找效率高
缺点:容易成为链表

平衡二叉树:

1、一颗二叉查找树
2、每个节点的左右子树的高度差不能大于1(从下往上算)。
平衡因子就是每个节点的左右子树的高度差,可以检测某个节点是否平衡。

优点:查找效率快
缺点:插入数据,涉及大量数据移动,效率低
该树要求:“绝对平衡”

红黑树

该树要求:适度平衡(局部平衡)。

1、根节点为黑色
2、个节点不是黑色就是红色
3、每个叶子节点都是黑色
4、一个节点是红色,其子节点必须是黑色
5、从一个节点到该叶子节点的所有路径上包含相同数目的黑点。


插入方式:
	1、染色
	2、旋转

优点:查找效率快
优点:插入数据时,只要求“适度平衡”,因此不会每次去旋转大量节点。

总结

平衡二叉树(AVL树)与红黑树比较:

平衡二叉树要求“绝对平衡”,所以插入时效率慢,但是查找效率快
红黑树只要求适度平衡,所以不需要每次旋转,插入效率快。红黑树最长的路径不能大于最短路径的两倍,所以查找效率较快。

最优二叉树

又称:赫夫曼树

WPL最小的二叉树就是最优二叉树,又称为赫夫曼树。
树的带权路径长度指所有叶子节点的带权路径之和。

构造最优二叉树

按照叶节点的权值构造最优二叉树
1. 先对权值进行排序---->  2, 3, 5, 7, 8

2. 选择权值最小的两个节点,可以规定权值较小的节点作为左节点, 大的作为右节点.

3. 构造出新的权值节点,然后将新的权值重新进行排序(以前使用过的权值不在参与排序).  

   重复1,2,3直到完成树的构造。

逻辑关系:非线性,数据间多对多。

图的性质:
顶点:每一个数据元素被称为顶点
图分为:有向图、无向图。
	有向图:把两个顶点之间的连线称为:弧
	无向图:把两个顶点之间的连线称为:边
顶点的度数:
	无向图:与该节点直接相连的节点数。
	有向图:出度+入度


存储结构:
1、顺序存储
利用数组来存放图的顶点数据,利用邻接矩阵(二维数组)表达顶点之间的关系。

2、链式存储(邻接表)

图的遍历方式

图的存储方式

可以用一个一维数组存储图的节点,再用一个二维数组存储节点之间的关系。

#define SIZE 20
typedef int datatype;
typedef struct ma{
    datatype v[SIZE]; //一维数组用于存储节点数据,(根据节点在一维数组中的下标,标定两个有关系的节点。方便存储和遍历)
    int matrix[SIZE][SIZE];//二维数组存储
}map_t;

    
map_t* create_tu()//根据已知的图的关系输入计算机。让计算机存储和查找
{
    int num,i=0,j;
    map_t* map = (map_t*)malloc(sizeof(map_t));
    if(NULL == map)
        return NULL;
    memset(map,0,sizeof(map));

    printf("输入顶点:(-1 退出)\n");
    while(1)//按照顺序输入节点
    {   
        scanf("%d",&num);
        getchar();
        if(num == -1 || i >= SIZE)
            break;
        map->v[i++] = num;
    }   

    printf("输入两数据间的关系,数据间用逗号隔开:i,j \n");
    while( scanf("%d,%d",&i,&j) == 2)//输入有关系的节点,比如在一维数组中,下标为1和2的节点有关系,就可以让a[1][2]和a[2][1]都赋值为1
    {   
        getchar();
        if(i < 0 || j < 0 || i >= SIZE || j >= SIZE)
            break;
        map->matrix[i][j] =1; 
        map->matrix[j][i] =1; 
    }     
   return map;
}

这里写图片描述

深度优先 DFS

类似树的先序遍历(递归)
    如上图如果从v1开始遍历,深度优先顺序如下
    v1->v2->v3->v4->v3->v5
    从v1开始,与他相连的节点有两个v2 v4,深度优先的原则是先遍历下标小的节点v2(下标的大小是由输入一维数组顺序决定,也就是由程序源决定)
    接着与v2相连的节点有:1,3,5;其中1已经遍历,所以此次遍历3
    与3相连的有 4 ,5;此次遍历4
    与4相连的有1,3,两个都遍历过了,所以应该回到节点3(已经遍历过了)
    与3相连的有4,5;4遍历了,所以继续遍历5.
    最终遍历顺序为: v1->v2->v3->v4->v5
    

int fistadj(map_t* map, int pos)
{
    int i = 0;
    for(i =0 ; i <SIZE ;i++)
    {
      if(1 == map->matrix[pos][i])
          return i;
    }
    return -1;
}

int nextAdj(map_t* map,int pos, int u)
{
    int i = 0;
    for(i = u+1 ;i < SIZE; i++)
    {
        if(1 ==  map->matrix[pos][i])
            return i;
    }
    return -1;
}

void DFS(map_t* map, int pos, int visited[])//遍历函数,调用时可以输入pos指定节点开始。
{
    int u;
    printf("%-4d",map->v[pos]);//打印当前节点数据
    visited[pos] =1;//另外定义并初始化为零的数组,大小与存储节点的数组一样大,每个节点被遍历,该数组对应下标元素赋值为 1
    u = fistadj(map,pos);//调用函数找到与当前节点相连节点中,下标最小的节点。
    while( u  != -1)
    {
        if(visited[u]  == 0)//节点没有被遍历,调用函数继续遍历
            DFS(map,u,visited);
        u = nextAdj(map,pos,u+1);//当前节点已经遍历,找其他节点
    }
    return ;
}
      

广度优先

类似树的层次遍历(队列)



排序

快速排序

int quick_sort(int a[], int low, int high)
{
	int i = low;
	int j = high;
	int temp = a[low];
	if(i < j)
	{
		while(i < j)
		{
			while(i < j && temp <= a[j]) j--;
			if(i < j) a[i] = a[j];
			while(i < j && temp >= a[i]) i++;
			if(i < j) a[j] = a[i];
		}
		a[i] = temp;
		quick_sort(a, low, i-1);
		quick_sort(a, i+1, high);
	}


非递归方式遍历二叉树:

先序:

typedef int data_t;
typedef struct node{
    data_t data;
    struct node* left;
    struct node* right;
}tree_node;


int traverse_pre_tree(tree_node*tree)//先序
{
    if(NULL == tree)//根节点为空函数退出
        return -1; 
    tree_node* data[50];//创建一个栈(指针数组),储存节点地址.
    int last = -1; 
    tree_node* p = tree;
    data[++last] = tree;//根节点入栈

    while(last >-1)//栈空,循环结束
    {   
        p = data[last];//p指向栈顶元素
        printf("%2d ",data[last--]->data);//栈顶元素出栈
        if(p->right != NULL)
        {
            data[++last] = p->right;//右节点入栈.
        }

        if(p->left != NULL)
        {
            data[++last] = p->left;//左节点入栈
        }
    }   
}



中序

int traverse_post_tree(tree_node*tree)//中序
{
    if(NULL == tree)//根节点为空函数退出
        return -1; 
    tree_node* data[50];//创建一个栈(指针数组),储存节点地址.
    tree_node* p =tree;
    
    int last = -1; 
    do{ 
        while(p != NULL)
        {
            data[++last] =p;//根节点入栈
            p = p->left;//所有左节点入栈
        }

        if(last != -1) 
        {
            p = data[last];//指针指向栈顶元素
            printf("%2d ",data[last--]->data);//栈顶元素出栈
            p = p->right;//指针指向栈顶元素右节点
        }
    }while(p != NULL || last != -1);
    
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值