链式存储结构的基本操作

链式存储结构的基本操作
链式存储结构的基本操作

1、线性表的链表实现:插入、删除、翻转

2、链式堆栈的实现

3、链式队列的基本操作

实验目的:掌握单链表,链式堆栈,链式队列的定义及基本操作

实验内容:

(1)用带表头的链表存放输入的数据,每读入一个数,按升序顺序插入到链表中,链表中允许两个结点有相同值。链表的头结点存放链表后面的结点个数,初始化时就生成头结点(初值为0)。链表翻转是把数据逆序(变成降序),注意,头结点不动。翻转后要再翻转一次,恢复升序后才能插入新元素,否则会出错

(2)先定义堆栈的几个基本操作,再设计一主函数利用堆的操作完成以下功能:假设一个算术表达式中可以包含三种括号:()[]{},且这三种括号可以按任意次序嵌套使用(如:...[...{...}...[...]...]...(...))。编写判别给定表达式中所含括号是否正确配对出现的算法,已知表达式已存入数据元素为字符的单链表中。

(3)先定义队列的几个基本操作,再设计一主函数利用队列的操作完成以下功能:键盘输入的字符可以临时存入键盘的缓冲区中。为了充分利用缓冲区的空间,往往将缓冲区设计成链式循环队列的结构,并为循环队列结构的缓冲区设置一个队首指针和一个队尾指针。每输入一个字符到缓冲区中,就将尾指针后移,链入缓冲区的循环队列之中;每输出一个字符号,就将队头指针前移,将它从缓冲队列中删除。假设有两个进程同时存在于一个应用程序中,第一个进程连续在屏幕上显示字符“X”,第二个进程不断检查键盘上是否有输入,若有则读入用户键入的字符,将其保存到键盘缓冲区中。

(1)//LinList.h

template class LinList; //前视定义,否则友元无法定义

template //模板类型为T

class ListNode

{

friend class LinList; //定义类LinList为友元

friend void LinListSort(LinList &L);

private:

ListNode *next; //指向下一结点的指针

T data; //定义为公有成员方便使用

int size;

public:

//构造函数1,用于构造头结点

ListNode(ListNode *ptrNext = NULL)

{size=0;next = ptrNext;}

//构造函数2,用于构造其他结点

ListNode(const T& item, ListNode *ptrNext = NULL)

{data = item; next = ptrNext; }

~ListNode(void){} //析构函数

};

//单链表类的定义

template

{

friend void LinListSort(LinList &L);

private:

ListNode *head; //头指针

int size; //当前的数据元素个数

ListNode *Index(int i); //定位

public:

LinList(void); //构造函数

~LinList(void); //析构函数

int ListSize(void) const; //取当前数据元素个数

void Insert(const T& item, int i); //前插

T Delete(int i); //删除

T GetData(int i); //取元素

void OrderInsert(T x);

void Converse(void);

};

//单链表类的实现

template

LinList::LinList(void) //构造函数

{

head = new ListNode(); //头指针指向头结点

size = 0; //size的初值为0

}

template

LinList::~LinList(void) //析构函数

{

ListNode *p, *q;

p = head; //p指向第一个结点

while(p != NULL) //循环释放结点空间直至初始化状态 {

q = p;

p = p->next;

delete q;

}

size = 0; //结点个数置为初始化值0

head = NULL;

}

template

ListNode *LinList::Index(int i) //定位

//返回指向第i个数据元素结点的指针

//参数i的取值范围为:-1≤i≤size-1;i=-1时返回头指针

{

if(i < -1 || i > size-1)

{

cout << "参数i越界出错!" << endl;

exit(0);

}

if(i == -1) return head; //i为-1时返回头指针head

ListNode *p = head->next; //p指向第一个数据元素结点

int j = 0; //从0开始计数

while(p != NULL && j < i) //寻找第i个结点

{

p = p->next;

j++;

}

return p; //返回第i个结点的指针

}

template

int LinList::ListSize(void) const //取当前数据元素个数并返回{

return size;

}

template

void LinList::Insert(const T& item, int i) //插入

//在第i个结点后插入一个元素值为item的新结点

//参数i的取值范围为:0≤i≤size

{

if(i < 0 || i > size)

{

cout << "参数i越界出错!" << endl;

exit(0);

}

ListNode *p = Index(i - 1); //p为指向第i-1个结点的指针

//构造新结点p,p的data域值为item,next域值为p->next

ListNode *q = new ListNode(item, p->next);

p->next = q; //新结点插入第i个结点前

size++; //元素个数加1

}

template

T LinList::Delete(int i) //删除

//删除第i个数据元素并返回。参数i的取值范围为:0≤i≤size-1 {

{

cout << "链表已空无元素可删!" << endl;

exit(0);

}

if(i < 0 || i > size-1)

{

cout << "参数i越界出错!" << endl;

exit(0);

}

ListNode *s, *p = Index(i - 1); //p为指向第i-1个结点指针 s = p->next; //s指向第i个结点

p->next = p->next->next; //第i个结点脱链

T x = s->data;

delete s; //释放第i个结点空间

size--; //结点个数减1

return x; //返回第i个结点的data域值

}

template

T LinList::GetData(int i) //取数据元素

//取第i个数据元素并返回。参数i的取值范围为:0≤i≤size-1 {

if(i < 0 || i > size-1)

{

cout << "参数i越界出错!" << endl;

exit(0);

}

ListNode *p = Index(i); //p指向第i个结点

return p->data;

}

template

void LinList::OrderInsert(T x)

//数据元素x有序插入

{

ListNode *curr, *pre;

//循环初始化

curr = head->next; //curr指向第一个数据元素结点

pre = head; //pre指向头结点

//定位插入位置

while(curr != NULL && curr->data <= x)

{

curr = curr->next;

}

//申请一个结点并赋值

ListNode *q = new ListNode(x, pre->next);

pre->next = q; //把新结点插入pre所指结点后

size++;

}

template

void LinList::Converse(void)

{

ListNode *p, *q;

p = head->next;

head->next = NULL;

while(p != NULL)

{

q = p;

p = p->next;

q->next = head->next;

head->next = q;;

}

}

