郝斌 数据结构 笔记

合集下载

“数据结构”读书笔记

“数据结构”读书笔记

“数据结构”读书笔记示例:第2章线性表学习线索:逻辑结构→基本运算定义→存储结构→基本运算实现(复杂度分析→应用实例)1. 逻辑结构:是由n(n≥0)个数据元素组成的有限序列。

2. 基本运算定义:(P.16)(1)Init_List(L),线性表初始化;(2)Length _ List (L),求线性表的长度;(3)Get_ List (L,i),取表元;(4)Locate_ List (L,x),按值查找;(5)Insert_ List (L,x,i);插入操作;(6)Delete_ List (L,i),删除操作。

3. 存储结构:(1)顺序表:把线性表的结点按逻辑次序存放在一组地址连续的存储单元里。

顺序存储的结构体定义:typedef struct{ datatype data[MAXSIZE]; /* 一维数组子域*/int last; /* 表长度子域*/} SeqList; /* 顺序存储的结构体类型*/4-1. 顺序表的基本运算的实现(算法及其复杂度分析、应用实例:顺序表的划分、合并、比较大小)(2)单链表:只有一个链域的链表称单链表。

结点结构:Data(节点值)Next(后继结点地址)其中data是数据域,next是指针域链式存储的结构体定义:typedef struct lnode{ datatype data; /* 数据子域*/struct lnode *next; /* 指针子域*/} LNode,*LinkList; /* 链式存储的结点结构类型*/4-2. 单链表的基本运算的实现(算法及其复杂度分析、应用实例:链表逆置、归并)单链表的发展:循环链表、双向链表顺序表和链表的比较1)基于空间:2)基于时间:“数据结构”读书笔记(线性结构部分)第1章绪论1. 数据:信息的载体,能被计算机识别、存储和加工处理。

2. 数据元素:数据的基本单位,可由若干个数据项组成,数据项是具有独立含义的最小标识单位。

郝斌java视频笔记

郝斌java视频笔记

访问控制符:包括public private protected和默认,在一个类的内部所有成员可以相互访问,访问控制符是透明的;在一个类的外部通过类对象名.私有成员名的方式无法访问该对象中的私有成员。

类的构造函数:构造函数一必须要与类名相同二构造函数不能有返回值(连void都不能有)。

构造函数会被类自动调用。

可以有多个构造函数但是在生成一个类的对象时只能调用一个构造函数函数重载:几个功能类似的函数(a+b,a+b+c)可以函数名相同,这就是函数的重载,调用函数时通过区分函数形参的个数、形参的顺序和形参的数据类型来判断具体调用哪个函数。

启动类前加publicThis:就是一个指针。

This出现在构造函数里,代表当前时刻正在创建的对象;this出现在普通函数里,代表当前时刻正在调用该函数的对象,此时this可以省略。

Static:static修饰的类的变量属性和函数方法都属于类本身,可以直接通过类名访问static 属性和方法,而不用去创建对象才能访问。

一个类的不同对象的变量属性是不同的,但是一个类的不同对象的static变量属性是通用唯一的。

只有非private的static成员才可以通过类名的方式访问。

Static的函数不能调用非static的函数和属性变量。

非static的函数可以访问static的函数和属性变量。

继承:extends子类内部只能访问父类的非private的成员父类私有成员不能被子类继承。

(成员包括属性和方法)Java只支持单继承,即一个子类有且只能有一个父类,但是可以多层继承子类不能继承父类的构造函数,调用父类的构造函数必须借助super;对super的调用必须是构造函数中的第一条语句;每个子类构造函数里的第一条语句,都是隐含的调用super ();即可以显示的写super(),前提是父类必须有无参的构造函数;也可以显示的写super (实参),前提是父类必须有带参的构造函数;一个子类的构造函数中只能有一个super语句函数重写:指在子类中重新定义父类中已有的方法;重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型多态:一个父类的引用变量即可以指向父类对象也可以指向子类对象,它可以根据指向的不同,自动调用不同的对象方法,这就是多态。

郝斌老师__数据结构