//LinList.cpp

#include

#include

#include "LinList.h"

void main(void)

{

LinList myList;

int s[] = {1,2,3,4,5,6,7,8,9,10}, n = 10;

int k[] = {1,4,3,6,9,7}, m = 6;

int temp;

for(int i = 0; i < n; i++) //为链表赋值

myList.OrderInsert(s[i]);

cout<<"升序插入数据:"<

for(i = 0; i < myList.ListSize(); i++) //测试Delete()和Insert()的最坏情况

{

temp = myList.GetData(i);

cout << temp << " ";

}

myList.Converse();

cout << endl;

cout<<"链表翻转:"<

for(i = 0; i < myList.ListSize(); i++) //测试Delete()和Insert()的最坏情况 {

temp = myList.GetData(i);

cout << temp << " ";

}

myList.Converse();

for(int j = 0; j < m; j++) //为链表赋值

myList.OrderInsert(k[j]);

myList.Converse();

cout << endl;

cout<<"链表翻转后插入新数据:"<

for(i = 0; i < myList.ListSize(); i++) //测试Delete()和Insert()的最坏情况 {

temp = myList.GetData(i);

cout << temp <<" ";

}

cout<

}

(2)//LinStack.h

template class LinStack; //前视定义,否则友元无法定义template //模板类型为T

class StackNode

{

friend class LinStack; //定义类LinStack为友元

private:

T data; //数据元素

StackNode *next; //指针

public:

//构造函数1,用于构造头结点

StackNode(StackNode *ptrNext = NULL)

{next = ptrNext;}

//构造函数2,用于构造其他结点

StackNode(const T& item, StackNode *ptrNext = NULL)

{data = item; next = ptrNext;}

~StackNode(){};

};

template

class LinStack

{

private:

StackNode *head; //头指针

int size; //数据元素个数

public:

LinStack(void); //构造函数

~LinStack(void); //析构函数

void Push(const T& item); //入栈

T Pop(void); //出栈

T GetTop(void)const; //取栈顶元素

int NotEmpty(void) const; //堆栈非空否

};

//堆栈类的实现

template

LinStack::LinStack() //构造函数

{

head = new StackNode; //头指针指向头结点 size = 0; //size的初值为0

}

template

LinStack::~LinStack(void) //析构函数

//释放所有动态申请的结点空间

{

StackNode *p, *q;

p = head; //p指向头结点

while(p != NULL) //循环释放结点空间

{

q = p;

p = p->next;

delete q;

}

}

template

int LinStack::NotEmpty(void) const //堆栈非空否{

if(size != 0) return 1;

else return 0;

}

template

void LinStack::Push(const T& item) //入栈

{

//新结点newNode的data域值为item,next域值为head->next

StackNode *newNode = new StackNode(item, head->next); head->next = newNode; //新结点插入栈顶

size++; //元素个数加1

}

template

T LinStack::Pop(void) //出栈

{

if(size == 0)

{

cout << "堆栈已空无元素可删!" << endl;

exit(0);

}

StackNode *p = head->next; //p指向栈顶元素结点

T data = p->data;

head->next = head->next->next; //原栈顶元素结点脱链

delete p; //释放原栈顶结点空间

size--; //结点个数减1

return data; //返回原栈顶结点的data域值

}

template

T LinStack::GetTop(void)const //取栈顶元素

{

return head->next->data;

}

//LinStack.cpp

#include

#include

#include

#include

void main()

//判断有n个字符的字符串exp左右括号是否配对正确

LinStack myStack; //定义顺序堆栈类对象myStack char exp[100];

int i;

cout<<"请输入一组表达式(以#结束):"<

for(i=0;i<100;i++)//输入表达式

{

cin>>exp[i];

if(exp[i]=='#')break;

}

for(i=0;exp[i]!='#';i++)

{

if((exp[i]=='(')||(exp[i]== '[')||(exp[i]== '{'))

myStack.Push(exp[i]); //入栈

else if(exp[i] == ')' &&myStack.NotEmpty()

&&myStack.GetTop()=='(')

myStack.Pop(); //出栈

else if(exp[i]==')'&&myStack.NotEmpty()

&&myStack.GetTop()!='(')

{

cout<<"左、右括号配对次序不正确!"<

return;

}

else if(exp[i] == ']' &&myStack.NotEmpty()

&&myStack.GetTop()=='[')

myStack.Pop(); //出栈

else if(exp[i]==']'&&myStack.NotEmpty()

&&myStack.GetTop()!='[')

{

cout<<"左、右括号配对次序不正确!"<

return;

}

else if(exp[i] == '}' &&myStack.NotEmpty()

&&myStack.GetTop()=='{')

myStack.Pop(); //出栈

else if(exp[i]=='}'&&myStack.NotEmpty()

&&myStack.GetTop()!='{')

{

cout<<"左、右括号配对次序不正确!"<

return;

}

else if(((exp[i]==')')||(exp[i]==']')||(exp[i]=='{'))

&&!myStack.NotEmpty())

{

cout<<"右括号多于左括号!"<

return;

}

}

if(myStack.NotEmpty())

cout<<"左括号多于右括号!"<

else

cout<<"左、右括号匹配正确!"<

}

(3)//LinQueue.h

template class LinQueue; //前视定义,否则友元无法定义template

class QueueNode

{

friend class LinQueue; //定义类LinQueue为友元private:

QueueNode *next; //指针

T data; //数据元素

public:

//构造函数

QueueNode(const T& item, QueueNode *ptrNext = NULL) :data(item), next(ptrNext){}

~QueueNode(){}; //析构函数

};

template

class LinQueue

{

private:

QueueNode *front; //队头指针

QueueNode *rear; //队尾指针

int count; //计数器

public:

LinQueue(void); //构造函数

~LinQueue(void); //析构函数

void Append(const T& item); //入队列

T Delete(void); //出队列

T GetFront(void)const; //取队头数据元素

int NotEmpty(void)const //非空否

{return count != 0;};

};

//队列类的实现

template

LinQueue::LinQueue() //构造函数

{

front = rear = NULL; //无头结点

count = 0; //count的初值为0

}

template

LinQueue::~LinQueue(void) //析构函数

{

QueueNode *p, *q;

p = front; //p指向第一个结点

while(p != NULL) //循环直至全部结点空间释放

{

q = p;

p = p->next;

delete q;

}

count = 0; //置为初始化值0

front = rear = NULL;

}

template

void LinQueue::Append(const T& item) //入队列

//把数据元素item插入队列作为新队尾结点

{

//构造新结点newNode,newNode的data域值为item,next域值为NULL QueueNode *newNode = new QueueNode(item, NULL);

if(rear != NULL) rear->next = newNode; //新结点链入

rear = newNode; //队尾指针指向新队尾结点

//若队头指针原先为空则置为指向新结点

if(front == NULL) front = newNode;

count++; //计数器加1

}

template

T LinQueue::Delete(void) //出队列

//把队头结点删除并由函数返回

{

if(count == 0)

{

cout << "队列已空!" << endl;

exit(0);

}

QueueNode *p = front->next; //p指向新的队头结点 T data = front->data; //保存原队头结点的data域值

delete front; //释放原队头结点空间

front = p; //front指向新的队头结点

count--; //计数器减1

return data; //返回原队头结点的data域值

}

template

T LinQueue::GetFront(void)const //取队头数据元素{

if(count == 0)

{

cout << "队列已空!" << endl;

exit(0);

}

return front->data;

}

//LinQueue.cpp

#include

#include "windows.h"

#include

#include

using namespace std;

#include "LinQueue.h"

DWORD WINAPI Input_Thread(LPVOID data)

{

LinQueue myQueue;

char str;

while(true)

{

str = _getch();

myQueue.Append(str);

cout<

}

return((DWORD)data);

}

void main()

{

HANDLE thread_handle;

DWORD thread_dword;

thread_handle = CreateThread(NULL,0,Input_Thread,NULL,0,&thread_dword); //创建线程 while(true) //不断打印X

{

cout<<"X";

Sleep(500);

}

CloseHandle(thread_handle);//关闭线程

}

顺序存储结构和链式存储结构

第二次作业 1. 试比较顺序存储结构和链式存储结构的优缺点。在什么情况下用顺序表比链表好? 2 .描述以下三个概念的区别:头指针、头结点、首元结点(第一个元素结点)。在单链表中设置头结点的作用是什么? 3.已知P结点是双向链表的中间结点,试从下列提供的答案中选择合适的语句序列。 a.在P结点后插入S结点的语句序列是-----------。 b.在P结点前插入S结点的语句序列是-----------。 c.删除P结点的直接后继结点的语句序列是----------。 d.删除P结点的直接前驱结点的语句序列是----------。 e.删除P结点的语句序列是------------。 (1)P->next=P->next->next; (10) P->prior->next=P; (2)P->prior=P->prior->prior; (11) P->next->prior =P; (3) P->next=S; (12)P->next->prior=S; (4) P->prior=S; (13) P->prior->next=S; (5)S->next=P; (14) P->next->prior=P->prior (6)S->prior=P; (15)Q=P->next; (7) S->next= P->next; (16)Q= P->prior; (8) S->prior= P->prior; (17)free(P); (9) P->prior->next=p->next; (18)free(Q); 4. 编写程序,将若干整数从键盘输入,以单链表形式存储起来,然后计算单链表中结点的个数(其中指针P指向该链表的第一个结点)。

树结构习题及答案

第5章树 【例5-1】写出如图5-1所示的树的叶子结点、非终端结点、每个结点的度及树深度。 解: (1)叶子结点有:B 、D 、F 、G 、H 、I 、 J 。 (2)非终端结点有:A 、C 、E 。 (3)每个结点的度分别是:A 的度为4,C 的度为2,E 的度为3,其余结点的度为0。 (4)树的深度为3。 【例5-7】如图5-5所示的二叉树,要求: (1)写出按先序、中序、后序遍历得到的结点序列。 (2)画出该二叉树的后序线索二叉树。 解: (1) 先序遍历序列:ABDEFC 中序遍历序列:DEFBAC 后序遍历序列:FEDBCA b a c d e f 图5-5 A B C D E F G H I J 图5-4

(2)其后序线索二叉树如图5-6所示。 5%、、G 、H 的 3.假定一棵三叉树的结点数为50,则它的最小高度为(3.C )。 A.3 B.4 C.5 D.6 4.在一棵二叉树上第4层的结点数最多为(4.D )。 第六步: 25 30 9 9 18 7 12 8 15 27 43 图5-13

A.2 B.4 C.6 D.8 5.用顺序存储的方法将完全二叉树中的所有结点逐层存放在数组中R[1..n],结点R[i]若有左孩子,其左孩子的编号为结点(5.B)。 A.R[2i+1] B.R[2i] C.R[i/2] D.R[2i-1] 6.由权值分别为3,8,6,2,5的叶子结点生成一棵哈夫曼树,它的带权路径长度为(6.D)。 A.24 B.48 C.72 D.53 7.线索二叉树是一种(7.C)结构。 A.逻辑 B.逻辑和存储 C.物理 D.线性 8.线索二叉树中,结点p没有左子树的充要条件是(8.B)。 A.p->lc=NULL B.p->ltag=1 C.p->ltag=1且p->lc=NULL D.以上都不对 9.设 10. A. 11. A. 12. A. B. C. D. 13. A. C. 14. A. 15. A. C. 1. 2. 3. 4. 5.由二叉树的先序序列和后序序列可以唯一确定一颗二叉树。(5.×) 6.树的后序遍历与其对应的二叉树的后序遍历序列相同。(6.√) 7.根据任意一种遍历序列即可唯一确定对应的二叉树。(7.√) 8.满二叉树也是完全二叉树。(8.√) 9.哈夫曼树一定是完全二叉树。(9.×) 10.树的子树是无序的。(10.×) 三、填空题 1.假定一棵树的广义表表示为A(B(E),C(F(H,I,J),G),D),则该树的度为_____,树的深度为_____,终端结点的个数为______,单分支结点的个数为______,双分支结点的个数为______,三分支结点的个数为_______,C结点的双亲结点为_______,其孩子结点为_______和_______结点。1.3,4,6,1,1,2,A,F,G