郝斌老师__数据结构
append_arr(&arr, 10);
append_arr(&arr, -3);
append_arr(&arr, 6);
append_arr(&arr, 88);
append_arr(&arr, 11);
if ( delete_arr(&arr, 4, &val) )
{
printf("删除成功!\n");
bool delete_arr(struct Arr * pArr, int pos, int * pVal);
int get();
bool is_empty(struct Arr * pArr);
bool is_full(struct Arr * pArr);
void sort_arr(struct Arr * pArr);
void g(struct Student st)
{
printf("%d %s %d\n", st.sid, , st.age);
}
void g2(struct Student *pst)
{
printf("%d %s %d\n", pst->sid, pst->name, pst->age);
//p[i]就是主函数的a[i]
}
int main(void)
{
int a[5] = {1,2,3,4,5};
Show_Array(a, 5); //a等价于&a[0], &a[0]本身就是int *类型
//printf("%d\n", a[2]);
return 0;

郝斌C语言详细笔记(附源码)

郝斌C语言详细笔记(附源码)

郝斌老师的C语言:课堂讲解全程动手敲代码,讲解细致,对于重要知识点的讲解不厌其烦,是一个难得的C语言入门教程。

在这里对老师的辛勤付出表示感谢。

郝斌c语言视频教程·概述:课程计划为什么学习c语言:Fortran语言主要用于科学计算,在第三代语言中,以1980年为分水岭,分为结构化和面向对象语言。

Basic语言是vb的前生,pascal语言一般是用于教学。

C语言是最重要的,其他的语言一般很少用了。

结构化的代表语言是c语言。

结构化语言的数据和操作是分离的,导致在写大项目的时候,会出现各种各样莫名其妙的问题。

在面向对象的语言中c++是最复杂的语言。

由于c++语言太复杂,sun公司对c++进行了改装,产生了java语言。

而c#是由微软开发的,和java相似,几乎一模一样。

在高级语言的执行速度上,c是最快的,c++其次,而java 和c#是最后的。

Java和c#流行,主要的一个原因是可以跨平台。

C语言的发展和过程:C语言的特点:·优点:代码量小,速度快,功能强大。

·缺点:危险性高,开发周期长,可移植性弱。

危险性高:写同一个程序,在java中会报错,而在c中不会报错,为什么呢,因为c认为程序你想怎么写就怎么写,c语言认为你写的程序不是很离谱,他都认为你写的这个程序有特殊的含义。

可以直接通过,而java 则不可以。

开发周期长:c语言是面向过程的语言,面向过程的语言的特点就是在开发大项目的时候,很容易崩溃,好比盖大楼,C语言还要造大量的砖块、钢筋等结构原材料,而C++ C# JAVA则进行了一定的继承封装等操作,相当于原材料直接给你,你只需要用它盖楼即可。

现在市场上的语言分三块C/c++:单纯的学习c是什么都做不了的。

JavaC#可移植性不强:这是针对java来说的,因为java的可移植性太强了,所以就感觉说c的可移植性不强。

金山公司最主要是靠wps办公软件来发展的。

Wps是c 语言开发的,其安装包比Office少了10多倍。

郝斌c语言详细笔记

郝斌c语言详细笔记

郝斌c语言详细笔记郝斌C语言详细笔记C语言是一门广泛应用于系统编程、嵌入式系统和游戏开发等领域的高级编程语言。

郝斌老师的C语言详细笔记是一份非常优秀的学习资料,它详细介绍了C语言的基础知识和高级应用,对于初学者和进阶者都非常有帮助。

一、基础知识1. 数据类型C语言中的数据类型包括基本数据类型和派生数据类型。

基本数据类型包括整型、浮点型、字符型和布尔型,而派生数据类型包括数组、结构体、共用体和指针等。

在使用数据类型时,需要注意它们的取值范围、精度和存储空间等方面的问题。

2. 运算符C语言中的运算符包括算术运算符、关系运算符、逻辑运算符、位运算符和赋值运算符等。

在使用运算符时,需要注意它们的优先级和结合性等方面的问题。

3. 控制语句C语言中的控制语句包括条件语句、循环语句和跳转语句等。

在使用控制语句时,需要注意它们的语法和逻辑结构等方面的问题。

二、高级应用1. 函数函数是C语言中的重要概念,它可以将程序分解为多个模块,提高程序的可读性和可维护性。

在使用函数时,需要注意它们的参数传递、返回值和作用域等方面的问题。

2. 数组和指针数组和指针是C语言中的重要数据结构,它们可以用于处理复杂的数据类型和数据结构。

在使用数组和指针时,需要注意它们的声明、初始化和访问等方面的问题。

3. 文件操作文件操作是C语言中的重要应用之一,它可以用于读写文件、处理文本和二进制数据等。

在使用文件操作时,需要注意文件的打开、关闭和读写等方面的问题。

总之,郝斌老师的C语言详细笔记是一份非常优秀的学习资料,它涵盖了C语言的基础知识和高级应用,对于初学者和进阶者都非常有帮助。

在学习C语言时,我们需要认真阅读笔记中的内容,理解其原理和应用,同时还需要进行实践和练习,以提高自己的编程能力。

1.郝斌数据库学习笔记之查询笔记

1.郝斌数据库学习笔记之查询笔记

1.字符要用双引号引起,实际上2000与2005,2008都允许单引号引起,但是oracle不允许。

为了将来可以方便的移植代码,就定为字符统一由双引号引起。

2.Select salary*12 as“年薪”from emp;As是指定列名,因为salary*12 是计算出来的结果,所以这个结果没有列名,as可以省略。

3.distinct 不允许重复的例如:select distinct deptno from emp;空值(null)被当做一个对象处理,对于两个输出项,则将两个合并为一个整体来判断是否相同4.SQL中用双横杠表示注释5.讲课时要引导学生得出结论,由你来决定结果是否正确6.做生意和谈业务就是要让客户跟着你走,理直气壮7.谈生意的时候,不要听推销员则么说,最好是你问他答,这样他就不敢唬你了,或者你不说话,一直让他说。

8.SQL中最重要的是执行顺序(这个地方在编程,在数据库,在shell处处都会存在,在编程中尤为重要,注意归类和总结)9.Select * from empWhere sal=5000--顺序:1.where sal=50002.selcet * from emp10.between 的用法select * from empwhere sal between 1500 and 300011.in 的用法select * from empwhere sal in (1500,3000) -- 仅输出sal为1500和3000的行,in相当于一个数组select * from empwhere sal not in(1500,3000)-- not in的用法13.数据库中不等于有两种表示:!= <> 推荐使用第二种,或取反为并,并取反为或14.top 用法Select top 2 *from empSelect top 5 percent * from empPercent 是百分比SQL server是用top来作分页的Oracle是用rownum分页什么时候用到分页?当你的结果有很多(例如一万行),你就需要分页,来规定每页仅显示10个结果,比如百度和谷歌都是规定了每页可以显示多少个结果虽然数据库都大同小异,但是由于各自使用的语言的不同,用一种语言无法完全实现代码的全移植。

数据结构与算法入门C语言(一)概述

数据结构与算法⼊门C语⾔(⼀)概述数据结构与算法⼊门C语⾔笔记来源于郝斌⽼师数据结构与算法视频,博主学习后纯⼿打,侵删。

数据结构概述⼀、数据结构定义如何把现实中⼤量⽽复杂的问题以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(⽐如查找、删除某个元素,对所有元素排序)⽽执⾏的相应操作,这个操作也叫算法。

特定的数据类型: 个体元素特定的存储结构:个体和个体之间的关系数据结构=个体+个体的关系算法=对存储数据的操作⼆、算法定义算法:解题的⽅法和步骤三、衡量算法的标准1.时间复杂度⼤概程序执⾏的次数,⽽⾮执⾏时间。

2.空间复杂度算法执⾏过程中⼤概所占⽤的最⼤内存。

3.难易程度4.健壮性四、数据结构的地位数据结构是软件⼼中最核⼼的课程程序=数据结构+数据的操作+可以被计算机执⾏的语⾔1.什么是堆?什么是栈?很多⼈以为是内存⾥的2块⼉空间,⼀块⼉叫堆,⼀块叫栈,其实不对。

实际上是指内存分配的⽅法不同的2种⽅式。

如果是压栈出栈的⽅式分配和释放的内存就叫栈内存。

如果是以堆排序分配的内存就叫堆内存。

**注意:数据结构⾥是没有堆这个概念的,堆是什么?是分配内存的⼀种⽅式,⽽不是存储数据的⼀种结构。

2.函数调⽤,如何调⽤呢?压栈和出栈。

按时间存储的东西得有个顺序吧,按顺序存储的结构就是队列。

编译原理得学树。

数据库就是数据结构得简化版,讨论得问题差不多,解决得问题更狭窄了程序=数据的存储+数据的操作+可被计算机执⾏的语⾔。

数据结构很重要,难度⼤,学完很难做出东西来,学它是练内功。

五、预备知识1.指针指针的重要性指针是C语⾔的灵魂定义地址内存单元的编号从0开始的⾮负整数范围:0-FFFFFFFF【0~4G-1】指针指针就是地址,地址就是指针。

指针的本质是⼀个操作受限的⾮负整数指针变量指针变量是存放内存单元地址(编号)的变量指针的分类1.基本类型的指针#include <stdio.h>int main(void){int *p; //p是个变量名字,int * 表⽰该P变量只能存储int类型变量的地址int i = 10;int j;//(1) 此时p还没有被赋值,⾥⾯是个垃圾值,这个垃圾值很可能正好是某个变量的地址//所以应该在使⽤ *p 之前给p赋值地址:p = &i;j = *p;//(2) 给垃圾值地址的变量赋值⼀个新值,垃圾值应不受你控制的,随意改内存很危险。

郝斌老师c语言笔记

经典指针程序:
互换两个数子:
#include <stdio.h>
#include <stdlib.h>
void huhuan(int a,int b)
{
int t;
t = a;
b = t;
return ;
}
int main()
{
int a = 3;
int b = 5;
huhuan (a,b);
printf ("a = %d,b = %d\n",a,b);
Register寄存器return返回short短的signed有符号的sizeof运算符static静止的struct结构体switch开关typedef定义类型
Unsigned无符号整数union联合void空的;无效的volatile不稳定的易失的易变的while当directive指示符fatal致命的precompiled预编译;先行编译
huhuan (&a,&b);
printf ("a = %d,b = %d\n",a,b);
return 0;
}
void huhuan(int * a,int * b)
{
int * t;//如果要互换,t必须定义成int*类型。
t = p;
p = q;
q = t;
}//这个程序依然不是正确的,因为只是改变了p和q的内容对实参依然没有实际的作用效果。
int main(void)
{
int a[2][3] = {{12,34,45},{423,2342,24}};
int i,j;
for (i = 0;i<2;++i)

郝斌 数据结构

链表new1# include <stdio.h># include <malloc.h># include <stdlib.h>struct node{int data; //存放数据本身struct node *next;};struct node *CreateList( void ){struct node *pH = NULL;int len; //存放节点的个数int i;int temp; //存放用户暂时存入的节点的值域的值struct node *pNew = NULL;//存放临时分配好的节点本身的内容struct node *pTail = NULL;//pTail永远指向链表的尾节点//创建一个头节点pH = ( struct node * )malloc( sizeof( struct node ) );if( NULL == pH ){puts( "动态内存分配失败" );exit( -1 );}pH ->next = NULL;pTail = pH;printf( " 请输入节点的个数:len = " );scanf( " %d ", &len );for( i = 0; i < len; ++ i ){printf( " 请输入第%d 节点的值: ", i + 1 );scanf( " %d ", &temp );//临时构造一个节点pNew = ( struct node * )malloc( sizeof( struct node ) );if( NULL == pNew )//如果p所指向的节点存在{}}}int main ( void ){struct node *pH = NULL;pH = CreateList();//通过CreateList()函数创建一个链表,j将该链表的首地址发松给pH TraverseList( ph );//遍历整个单链表return 0;}跨函数使用内存malloc//2012年9月9日晚上# include <stdio.h># include <malloc.h>struct Student{int sid;int age;};struct Student *CreateStudent( void );void ShowStudent( struct Student * );int main( void ){struct Student *ps;ps = CreateStudent();ShowStudent( ps );return 0;}struct Student *CreateStudent( void ){struct Student *p = ( struct Student * )malloc( sizeof( struct Student ) );p->sid = 99;p->age = 88;return p;void ShowStudent( struct Student *pst ){printf( " %d %d\n ", pst->sid, pst->age );}快速排序# include <stdio.h>void QuickSort( int *a, int low, int high );int FindPos( int *a, int low, int high );int main( void ){int a[6] = { 2, 1, 0, 5, 4, 3 };int i;QuickSort( a, 0, 5 );//第二个参数表示第一个元素的下标,第三个参数表示最后一个元素的下标for( i = 0; i < 6; ++ i )printf( "%d ", a[i] );printf( "\n" );return 0;}void QuickSort( int *a, int low, int high ){int pos;if( low < high ){pos = FindPos( a, low, high );QuickSort( a, low, pos - 1 );QuickSort( a, pos + 1, high );}}int FindPos( int *a, int low, int high ){int val = a[low];while( low < high ){while( low < high && a[high] > val )-- high;a[low] = a[high];while( low < high && a[low] <= val )++ low;a[high] = a[low];}//终止while循环之后low和high一定相等的a[low] = val;return low;//或者return high;}连续存储数组的算法1//2012年9月10日晚上# include <stdio.h># include <malloc.h># include <stdlib.h>//使用exit( -1 );需要定义的头文件//定义了一个数据类型,没有定义变量struct Arr{int *pBase;//存储的是数组第一个元素的地址int len;//数组所能容纳的最大元素的个数int cnt;//当前所在有效的个数};void init_arr( struct Arr *pArr, int length );//分号不能省bool append_arr();//追加bool insert_arr();bool delete_arr();int get();bool is_empty( struct Arr *pArr );bool is_full();bool sort_arr();void sort_arr();void show_arr( struct Arr *pArr );void inversion_arr();int main( void ){struct Arr arr;init_arr( &arr, 6 );//地址只占四个字节show_arr( &arr );//printf( " %d\n ", arr.len );return 0;}void init_arr( struct Arr *pArr, int length ){pArr->pBase = ( int * )malloc( sizeof( int )*length );//pArr->len = 99;if( NULL == pArr->pBase ){printf( "动态内存分配失败!\n" );exit( -1 );//终止整个程序}else{pArr->len = length;pArr->cnt = 0;}return;}bool is_empty( struct Arr *pArr ){if( 0 == pArr->cnt ){return true;}elsereturn false;}void show_arr( struct Arr *pArr ){/*if( 数组为空)提示用户数组为空else输出数组有效内容*/if( is_empty( pArr ) )printf( "数组为空!\n" );}else{for( int i = 0; i < pArr->cnt; ++i )printf( " %d ", pArr->pBase[i] );printf( "\n" );}}连续存储数组的算法2//2012年9月11日早上# include <stdio.h># include <malloc.h># include <stdlib.h>//使用exit( -1 );需要定义的头文件//定义了一个数据类型,没有定义变量struct Arr{int *pBase;//存储的是数组第一个元素的地址int len;//数组所能容纳的最大元素的个数int cnt;//当前所在有效的个数};void init_arr( struct Arr *pArr, int length );//分号不能省bool append_arr( struct Arr *pArr, int val );//追加bool insert_arr( struct Arr *pArr, int pos, int val );//pos的值从1开始bool delete_arr( struct Arr *pArr, int pos, int *pVal );int get();bool is_empty( struct Arr *pArr );bool is_full( struct Arr *pArr );void sort_arr( struct Arr *pArr );void show_arr( struct Arr *pArr );void inversion_arr( struct Arr *pArr );//倒置int main( void ){struct Arr arr;int val;init_arr( &arr, 6 );//地址只占四个字节show_arr( &arr );append_arr( &arr, 1 );append_arr( &arr, 2 );append_arr( &arr, 3 );append_arr( &arr, 4 );if ( delete_arr( &arr, 1, &val ) ){printf("删除成功\n");printf("你删除的元素是:%d\n", val);}elseprintf("删除失败\n");/*append_arr( &arr, 2 );append_arr( &arr, 3 );append_arr( &arr, 4 );append_arr( &arr, 5 );insert_arr( &arr, 6, 99 );append_arr( &arr, 6 );append_arr( &arr, 7 );//这个也是追加不成功的,因为是只是分配了6个数if( append_arr( &arr, 8 ) ){printf( "追加成功\n" );}else{printf( "追加失败\n" );}*/show_arr( &arr );inversion_arr( &arr );printf("倒置之后的内容是:\n");show_arr( &arr );sort_arr( &arr ); //呜呜,这里哪里是出错了呢??printf("排列\n");show_arr( &arr );//printf( " %d\n ", arr.len );return 0;}void init_arr( struct Arr *pArr, int length ){pArr->pBase = ( int * )malloc( sizeof( int )*length );//pArr->len = 99;if( NULL == pArr->pBase ){printf( "动态内存分配失败!\n" );exit( -1 );//终止整个程序}else{pArr->len = length;pArr->cnt = 0;}return;}bool is_empty( struct Arr *pArr ){if( 0 == pArr->cnt ){return true;}elsereturn false;}bool is_full( struct Arr *pArr ){if( pArr->cnt == pArr->len )return true;elsereturn false;}void show_arr( struct Arr *pArr ){/*if( 数组为空)提示用户数组为空else输出数组有效内容*/if( is_empty( pArr ) ){printf( "数组为空!\n" );}else{for( int i = 0; i < pArr->cnt; ++i )printf( " %d ", pArr->pBase[i] );printf( "\n" );}}bool append_arr( struct Arr *pArr, int val ){//满时返回falseif( is_full( pArr ) )return false;//不满时追加elsepArr->pBase[pArr->cnt] = val;( pArr->cnt ) ++;return true;}bool insert_arr( struct Arr *pArr, int pos, int val ){int i;//第一中情况,数组里面全满时if( is_full( pArr ) )return false;//第二种情况,数组里面不为满时if( pos < 1 || pos > pArr->cnt + 1 )return false;//把原来的第pos的位置和之后的数都向前移动for( i = pArr->cnt - 1; i >= pos - 1; --i ){pArr->pBase[i + 1] = pArr->pBase[i];}//把第pos位置插入新的值pArr->pBase[pos - 1] = val;( pArr->cnt ) ++;//个数加一return true;}bool delete_arr( struct Arr *pArr, int pos, int *pVal ){int i;if( is_empty( pArr ) )return false;if( pos < 1 || pos > pArr->cnt )return false;*pVal = pArr->pBase[pos - 1];for( i = pos; i < pArr->cnt; ++i ) //cnt表示数组有效的个数{pArr->pBase[i - 1] = pArr->pBase[i]; //这里要前移一个数,所以上面的可以i <= pArr->cnt - 1}pArr->cnt --; //删除了一个数组个数,所以有效个数要相应的减一return true;}void inversion_arr( struct Arr *pArr ){int i = 0;int j = pArr->cnt - 1;int t;while( i < j ){t = pArr->pBase[i];pArr->pBase[i] = pArr->pBase[j];pArr->pBase[j] = t;++ i;-- j;}return;}void sort_arr( struct Arr *pArr ){int i, j, t;for( i = 0; i < pArr->cnt; ++i ){for( j = j + 1; j < pArr->cnt; ++ j ){if( pArr->pBase[i] > pArr->pBase[j] ){t = pArr->pBase[i];pArr->pBase[i] = pArr->pBase[j];pArr->pBase[j] = t;}}}}链表//2012年9月12日早上离散存储[链表]定义:n个节点离散分配彼此通过指针相连每个节点只有一个前驱节点,每个节点只有后续节点首节点没有前驱节点,尾节点没有后续节点术语:首节点:第一个有效的节点尾节点:最后一个有效的节点头节点:头节点额数据类型和首节点类型一样首节点前一个没有存放有效数据加头节点的目的主要是为了方便链表的操作头指针:指向头节点的指针变量尾指针:指向尾节点的指针如果希望通过一个函数来对链表进行处理,我们至少需要接受链表的哪些参数因为我们通过头指针可以推算出链表的其他信息分类:单链表双链表:每一个节点有两个指针域循环链表:能通过任何一个节点找到所有的节点非循环链表算法:遍历查找清空销毁求长度排序删除节点插入节点typedef struct node{int data;struct node *pNext;}NODE, *PNODE;PNODE p = ( PNODE )malloc( sizeof( NODE ) );free( p );//删除p指向节点所占的内存,不是删除p本身所占的内存p->pNext;//p所指向结构体变量中的pNext成员本身删除p所节点的后面节点先临时定义一个指向p后面节点的指针rr = p->pNext;//r所指向后面的那个节点p->pNext = r->pNext;free(r);链表创建和链表遍历算法的演示//2012年9月12日早上# include <stdio.h># include <malloc.h># include <stdlib.h>typedef struct Node{int data;struct Node *pNext;}NODE, *PNODE;//函数的声明PNODE create_list(void);void traverse_list( PNODE pHead );int main( void ){PNODE pHead = NULL;//等价于struct Node *pHead = NULL;pHead = create_list();//创建一个非循环单链表,并将该链表的头节点的头结点的地址赋给pHeadtraverse_list( pHead );return 0;}PNODE create_list(void){int len;//用来存放节点有效节点的个数int i;int val;//用来临时存放用户输入的节点的值//分配了一个不存放有效数据的头节点PNODE pHead = ( PNODE )malloc( sizeof( NODE ) );if( NULL == pHead ){printf( " 分配失败,程序终止" );exit( -1 );}PNODE pTail = pHead;//pTail指向链表的尾指针,刚开始时尾指针后头指针指向的相同pTail->pNext = NULL;printf( " 请输入你需要生成的链表节点的个数:len = " );//scanf( " %d ", &len ); //注意了,这里要先打一个空格,在输入一个数字,因为%d前面有个空格,所以......scanf( "%d", &len );for( i = 0; i < len; ++i ){printf(" 请输入第%d个节点的值: ", i + 1);scanf( "%d", &val );PNODE pNew = ( PNODE )malloc( sizeof( NODE ) );if( NULL == pNew ){printf( " 分配失败,程序终止" );exit( -1 );}//把新生成的节点挂在尾节点的后面pNew->data = val;pTail->pNext = pNew;pNew->pNext = NULL;pTail = pNew;//}return pHead;}void traverse_list( PNODE pHead ){PNODE p = pHead->pNext;while( NULL != p ){printf( " %d ", p->data );p = p->pNext;}printf( " \n " );return;//意思是告诉别人程序已经结束}每一个链表节点的数据类型该如何处理的问题//2012年9月11日晚上# include <stdio.h>typedef struct Node{int data;//数据域struct Node *pNext;//指针域}NODE, *PNODE;int main( void ){return 0;}排序:冒泡出入选择快速排序归并排序排序和查找的关系排序是查找的前提排序重点Typedef的用法1# include <stdio.h>//typedef int lisi; //为int再重新多取一个名字,lisi等价于inttypedef struct Student{int sid;char name[100];char sex;}ST;int main( void ){struct Student st; //等价于ST st;struct Student *ps = &st; //等价于ST *PS;ST st2;st2.sid = 200;printf("%d\n", st2.sid);return 0;}Typedef的用法2# include <stdio.h>typedef struct Student{int sid;char name[100];char sex;}*PST; //PST等价于struct Student *int main( void ){struct Student st;PST ps = &st;ps->sid = 99;printf( "%d\n", ps->sid );return 0;}Typedef的用法3# include <stdio.h>typedef struct Student{int sid;char name[100];char sex;}*PSTU, STU;//等价于STU代表struct Student, PSTU代表了struct Student *int main( void ){STU st;//struct Studtn st;PSTU ps = &st;//struct Student *ps = &st;ps->sid = 99;printf( "%d\n", ps->sid );return 0;}1到100相加# include <stdio.h>long sum( int n ){//用递归实现if( 1 == n )return 1;elsereturn sum( n - 1 ) + n;/*//用循环实现long s = 0;int i;for( i = 1; i <= n; ++i )s += i;return s;*/}int main( void ){printf( "%d\n", sum(100) );return 0;}//2012年9月17日早上到2012年9月18日早上递归定义:一个函数自己直接或间接调用自己举例:1)1 + 2 + 3 + ...100的和2)求阶乘3)汉诺塔4)走迷宫递归满足三个条件1)递归必须得有一个明确的中止条件2)该函数所处理的数据规模必须在递减3)这个转化必须是可解的递归和循环递归:1)易于理解2)速度慢3)存储空间大循环:1)不易理解2)速度快3)存储空间小递归的应用数和森林就是以递归的方式定义的数和图很多算法都是以递归来实现的很多数学公式就是以递归的方式定义的菲波拉契//2012年9月18日早上# include <stdio.h>void hannuota( int n, char A, char B, char C ){/*如果是1个盘子直接将A柱子上的盘子从A移动到C否则先将A柱子上的n-1个盘子借助于C移动到B直接将A柱子上的盘子从A移到C最后将B柱子上的n-1借助A移动到C*/if( 1 == n ){printf( "将编号为%d的盘子直接从%c柱子%c柱子\n", n, A, C );}else{hannuota( n-1, A, C, B );printf( "将编号为%d的盘子直接从%c柱子%c柱子\n", n, A, C );hannuota( n-1, B, A, C );}}int main( void ){char ch1 = 'A';char ch2 = 'B';char ch3 = 'C';int n;printf( "请输入要移动的盘子个数:" );scanf( "%d", &n );hannuota( n, 'A', 'B', 'C' );}阶乘的递归实现# include <stdio.h>//假定是1或大于1的值long f( long n ){if( 1 == n )return 1;elsereturn f( n - 1 ) * n;}int main( void ){printf( "%d\n", f(3) );return 0;} 阶乘的循环使用//程序实现不了功能噢# include <stdio.h>int main( void ){int val;int i, mult;printf( "请输入一个数字:" );printf( "val = " );scanf( "%d", &val );for( i = 1; i <= val; ++i )mult = mult * i;printf( "%d的阶乘是:%d\n", val, mult );return 0;}队和列//2012年9月14日早上到2012年9月17日早上队列定义:一种可以实现"先进先出"的存储结构分类链式队列用链表实现静态队列用数组实现静态队列通常都必须是循环队列循环队列1.静态队列为什么必须是循环队列2.循环队列需要几个参数确定及其含义两个参数来确定(front和rear)2个参数不同场合有不同的含义建议初学者先记住,然后慢慢体会1)队列初始化front和rear的值都是零2)队列非空front代表的是队列的第一个因素rear代表的是队列的最后一个有效元素的下一个元素3)队列空front和reard的值相等,单不是零3.循环队列各个参数含义建议初学者先记住,然后慢慢体会1)队列初始化front和rear的值都是零2)队列非空front代表的是队列的第一个因素rear代表的是队列的最后一个有效元素的下一个元素3)队列空front和reard的值相等,单不是零4.循环队列入队伪算法讲解两部完成:1)将值存入r所代表的位置2)rear = ( rear+1 ) % 数组的长度5.循环队列出队伪算法讲解front = ( front+1 ) % 数组的长度6.如何判断循环队列是否为空如果front与rear的值相等则该队列就一定为空7.如何判断循环队列是否已满预备知识:( front和rear没有任何关系)front的值可能比rear大也完全有可能比rear小当然也可能相等两种方式:1)多增加一个标志参数2)少用一个元素[通常使用第二种方式]用c伪算法表示就是:如果r和f的值紧挨着,则队列已满if( (r + 1)%数组长度== f )已满else不满队列算法入队出队队列的具体应用所有和时间有关的操作都与队列有关循环队列程序的演示/2012年9月17日早上# include <stdio.h># include <malloc.h>typedef struct Queue{int *pBase;int front;int rear;}QUEUE;void init( QUEUE * );bool en_queue( QUEUE *, int val );//入队void traverse_queue( QUEUE * );bool full_queue( QUEUE * );bool out_queue( QUEUE *, int * );//出队bool empty_queue( QUEUE * );int main( void ){QUEUE Q;int val;init( &Q );en_queue( &Q, 1 );en_queue( &Q, 2 );en_queue( &Q, 3 );en_queue( &Q, 4 );en_queue( &Q, 5 );en_queue( &Q, 6 );en_queue( &Q, 7 );en_queue( &Q, 8 );en_queue( &Q, 9 );traverse_queue( &Q );if ( out_queue( &Q, &val ) ){printf( "出队成功,队列出队的元素是%d\n", val );}else{printf( "出队失败!\n" );}traverse_queue( &Q );return 0;}void init( QUEUE *pQ ){pQ->pBase = ( int * )malloc( sizeof( int )*6 );pQ->front = 0;pQ->rear = 0;}bool full_queue( QUEUE *pQ ){if( ( pQ->rear + 1 ) % 6 == pQ->front ){return true;}elsereturn false;}bool en_queue( QUEUE *pQ, int val ){if( full_queue( pQ ) ){return false;}else{pQ->pBase[pQ->rear] = val;pQ->rear = ( pQ->rear + 1 ) % 6;return true;}}void traverse_queue( QUEUE *pQ ){int i = pQ->front;while( i != pQ->rear ){printf( "%d ", pQ->pBase[i] );i = ( i + 1 ) % 6;}printf("\n");return;}bool empty_queue( QUEUE *pQ ){if( pQ->front == pQ->rear )return true;elsereturn false;}bool out_queue( QUEUE *pQ, int *pVal ) {if( empty_queue( pQ ) ){return false;}else{*pVal = pQ->pBase[pQ->front];pQ->front = (pQ->front + 1) % 6;return true;}树测试# include <stdio.h># include <stdlib.h>int main ( void ){int i;charchar *ptr1[4]={"china","chengdu","sichuang","chongqin"};for( i = 0; i < 4; i ++ ){printf( "%s\n", ptr1[i] );}}树非线性结构数树定义专业定义:1)有且只有一个称为根的节点2)有若干个互不相交的子树,这些子树本身也是一课树通俗的定义:1)树是由节点和边组成2)每个节点只有一个父节点但可以有多个子节点3)但有一个节点例外,该节点没有放节点,此节点称为根节点专业术语节点父节点子节点子孙堂兄弟深度:从根节点到底层节点的层数称之为深度根节点是第一层叶子节点:没有子节点的节点非终端节点:实际就是非叶子节点(有子节点的节点)度:子节点的个数称为度树分类一般树任意一个子节点的个数都不受限制二叉树任意一个节点的子节点的个数最多两个,且子节点的个数不可以更改分类:一般二叉树满二叉树在不增加树的层数的前提下,无法再添加一个节点的二叉树就是满二叉树完全二叉树如果只是删除满二叉树最底层最右边的连续若干个节点,这样形成的二叉树就是完全二叉树森林n个互不相交的树的集合树的存储森林的存储二叉树的存储连续存储[完全二叉树](只能是这样子存储)优点:查找某个节点的父节点和子节点(也包括有没有子节点)很快缺点:耗用内存空间过大链式存储一般树的存储双亲表示法求父节点方遍孩子表示法求子节点方便双亲孩子表示法求父节点和子节点都很方便二叉树表示法把一个普通的树转化成二叉树来存储具体的转化方法:设法保证任意一个节点的左指针域指向它的第一个孩子右指针域指向他的下一个兄弟只要能满足此条件,就可以把一个普通树转化成二叉树一个普通树转化成的二叉树一定没有右子树森林的存储先把森林转化成二叉树,在存储二叉树操作遍历先序遍历[先访问根节点]先访问根节点再先序访问左子树再先序访问右子树中序遍历[中间访问根节点]中序遍历左子树再访问根节点再中序遍历右子树后续遍历[最后访问根节点]中序遍历左子树中序遍历右子树再访问根节点已知二中遍历序列求原始二叉树通过先序和中序或者中序和后序我们可以还原原始的二叉树但是通过先序和后序是无法还原原始的二叉树的换种说法:只有通过先序和中序,或者中序和后序我们才可以唯一的确定的二叉树应用树是数据库中数据组织一种重要形式操作系统子父进程的关系本身就是一颗树面向对象语言中类的继承关系本身就是一棵树赫夫曼树数操作链式二叉树遍历具体程序演示# include <stdio.h># include <malloc.h>struct BTNode{int data;struct BTNode *pLchild;//p是指针L是左child是孩子struct BTNode *pRchild;};void PreTraverseBTree( struct BTNode * pT );void InTraverseBTree( struct BTNode * pT );void PostTraverseBTree( struct BTNode * pT );struct BTNode *CreateBTree( void );int main( void ){struct BTNode *pT = CreateBTree();printf( "先序\n" );PreTraverseBTree( pT );//先序printf( "中序\n" );InTraverseBTree( pT );//中序printf( "后序\n" );PostTraverseBTree( pT );//后序return 0;}void PreTraverseBTree( struct BTNode * pT ) {/*伪算法先访问根节点再先序访问左子树再先序访问右子树*/if( pT != NULL ){printf( "%c\n", pT->data );if( NULL != pT->pLchild ){PreTraverseBTree( pT->pLchild );}if( NULL != pT->pRchild ){PreTraverseBTree( pT->pRchild );//pT->pLchild可以代表整个左子树}}}void InTraverseBTree( struct BTNode * pT ){if( pT != NULL ){if( NULL != pT->pLchild ){InTraverseBTree( pT->pLchild );}printf( "%c\n", pT->data );if( NULL != pT->pRchild ){InTraverseBTree( pT->pRchild );//pT->pLchild可以代表整个左子树}}}void PostTraverseBTree( struct BTNode * pT ) {if( pT != NULL ){if( NULL != pT->pLchild ){InTraverseBTree( pT->pLchild );}if( NULL != pT->pRchild ){InTraverseBTree( pT->pRchild );//pT->pLchild可以代表整个左子树}printf( "%c\n", pT->data );}}struct BTNode *CreateBTree( void ){struct BTNode *pA = ( struct BTNode * )malloc( sizeof( struct BTNode ) );struct BTNode *pB = ( struct BTNode * )malloc( sizeof( struct BTNode ) );struct BTNode *pC = ( struct BTNode * )malloc( sizeof( struct BTNode ) );struct BTNode *pD = ( struct BTNode * )malloc( sizeof( struct BTNode ) );struct BTNode *pE = ( struct BTNode * )malloc( sizeof( struct BTNode ) );pA->data = 'A';pB->data = 'B';pC->data = 'C';pD->data = 'D';pE->data = 'E';pA->pLchild = pB;pA->pRchild = pC;pB->pLchild = pB->pRchild = NULL;pC->pLchild = pD;pC->pRchild = NULL;pD->pLchild = NULL;pD->pRchild = pE;pE->pLchild = pE->pRchild = NULL;return pA;}线性结构和非线性结构逻辑结构线性数组链表栈和队列是一种特殊线性结构非线性树图物理结构快速排序图表链式二叉树二叉树表示方法后序遍历普通二叉树转化为二叉树普通二叉树转化为完全二叉树(正方形为要删除的)森林转化成二叉树先序遍历先序遍历2已知先序和中序求后序已知先序和中序求后序2已知中序和后序求先序中序遍历中序遍历2栈定义一种可以实现"先进后出"的存储结构栈类似于箱子分类静态栈动态栈算法出栈压栈应用函数调用中断表达式求值内存分配缓冲处理迷宫凡是静态分配的的都是栈里面分配(有操作系统帮你分配的)凡是动态分配的都是堆里面分配(由程序员手动分配的)//编译器编译成功,但是运行不是程序所需要的功能?# include <stdio.h># include <malloc.h># include <stdlib.h>typedef struct Node{int data;struct Node *pNext;}NODE, *PNODE;typedef struct Stack{PNODE pTop;PNODE pBottom;//pBottem是指向栈底下一个没有实际意义的元素}STACK, *PSTACK;void init( PSTACK );void push( PSTACK, int );void traverse( PSTACK );bool pop( PSTACK, int * );bool empty( PSTACK pS );int main( void ){STACK S;//STACK等价于struct Stackint val;init( &S );//目的是造出一个空栈push( &S, 1 );//压栈push( &S, 2 );push( &S, 3 );push( &S, 4 );push( &S, 5 );push( &S, 6 );push( &S, 7 );traverse( &S );//遍历输出clear( &S ); //清空数据traverse( &S );//遍历输出if( pop( &S, &val ) )printf( "出栈成功,出栈的元素是&d\n", val );}else{printf( "出栈失败" );}traverse( &S );//遍历输出return 0;}void init( PSTACK pS ){pS->pTop = ( PNODE )malloc( sizeof( NODE ) );if( NULL == pS->pTop ){printf( "动态内存分配失败!\n" );exit( -1 );}else{pS->pBottom = pS->pTop;pS->pTop = NULL;//或是pS->pBottom = NULL;}}void push( PSTACK pS, int val ){PNODE pNew = ( PNODE )malloc( sizeof( NODE ) );pNew->data = val;pNew->pNext = pS->pTop;//pS->Top不能改为pS->pBottom pS->pTop = pNew;return;}void traverse( PSTACK pS ){PNODE p = pS->pTop;while( p != pS->pBottom ){printf( "%d ", p->data );p = p->pNext;printf( "\n" );return;}bool empty( PSTACK pS ){if( pS->pTop == pS->pBottom )return true;elsereturn false;}//把pS所指向的栈出栈一次,并把出栈的元素存入pVal形参所指向的变量中,如果出栈失败,则返回false,否则truebool pop( PSTACK pS, int *pVal){if( empty( pS ) )//pS本身存放的就是S的地址{return false;}else{PNODE r = pS->pTop;*pVal = r->data;pS->pTop = r->pNext;free( r );r = NULL; //为什么要把r赋给NULL呢??return true;}}//clear清空void clear( PSTACK pS ){if( empty( pS ) ){return ;}else{PNODE p = pS->pTop;PNODE q = p->pNext;while( p != pS->pBottom ){q = p->pNext;free( p );p = q;}pS->pTop = pS->pBottom;}}。

郝斌-数据结构笔记

郝斌——数据结构数据结构概述(1)定义:我们如何把现实中大量而复杂的问题已特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上位实现某个功能二执行的相应操作,这个相应的操作也叫算法。

解释:数据结构要解决的问题就是把现实中大量复杂的问题存储到内存中,把单个数据的类型确定,再把数据之间关系确定,这样就可以存储到内存中去了,算法就是对数据结构的操作。

比如数组是一个数据结构,单个数据类型就确定,数据之间关系就是连续存储,操作数组就是一个算法。

侠义的算法是依附于某个数据结构上,也就是说同样对数组遍历和对链表遍历,算法肯定不一样。

数据结构解决存储问题,算法解决数据间的关系。

数据结构=个体+个体的关系算法=对存储数据的操作。

狭义的算法算法:解题的方法和步骤(2)衡量算法的标准:1时间复杂度大概程序要执行的次数,而非执行的时间:运行步骤最多的最关最核心的要运行的次数可以大概代表2空间复杂度:算法执行过程中大概所占有的最大内存。

3 难易程度4健壮性前两个最重要(一般算法有循环)(3)第三个内容:数据结构的地位(数据结构是软件中最核心的课程)数据库和数据结构的区别:数据库是数据结构的简化版程序:数据的存储+数据段操作+可以被计算机之行的语言(4)预备知识:伪算法不是真正的算法通过语言来实现伪算法,希望编程语言实现要通过指针。

链表的知识很重要,以后都会用到。

C++的指针不够,学C语言的用途是为了以后能看懂更高级的语言*p就代表一个变量,例如i 。

int*p表示定义一个存放整形变量的地址的指针变量。

程序运行完,内存就终止了。

复习:1:指针:int *p//p 是个变量名字,用来存放地址,只能存储int型变量的地址指针的重要性:是C语言的灵魂,定义地址线cpu 内存0控制线 1。

数据线地址内存单元的编号(cpu只能访问内存,不能访问硬盘)从0开始的非负整数,范围为0——4g-1指针就是地址,地址就是指针指针变量是存放内存单元地址的变量指针和指针变量不一样指正的本质是一个操作受限的非负整数分类:Int *p;Int *j;Int i=10;P=&I;//(1).把i的地址赋给i,*p就指向了I (2).p和i没有任何的关系(3)*p就是iP=10//errorI=*j//error1 基本类型的指针(p=&i表示指针变量存储i的地址,但是p为p,i为i 两者无任何关系,但是*p和i却是等效的两者可以互换)变量不进行初始化,会是一个随机数的原因。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

数据结构一、数据结构概述严蔚敏吴伟民高一凡(C代码具体实现此书)数据结构的定义:我们如何把现实中大量而复杂的现实问题以特定数据类型(个体)和特定存储结构(个体和个体的关系)保存到主存储器(内存)中,以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排序)而执行的相应操作,这个相应的操作也叫算法。

数据结构是专门研究数据存储的问题。

数据结构(存储)=个体+个体的关系算法(操作)=对存储数据的操作(存储方式不同,则算法不同)算法又分广义(和存储结构无关(泛型))和狭义算法算法:狭义的算法与数据的存储方式密切相关广义的算法与数据的存储方式无关泛型:利用某种技术达到的效果就是:不同的存储方式,执行的操作是一样的算法:解题方法和步骤衡量算法的标准1. 时间复杂度大概程序要执行的次数,而非执行的时间。

2. 空间复杂度算法执行过程中大概所占用的最大内存。

3. 难易程度4. 健壮性数据结构的地位:数据结构是软件中最核心的课程,(栈,堆只是内存分配方式不同,无物理实体)程序=数据的存储+数据的操作+可以被计算机执行的语言预备知识:指针指针的重要性:指针是C语言的灵魂定义:地址:内存单元的编号,从0开始的非负整数指针:指针就是地址,地址就是指针指针变量是存放内存单元地址的变量指针的本质是一个操作受限的非负整数分类:1. 基本类型的指针基本概念Int i=10;Int * p=&i;//等价于int* p;p=&i;详解这两步操作:1)、p存放了i的地址,我们说p指向了i;2)、p和i是完全不同的两个变量,修改p的值不影响i的值,反之亦然。

3)、p指向i,*p就是i变量本身,*p可以与i在任何地方互换Int* p// p是个指针变量,int * 表示该p 变量只能存储int类型变量的地址注意:指针变量也是变量,只不过它存放的不能是内存单元的内容而是地址;普通变量前不能加*;常量和表达式前不能加&。

2. 指针和数组的关系指针和一维数组数组名一维数组名是个指针常量它存放的是一维数组第一个元素的地址,它的值不能被改变一维数组名指向的是数组的第一个元素下标和指针的关系a[i]<< == >>*(a+i)Int a[5]={1,2,3,4,5};a[i]<< == >>*(a+i)所以a[3]==*(a+3)==3[a]printf(“%p\n”,a+1);//输出a+1地址printf(“%p\n”,*a+1);//输出00000002 等价于a[0]+1无论指针变量所指向的变量占多少字节,指针变量所占字节数不变(4字节)。

回收和销毁的不同结构体(类)为什么会出现结构体为了表示一些复杂的数据,而普通的基本类型变量无法满足要求。

什么叫结构体结构体是用户根据实际需要自己定义的复合数据类型。

如何使用结构体两种方式:struct Student st={1000,“zhangdan”,20};struct Student * pst=&st;1. 通过结构体变量名来实现st.sid2.通过指向结构体变量的指针来实现【重点】pst->sid //pst->sid等价于(*pst).sid,而(*pst).sid等价于st.sid所以pst->sid等价于st.sid。

pst所指向的结构体变量中的sid这个成员注意事项:结构体变量不能加减乘除,但可以相互复制。

普通结构体变量和结构体指针变量作为函数传参的问题动态内存的分配和释放动态构造一维数组假设动态构造一个int型数组Int*p=(int *)malloc(int len)1、malloc只有一个int型的形参,表示要求系统分配的字节数。

2、malloc函数的功能是请求系统len个字节的内存空间,如果请求分配成功,则返回第一个字节的地址,如果分配不成功,则返回NULL。

3、malloc函数能且只能返回第一个字节的地址,所以我们需要把这个无实际意义的第一个字节的地址(俗称干地址)转化为一个有实际意义的地址。

在malloc前面必须加(数据类型*),表示把这个无实际意义的第一个字节的地址转化为相应类型的地址。

如:double *p=(double *)malloc(80);表示将系统分配好的80个字节的第一个字节的地址转化为double型地址,更准确的说是吧第一个字节的地址转化为8个字节的地址,这样p就指向了第一个的8个字节,p+1就指向了第二个的8个字节,p+i就指向了第i+1个的8个字节。

p[0]就是第一个元素,p[i]就是第i+1个元素free()释放的是指针指向的内存!释放的是内存,不是指针!指针是一个变量,只有程序结束时才被销毁。

释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的;因此,释放内存后把指针指向NULL,防止指针在后面不小心又被解引用了。

内存的基本概念:1. 内存是用来存储数据的设备。

他的存储速度介于寄存器和硬盘之间。

2. 内存是CPU唯一可以访问的大容量存储设备!所有硬盘中的程序和数据必须调入内存之后方可被CPU执行!切记:CPU不能直接处理硬盘中的数据!3. 内存的问题是软件开发中最核心的问题之一!如:内存的分配,内存的释放,内存什么时候分配,内存什么时候释放,由谁来分配,由谁来释放,分配在什么地方,访问权限如何!4. 内存是多字节组成的线性一维存储空间5. 内存的基本划分单位是字节6. 每个字节含有8位,每一位存放1个0或1个17. 字节和编号是一一对应的。

每个字节都有一个唯一确定的编号,一个编号对应一个字节,这个编号也叫地址。

8. 一个系统所能管理的内存空间大小取决于参与编号的二进制位数,而二进制位数由地址总线确定。

软件运行与内存关系(垃圾数据)内存是在操作系统的统一管理下使用的!1. 软件在运行前需要向操作系统申请存储空间,在内存空闲空间足够时,操作系统将分配一段内存空间并将外存中软件拷贝一份存入该内存空间中,并启动该软件的运行!(操作系统软件的加载)2. 在软件运行期间,该软件所占内存空间不再分配给其他软件3. 当软件运行完毕后,操作系统将回收该内存空间(注意:操作系统并不清空该内存空间中遗留下来的数据,只是访问控制权限被收回了,所以变量在使用之前必须初始化),以便再次分配给其他软件使用。

综上所述,一个软件所分配到的空间中极有可能存在着以前其他软件使用过后的残留数据,这些数据被称之为垃圾数据。

所以通常情况下我们为一个变量,一个数组,分配好存储空间之后都要对该内存空间初始化。

模块一线性结构【把所有的结点用一根直线串起来】连续存储[数组]1.什么叫数组元素类型相同,大小相等2.数组的优缺点(和链表相比)优点:存取元素效率非常高缺点:事先必须知道数组长度,插入删除元素效率级低,空间通常是有限制的,需要大块连续的内存块3.数组排序(升序)void sort_Arr(struct Arr *Arr){int i,j,t;for(i=0;i<len-1;++i){for(j=i+1;j<len;++j){if(a[i]>a[j]){t=a[i];a[i]=a[j];a[j]=t;}}}}离散存储[链表]1.定义:n个结点离散分配;彼此通过指针相连;每个结点只有一个前驱结点,每个结点只有一个后续结点;首结点没有前驱结点,尾结点没有后续结点。

专业术语:首结点:第一个有效结点尾结点:最后一个有效结点头结点:头结点类型和首结点数据类型一样第一个有效结点之前的那个结点头结点并不存放有效数据目的:可以方便对链表的操作头指针:指向头结点的指针变量尾指针:指向尾结点的指针变量如果希望通过一个函数来对链表进行处理,我们至少需要接收链表的哪些参数:只需要一个参数:头指针因为通过头指针我们可以推算出链表的其他所有信息。

2.分类:单链表双链表:每个结点有两个指针域循环链表:能通过任何一个结点找到其他所有的结点非循环链表3.链表的优缺点(和数组相比)优点:空间没有限制,插入删除效率高缺点:存取元素效率低4.算法:遍历 :PNODE p=pHead->pNext;while(p!=NULL){printf("%d ",p->data);p=p->pNext;}查找清空销毁求长度PNODE p=pHead->pNext;int len=0;while(p!=NULL){len++;p=p->pNext;}排序:void sort_list(struct Node *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;++j,q=q->pNext){if(p->data>q->data)//a[i]>a[j]{t=p->data;//t=a[i]p->data=q->data;//a[i]=a[j]q->data=t;//a[j]=t}}}}删除结点 :注意需要free(被删结点)r=p->pNext;p->pNext=p->pNext->pNext;free(r);插入结点:bool insert_list(PNODE pHead,int pos,int val){}1.r=p->pNext;p->pNext=q;q->pNext=r;2.q->pNext=p->pNext;p->pNext=q;链表的优缺点:静态分配全在栈里分配(由操作系统分配),动态分配全在堆里分配(由程序员手动分配)。

栈和堆表示的是分配数据的方式,静态的和局部变量是以压栈和出栈的方式分配内存,动态内存是以堆排序的方式分配内存。

静态变量超链接/link?url=HGFRGNltZhpzut56rlaunJAHe9ilnPxggR-za5ZoY6Ar4K 2vL-MimUjptvGqcvHgZGJfZC6XJol1DvuXfghpBK把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。

把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。

线性结构的两种常见应用之一栈定义一种可以实现“先进后出”的存储结构类似于箱子分类静态栈(连续:数组)动态栈(不连续:链表)算法压栈(入栈)出栈应用函数调用;中断;表达式求值;内存分配;缓冲处理;迷宫线性结构的两种常见应用之二队列定义一种可以实现“先进先出”的存储结构分类链式队列 -- 用链表实现静态队列 -- 用数组实现静态队列通常都必须是循环队列循环队列的讲解:1.静态队列为什么必须是循环队列如若不是循环队列,指针只能上移,会造成静态分配的连续内存空间浪费。

相关文档
最新文档