四种基本的存储结构

四种基本的存储结构 Prepared on 22 November 2020

数据的四种基本存储方法 数据的存储结构可用以下四种基本存储方法得到: (1)顺序存储方法 该方法把逻辑上相邻的结点存储在物理位置上相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现。 由此得到的存储表示称为顺序存储结构(Sequential Storage Structure),通常借助程序语言的数组描述。 该方法主要应用于线性的数据结构。非线性的数据结构也可通过某种线性化的方法实现顺序存储。 (2)链接存储方法 该方法不要求逻辑上相邻的结点在物理位置上亦相邻,结点间的逻辑关系由附加的指针字段表示。由此得到的存储表示称为链式存储结构(Linked Storage Structure),通常借助于程序语言的指针类型描述。 (3)索引存储方法 该方法通常在储存结点信息的同时,还建立附加的索引表。

索引表由若干索引项组成。若每个结点在索引表中都有一个索引项,则该索引表称之为稠密索引(Dense Index)。若一组结点在索引表中只对应一个索引项,则该索引表称为稀疏索引(Spare Index)。索引项的一般形式是: (关键字、地址) 关键字是能唯一标识一个结点的那些数据项。稠密索引中索引项的地址指示结点所在的存储位置;稀疏索引中索引项的地址指示一组结点的起始存储位置。 (4)散列存储方法 该方法的基本思想是:根据结点的关键字直接计算出该结点的存储地址。 四种基本存储方法,既可单独使用,也可组合起来对数据结构进行存储映像。 同一逻辑结构采用不同的存储方法,可以得到不同的存储结构。选择何种存储结构来表示相应的逻辑结构,视具体要求而定,主要考虑运算方便及算法的时空要求。 数据结构三方面的关系

31构建二叉树的二叉链表存储结构

Computer Education教育与教学研究 文章编号:1672-5913(2008)06-0066-03 构建二叉树的二叉链表存储结构 王岁花,岳冬利 (河南师范大学 计算机与信息技术学院,新乡 453007) 摘要:本文根据笔者多年的教学经验,介绍了四种构建二叉树的二叉链表存储结构的方法。 关键词:二叉树;链表;存储结构;递归 中图分类号:G642 文献标识码:B 1 引言 《高等学校计算机科学与技术专业发展战略研究报告暨专业规范》中将“计算机科学与技术”专业名称下的人才培养规格归纳为三种类型、四个不同的专业方向:科学型(计算机科学专业方向)、工程型(包括计算机工程专业方向和软件工程专业方向)、应用型(信息技术专业方向)。“数据结构”课程出现在四个专业方向的核心课程中,而树型结构同样无一例外的出现在了四个专业方向的核心知识单元中。 树型结构描述的是研究对象之间一对多的关系。在存储树时,如果用指针来描述元素之间的父子关系,则由于对每个元素的孩子数量没有限制(最小可以是0,最多可以是树的度d),若结点的结构定义为一个数据域data和d个指针域,则可以证明,有n个结点、度为d的树的多重链表存储结构中,有n*(d-1)+1个空链域,采用这样的存储将造成很大的浪费。 二叉树是树型结构的一种特殊情况,对于它的操作和存储要比树简单的多,且树和森林可以用二叉链表做媒介同二叉树进行相互转换,所以对二叉树的研究就显得特别重要。 二叉树的二叉链表存储是二叉树的一种重要的存储结构,在每一本“数据结构”教材中都占据了一定的篇幅,但对于怎样建立一棵二叉树的二叉链表存储结构,却很少提及。笔者从事“数据结构”课程教学已二十余年,总结出了以下四种构建方法,希望能对同仁和学数据结构的学生有所帮助。通过本文的学习,学生将会对二叉链表和递归有更深入的理解。 2 二叉树的二叉链表存储结构构建方法 假设有关二叉树的二叉链表存储的类型定义如下: typedef struct BiTNode{ // 结点结构ElemType data ;//数据域 struct BiTNode *Lchild ;//左孩子指针 struct BiTNode *Rchild;//右孩子指针} BiTNode ,*BiTree ; 说明:ElemType为二叉树的元素值类型,根据具体情况进行定义,本文假设为char型;BiTNode为结点类型;BiTree为指向BiTNode的指针类型。下面的算法均用类C 描述。 2.1 利用扩展二叉树的先序序列构建 只根据二叉树的先序序列是不能唯一确定一棵二叉树的。针对这一问题,可做如下处理:对二叉树中每个结点的空指针引出一个虚结点,设其值为#,表示为空,把这样处理后的二叉树称为原二叉树的扩展二叉树。扩展二叉树的先序序列可唯一确定这棵二叉树。如图1所示,给出了一棵二叉树的扩展二叉树,以及该扩展二叉树的先序序列。 收稿日期:2007-12-15 作者简介:王岁花,副教授,主要研究方向是语义Web和课程教学论。 项目资助:河南师范大学教学研究基金资助 66

二叉树的顺序存储结构

#include #include #define VirNode ' ' /* 用空格符描述“虚结点”*/ #define MAXSIZE 64 typedef char ElemType; typedefElemTypeSqBitTree[MAXSIZE]; void crebitree(SqBitTreeBT,int n) /* n为二叉树真实结点数*/ { inti,j,m; i=1; m=0; while(m

{ inti,n=0; for(i=1;i<=BT[0]/2;i++) if(BT[i]!=VirNode&&BT[2*i]==VirNode&&BT[2*i+1]==VirNode) n++; for(;i<=BT[0];i++) if(BT[i]!=VirNode) n++; return n; } int countn1(SqBitTree BT) { inti,n=0; for(i=1;i<=BT[0]/2;i++) if(BT[i]!=VirNode&&(BT[2*i]==VirNode&&BT[2*i+1]!=VirNode|| BT[2*i]!=VirNode&&BT[2*i+1]==VirNode)) n++; return n; } int countn2(SqBitTree BT) { inti,n=0; for(i=1;i<=BT[0]/2;i++) if(BT[i]!=VirNode&&BT[2*i]!=VirNode&&BT[2*i+1]!=VirNode) n++; return n; } //主函数 void main() { SqBitTree T; int n; crebitree(T,5); levellist(T); printf("High=%d\n",high(T)); levellist(T); printf("n2=%d\n",countn2(T)); getch(); }

四种基本的存储结构

数据的四种基本存储方法 数据的存储结构可用以下四种基本存储方法得到: (1)顺序存储方法 ???该方法把逻辑上相邻的结点存储在物理位置上相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现。 ???由此得到的存储表示称为顺序存储结构(SequentialStorageStructure),通常借助程序语言的数组描述。 该方法主要应用于线性的数据结构。非线性的数据结构也可通过某种线性化的方法实现顺序存储。 (2)链接存储方法 ???该方法不要求逻辑上相邻的结点在物理位置上亦相邻,结点间的逻辑关系由附加的指针字段表示。由此得到的存储表示称为链式存储结构(LinkedStorageStructure),通常借助于程序语言的指针类型描述。 (3)索引存储方法 ???该方法通常在储存结点信息的同时,还建立附加的索引表。 ???索引表由若干索引项组成。若每个结点在索引表中都有一个索引项,则该索引表称之为稠密索引(DenseIndex)。若一组结点在索引表中只对应一个索引项,则该索引表称为稀疏索引(SpareIndex)。索引项的一般形式是:

????????????????????(关键字、地址) 关键字是能唯一标识一个结点的那些数据项。稠密索引中索引项的地址指示结点所在的存储位置;稀疏索引中索引项的地址指示一组结点的起始存储位置。(4)散列存储方法 ???该方法的基本思想是:根据结点的关键字直接计算出该结点的存储地址。 四种基本存储方法,既可单独使用,也可组合起来对数据结构进行存储映像。 同一逻辑结构采用不同的存储方法,可以得到不同的存储结构。选择何种存储结构来表示相应的逻辑结构,视具体要求而定,主要考虑运算方便及算法的时空要求。 数据结构三方面的关系 数据的逻辑结构、数据的存储结构及数据的运算这三方面是一个整体。孤立地去理解一个方面,而不注意它们之间的联系是不可取的。 存储结构是数据结构不可缺少的一个方面:同一逻辑结构的不同存储结构可冠以不同的数据结构名称来标识。 【例】线性表是一种逻辑结构,若采用顺序方法的存储表示,可称其为顺序表;若采用链式存储方法,则可称其为链表;若采用散列存储方法,则可称为散列表。

数据结构复习要点(整理版).docx

第一章数据结构概述 基本概念与术语 1.数据:数据是对客观事物的符号表示,在计算机科学中是指所有能输入到计算机中并被计算机程序所处理的符号的总称。 2. 数据元素:数据元素是数据的基本单位,是数据这个集合中的个体,也称之为元素,结点,顶点记录。 (补充:一个数据元素可由若干个数据项组成。数据项是数据的不可分割的最小单位。 ) 3.数据对象:数据对象是具有相同性质的数据元素的集合,是数据的一个子集。(有时候也 叫做属性。) 4.数据结构:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 (1)数据的逻辑结构:数据的逻辑结构是指数据元素之间存在的固有逻辑关系,常称为数据结构。 数据的逻辑结构是从数据元素之间存在的逻辑关系上描述数据与数据的存储无关,是独立于计算机的。 依据数据元素之间的关系,可以把数据的逻辑结构分成以下几种: 1. 集合:数据中的数据元素之间除了“同属于一个集合“的关系以外,没有其他关系。 2. 线性结构:结构中的数据元素之间存在“一对一“的关系。若结构为非空集合,则除了第一个元素之外,和最后一个元素之外,其他每个元素都只有一个直接前驱和一个直接后继。 3. 树形结构:结构中的数据元素之间存在“一对多“的关系。若数据为非空集,则除了第一个元素 (根)之外,其它每个数据元素都只有一个直接前驱,以及多个或零个直接后继。 4. 图状结构:结构中的数据元素存在“多对多”的关系。若结构为非空集,折每个数据可有多个(或零个)直接后继。 (2)数据的存储结构:数据元素及其关系在计算机内的表示称为数据的存储结构。想要计算机处理数据,就必须把数据的逻辑结构映射为数据的存储结构。逻辑结构可以映射为以下两种存储结构: 1. 顺序存储结构:把逻辑上相邻的数据元素存储在物理位置也相邻的存储单元中,借助元素在存储器中的相对位置来表示数据之间的逻辑关系。 2. 链式存储结构:借助指针表达数据元素之间的逻辑关系。不要求逻辑上相邻的数据元素物理位置上也相邻。 5. 时间复杂度分析:1.常量阶:算法的时间复杂度与问题规模n 无关系T(n)=O(1) 2. 线性阶:算法的时间复杂度与问题规模 n 成线性关系T(n)=O(n) 3. 平方阶和立方阶:一般为循环的嵌套,循环体最后条件为i++ 时间复杂度的大小比较: O(1)< O(log 2 n)< O(n )< O(n log 2 n)< O(n2)< O(n3)< O(2 n )

完全二叉树的顺序存储

1 完全二叉树的顺序存储 #include #include class treenode { public: char data; int left, right, parent; treenode(){left=right=parent=-1;} }; int n; //全局变量 void creattree(char a[],treenode t[]) //建二叉树 { for(int i=0;a[i]!='\0';i++) { t[i].data=a[i]; if(2*i+1=n) cout<<"该树中无"<

二叉树的存储表示

二叉树的存储表示 1二叉树的顺序存储表示 2二叉树的链式存储表示 3三叉链表 1二叉树的顺序存储表示 二叉树的顺序存储结构的定义如下: #define MAXSIZE = 100; //暂定二叉树中节点数的最大值为100 Typedef struct { ElemType *data ; //存储空间基址(初始化时分配空间) Int nodeNum ; //二叉树中节点数 }SqBiTree ; //二叉树的顺序存储结构 为了能在存储结构中反映出节点之间的逻辑关系,必须将二叉树中节点依照一定规律安排在这组存储单元中。对于完全二叉树,只要从根起按层序存储即可。 显然,这种顺序存储结构仅适用于完全二叉树。因为,在最坏的情况下,一个深度为 k 且只有 k 个结点的单支树(树中不存在度为 2 的结点)却需要长度为2k -1的一维数组。 二叉树的顺序存储图如图1所示: 2 6 320 116 5402 106 543216 (a )满二叉树(b )一般二叉树 图1 顺序存储

2二叉树的链式存储表示 二叉树有不同的链式结构,其中最常用的是二叉链表与三叉链表。二叉链表的结点形式如表1所示: 表1链式存储 date域:称为数据域,用于存储二叉树结点中的数据元素, 1child域:称为左孩子指针域,用于存放指向本结点左孩子的指针(左指针)。 rchild域:称为右孩子指针域,用于存放指向本结点右孩子的指针(右指针)二叉链表中的所有存储结点通过它们的左、右指针的链接而形成一个整体。 根指针:每个二叉链表还必须有一个指向根结点的指针。根指针具有标识二叉链表的作用,对二叉链表的访问能从根指针开始。 图2中(a)(b)表示一棵二叉树及其二叉链表。值得注意的是,二叉链表中每个存储结点的每个指针域必须有一个值,这个值或者是指向该结点的一个孩子的指针,或者是空指针NULL。 二叉链表的类型定义如下: Typedef struct btnode *bitreptr; Struct btnode { Datatype data; Bitreptr lchild,rchild; }; Bitreptr root; 若二叉树为空,则root=NULL。若某结点的某个孩子不存在,则相应的指针为空。具有n个结点的二叉树中,一共有2n个指针域,其中只有n-1个用来指向结点的的左右孩子,其余的n+1个指针域为NULL。 在二叉链表这种存储结构上,二叉树的多数基本运算如求根,求左、右孩子等很容易实现。但求双亲运算PARENT(BT,X)的实现却比较麻烦,而且其时间性能不高。

用顺序结构表示栈并实现栈地各种基本操作

栈的顺序表示和实现 2.2基础实验 2.2.1实验目的 (1)掌握栈的顺序表示和实现 (2)掌握栈的链式表示和实现 (3)掌握队列的顺序表示和实现 (4)掌握队列的链式表示和实现 2.2.2实验内容 实验一:栈的顺序表示和实现 【实验内容与要求】 编写一个程序实现顺序栈的各种基本运算,并在此基础上设计一个主程序,完成如下功能: (1)初始化顺序栈 (2 )插入元素 (3)删除栈顶元素 (4)取栈顶元素 (5)遍历顺序栈 (6)置空顺序栈 【知识要点】 栈的顺序存储结构简称为顺序栈,它是运算受限的顺序表。 对于顺序栈,入栈时,首先判断栈是否为满,栈满的条件为:p->top= =MAXNUM-1 ,栈满时,不能入栈;否则岀现空间溢岀,引起错误,这种现象称为上溢。 岀栈和读栈顶元素操作,先判栈是否为空,为空时不能操作,否则产生错误。通常栈空作为一种控制转移的条件。 注意: (1)顺序栈中元素用向量存放 (2)栈底位置是固定不变的,可设置在向量两端的任意一个端点 (3)栈顶位置是随着进栈和退栈操作而变化的,用一个整型量top (通常称top为栈顶指针)来指示当前栈顶位置 【实现提示】 /*定义顺序栈的存储结构*/

typedef struct { ElemType stack[MAXNUM]; int top; }SqStack; /*初始化顺序栈函数*/ void lnitStack(SqStack *p) {q=(SqStack*)malloc(sizeof(SqStack)/* 申请空间*/) /*入栈函数*/ void Push(SqStack *p,ElemType x) {if(p->toptop=p->top+1; /* 栈顶+1*/ p->stack[p->top]=x; } /* 数据入栈*/ } /*岀栈函数*/ ElemType Pop(SqStack *p) {x=p->stack[p->top]; /* 将栈顶元素赋给x*/ p->top=p->top-1; } /* 栈顶-1*/ /*获取栈顶元素函数*/ ElemType GetTop(SqStack *p) { x=p_>stack[p_>top];} /*遍历顺序栈函数*/ void OutStack(SqStack *p) { for(i=p->top;i>=0;i--) printf("第%d 个数据元素是:%6d\n",i,p->stack[i]);} /*置空顺序栈函数*/ void setEmpty(SqStack *p) { p->top= -1;} 【参考程序】 #include #include #define MAXNUM 20 #define ElemType int /*定义顺序栈的存储结构*/ typedef struct { ElemType stack[MAXNUM]; int top; }SqStack; /*初始化顺序栈*/ void InitStack(SqStack *p) { if(!p) printf("Eorror");

树结构习题及答案

【例5-1】写出如图5-1所示的树的叶子结点、非终端结点、每个结点的度及树深度。 A B C D E F G H I J 图5-1 解: (1)叶子结点有:B、D、F、G、H、I、J。 (2)非终端结点有:A、C、E。 (3)每个结点的度分别是:A的度为4,C的度为2,E的度为3,其余结点的度为0。 (4)树的深度为3。 【例5-2】一棵度为2的树与一棵二叉树有什么区别? 解:度为2的树有两个分支,但分支没有左右之分;一棵二叉树也有两个分支,但有左右之分,左右子树的次序不能交换。 【例5-3】树与二叉树有什么区别? 解:区别有两点: (1)二叉树的一个结点至多有两个子树,树则不然; (2)二叉树的一个结点的子树有左右之分,而树的子树没有次序。 【例5-4】分别画出具有3个结点的树和三个结点的二叉树的所有不同形态。 解:如图5-2(a)所示,具有3个结点的树有两种不同形态。 图5-2(a) 如图5-2(B)所示,具有3个结点的二叉树有以下五种不同形态。 图5-2(b) 【例5-5】如图5-3所示的二叉树,试分别写出它的顺序表示和链接表示(二叉链表)。 解: (2)该二叉树的二叉链表表示如图5-4所示。

【例5-6】试找出满足下列条件的所有二叉树: (1)先序序列和中序序列相同; (2)中序序列和后序序列相同; (3)先序序列和后序序列相同。 解: (1)先序序列和中序序列相同的二叉树为:空树或者任一结点均无左孩子的非空二叉树; (2)中序序列和后序序列相同的二叉树为:空树或者任一结点均无右孩子的非空二叉树; (3)先序序列和后序序列相同的二叉树为:空树或仅有一个结点的二叉树。 【例5-7】如图5-5所示的二叉树,要求: (1)写出按先序、中序、后序遍历得到的结点序列。 (2)画出该二叉树的后序线索二叉树。 解: (1) 先序遍历序列:ABDEFC 中序遍历序列:DEFBAC 后序遍历序列:FEDBCA (2)其后序线索二叉树如图5-6所示。 b a c d e f 图5-5 图5-6

实验四、栈的顺序和链式存储的表示和实现

实验四、栈的顺序和链式存储的表示和实现 实验目的: 1.熟悉栈的特点(先进后出)及栈的基本操作,如入栈、出栈等。 2.掌握栈的基本操作在栈的顺序存储结构和链式存储结构上的实现。 实验内容: 1.栈的顺序表示和实现 编写一个程序实现顺序栈的各种基本运算,并在此基础上设计一个主程序,完成如下功能。 (1)初始化顺序栈 (2)插入一个元素 (3)删除栈顶元素 (4)取栈顶元素 (5)遍历顺序栈 (6)置空顺序栈 #include #include #define MAXNUM 20 #define elemtype int //定义顺序栈的存储结构 typedef struct {

elemtype stack[MAXNUM]; int top; }sqstack; //初始化顺序栈 void initstack(sqstack *p) { if(!p) printf("error"); p->top=-1; } //入栈 void push(sqstack *p,elemtype x) { if(p->toptop=p->top+1; p->stack[p->top]=x; } else printf("\noverflow!\n"); } //出栈

elemtype pop(sqstack *p) { elemtype x; if(p->top!=0) { x=p->stack[p->top]; printf(" 以前的栈顶数据元素%d 已经被删除!\n",p->stack[p->top]); p->top=p->top-1; return(x); } else { printf("栈为空\n"); return(0); } } //获取栈顶元素 elemtype gettop(sqstack *p) { elemtype x;

数据结构顺序存储结构

数据结构顺序表 第一种方法: #include #define MAX_SIZE 50 typedefintElemType; //自定义类型 typedefstruct { //结构体 ElemTypedata[MAX_SIZE]; intlen; }SqList; /*参数一:顺序表参数二:一个数组参数三:顺序表长度*/ voidcreateSqList(SqList&L,int a[], int n){ for(int i = 0; i < n; i++){ L.data[i]=a[i]; } L.len = n; } //打印输出顺序表 voidprintSqList(SqList L){ printf("打印顺序表:"); for(int i = 0; i

第二种方法: #include #include #define MAX_SIZE 50 typedefintElemType; //自定义类型 typedefstruct { //结构体 ElemTypedata[MAX_SIZE]; intlen; }SqList; /*参数一:顺序表参数二:一个数组参数三:顺序表长度*/ voidcreateSqList(SqList *L,int a[], int n){ for(int i = 0; i < n; i++){ L->data[i]=a[i]; } L->len = n; } //打印输出顺序表 voidprintSqList(SqList *L){ printf("打印表:"); for(int i = 0; i < L->len; i++){ printf("%d ",L->data[i]); } printf("\n"); } int main(){ //初始化一个空表 SqList *L; L=(SqList *)malloc(sizeof(SqList)); L->len=0; int i; //初始化数组 int array[5]; for(i=0;i<5;i++){ array[i]=i; } createSqList(L,array, 5); printSqList(L); }

实验五--二叉树的存储结构和基本操作

实验五二叉树的存储表示和基本操作 实验内容 1. 二叉树的二叉链表的存储结构 —————二叉树的二叉链表存储表示———————— typedef struct node { ElemType data; /*数据元素*/ struct node *lchild; /*指向左孩子*/ struct node *rchild; /*指向右孩子*/ } BTNode; 2. 二叉树的基本操作 (1)创建操作:创建一棵二叉树。 (2)查找操作:查找二叉树中值为x的结点。 (3)查找左孩子操作:查找二叉树中值为x的结点的左孩子。 (4)查找右孩子操作:查找二叉树中值为x的结点的右孩子。 (5)求深度操作:求二叉树的深度。 (6)求宽度操作:求二叉树的宽度。 (7)求结点个数操作:求二叉树的结点个数。 (8)求叶子结点个数操作:求二叉树的叶子结点个数。 (9)输出操作:以括号表示法输出二叉树。 3. 链式队列操作实现的步骤 (1)实现将链式队列的存储结构和基本操作程序代码。 (2)实现main主函数。 4.程序代码完整清单 #include #include #define MaxSize 100 typedef char ElemType; typedef struct node { ElemType data; /*数据元素*/ struct node *lchild; /*指向左孩子*/ struct node *rchild; /*指向右孩子*/ } BTNode; //基本操作函数声明 void CreateBTNode(BTNode *&b,char *str); /*创建一棵二叉树*/ BTNode *FindNode(BTNode *b,ElemType x); /*查找二叉树的结点*/ BTNode *LchildNode(BTNode *p); /*查找二叉树结点的左孩子*/ BTNode *RchildNode(BTNode *p); /*查找二叉树结点的右孩子*/ int BTNodeDepth(BTNode *b); /*求二叉树的深度*/

栈的顺序和链式存储的表示和实现

实验三栈的顺序和链式存储的表示和实现 实验目的: 1.熟悉栈的特点(先进后出)及栈的基本操作,如入栈、出栈等。 2.掌握栈的基本操作在栈的顺序存储结构和链式存储结构上的实现。 实验内容: 1.栈的顺序表示和实现 编写一个程序实现顺序栈的各种基本运算,并在此基础上设计一个主程序,完成如下功能。 (1)初始化顺序栈 (2)插入一个元素 (3)删除栈顶元素 (4)取栈顶元素 (5)便利顺序栈 (6)置空顺序栈 #include #include #define MAXNUM 20 #define elemtype int //定义顺序栈的存储结构 typedef struct { elemtype stack[MAXNUM]; int top; }sqstack; //初始化顺序栈 void initstack(sqstack *p) { if(!p) printf("error"); p->top=-1; } //入栈 void push(sqstack *p,elemtype x) { } //出栈 elemtype pop(sqstack *p) { }

//获取栈顶元素 elemtype gettop(sqstack *p) { elemtype x; if(p->top!=-1) { x=p->stack[p->top]; return x; } else { printf("Underflow!\n"); return 0; } } //遍历顺序栈 void outstack(sqstack *p) { int i; printf("\n"); if(p->top<0) printf("这是一个空栈!\n"); for(i=p->top;i>=0;i--) printf("第%d个数据元素是:%6d\n",i,p->stack[i]); } //置空顺序栈 void setempty(sqstack *p) { } //主函数 main() { sqstack *q; int y,cord; elemtype a;

线性表的链式存储结构实验报告

实验报告 课程名称:数据结构与算法分析 实验名称:链表的实现与应用 实验日期:班级:数媒1401 姓名:范业嘉学号 08 一、实验目的 掌握线性表的链式存储结构设计与基本操作的实现。 二、实验内容与要求 ⑴定义线性表的链式存储表示; ⑵基于所设计的存储结构实现线性表的基本操作; ⑶编写一个主程序对所实现的线性表进行测试; ⑷线性表的应用:①设线性表L1和L2分别代表集合A和B,试设计算法求A和B的并集C,并用 线性表L3代表集合C;②(选做)设线性表L1和L2中的数据元素为整数,且均已按值非递减有序排列,试设计算法对L1和L2进行合并,用线性表L3保存合并结果,要求L3中的数据元素也按值非递减有序排列。 ⑸设计一个一元多项式计算器,要求能够:①输入并建立多项式;②输出多项式;③执行两个多项式相加;④执行两个多项式相减;⑤(选做)执行两个多项式相乘。 三、数据结构设计 1.按所用指针的类型、个数、方法等的不同,又可分为: 线性链表(单链表) 静态链表 循环链表 双向链表 双向循环链表 2.用一组任意的存储单元存储线性表中数据元素,用指针来表示数据元素间的逻辑关系。 四、算法设计 1.定义一个链表 void creatlist(Linklist &L,int n) { int i; Linklist p,s; L=(Linklist)malloc(sizeof(Lnode)); p=L; L->next=NULL; for(i=0;idata); s->next=NULL; p->next=s; p=s; }

数据结构试题及答案

一、判断题: 1、线性表的逻辑顺序与物理顺序总是一致的。( ) 2、线性表的顺序存储表示优于链式存储表示。( ) 3、线性表若采用链式存储表示时所有结点之间的存储单元地址可连续可不连续。( ) 4、二维数组是其数组元素为线性表的线性表。( ) 5、每种数据结构都应具备三种基本运算:插入、删除和搜索。( ) 6、数据结构概念包括数据之间的逻辑结构,数据在计算机中的存储方式和数据的运算三个 方面。( ) 7、线性表中的每个结点最多只有一个前驱和一个后继。() 8、线性的数据结构可以顺序存储,也可以链接存储。非线性的数据结构只能链接存储。() 9、栈和队列逻辑上都是线性表。() 10、单链表从任何一个结点出发,都能访问到所有结点() 11、删除二叉排序树中一个结点,再重新插入上去,一定能得到原来的二叉排序树。() 12、快速排序是排序算法中最快的一种。() 13、多维数组是向量的推广。() 14、一般树和二叉树的结点数目都可以为0。() 15、直接选择排序是一种不稳定的排序方法。() 16、98、对一个堆按层次遍历,不一定能得到一个有序序列。() 17、在只有度为0和度为k的结点的k叉树中,设度为0的结点有n0个,度为k的结点有nk个,则有n0=nk+1。() 18、折半搜索只适用与有序表,包括有序的顺序表和有序的链表。() 19、堆栈在数据中的存储原则是先进先出。() 20、队列在数据中的存储原则是后进先出。() 21、用相邻矩阵表示图所用的存储空间大小与图的边数成正比。() 22、哈夫曼树一定是满二叉树。() 23、程序是用计算机语言表述的算法。() 24、线性表的顺序存储结构是通过数据元素的存储地址直接反映数据元素的逻辑关系。() 25、用一组地址连续的存储单元存放的元素一定构成线性表。() 26、堆栈、队列和数组的逻辑结构都是线性表结构。() 27、给定一组权值,可以唯一构造出一棵哈夫曼树。() 28、只有在初始数据为逆序时,冒泡排序所执行的比较次数最多。()

二叉树链式存储结构 第六章实验报告

实验名称:二叉树链式存储结构 实验类型:验证性实验 班级:20102111 学号:2010211102 姓名: 实验日期:2012.5.27 1.问题描述 二叉链表的C语言描述; 基本运算的算法——建立二叉链表、先序遍历二叉树、中序遍历二叉树、后序遍历二叉树、后序遍历求二叉树深度。 2.数据结构设计 typedef struct Bitnode { char data; struct Bitnode *lchild,*rchild; }Bitnode,*Bitree; 3.算法设计 建立二叉链表:void createBitree(Bitree &T) { char ch; if((ch=getchar())=='#') T=NULL; else{T=(Bitnode*)malloc(sizeof(Bitnode)); T->data=ch; createBitree(T->lchild); createBitree(T->rchild); } } 先序遍历二叉树:void preorder(Bitree &T) { if(T!=NULL) {printf("%c",T->data); preorder(T->lchild); preorder(T->rchild);}}

中序遍历二叉树:void inorder(Bitree &T) {if(T!=NULL) { inorder(T->lchild); printf("%c",T->data); inorder(T->rchild); } 后序遍历二叉树:void postorder(Bitree &T) { if(T!=NULL) {postorder(T->lchild); postorder(T->rchild); printf("%c",T->data); } }//后序遍历 后序遍历求二叉树深度:int Depth(Bitree &T) {//返回深度 int d,dl,dr; if(!T) d=0; else {dl=Depth(T->lchild); dr=Depth(T->rchild); d=1+(dl>dr?dl:dr) ; } return d; } 4.运行、测试与分析 运行程序,显示菜单, (1)如图1.1: 图1.1 (2)结果图1.2: 图1.2

相关文档
最新文档