赞
踩
常用数据结构
(一对一的关系)
- 用一组地址连续的存储单元依次存储线性表中每个数据元素。
- 逻辑关系相邻的两个元素在物理位置上也相邻。
typedef struct { int items[LISTSIZE]; int length; } SqList;
- length:线性表当前的长度。
- LISTSIZE:最大容量。
template <typename T> class sqlist{ public: sqlist(int maxsize=10):Maxsize(maxsize) { elements=new T[maxsize]; length=0; } private: int Maxsize;//最大容量 T *elements;//元素初始地址 int length;//当前有效长度 };
初始化顺序表
//初始化顺序表,表的长度设置为0 void InitList(SqList *L) { L->length=0; }
求顺序表中当前元素的个数
//顺序表的长度 int ListLength(SqList * L) { return L->length; }
判断顺序表是否为空
//判断顺序表是否为空 bool ListEmpty(SqList *L) { if(L->length==0) return true; else return false; }
向顺序表中插入数据元素
//向顺序表中插入数据元素 bool ListInsert(SqList *L,int pos,int item) { int i; if(L->length==LISTSIZE) { printf("顺序列表已满,无法进行插入操作"); return false; } if(pos<1||pos>L->length+1) { printf("插入位置不合法"); return false; } for(i=L->length-1;i>=pos-1;i--) { L->items[i+1]=L->items[i]; } L->items[pos-1]=item; L->length++; return true; }
删除顺序表中的元素
//删除顺序表中的元素 bool ListDelete(SqList *L,int pos,int *item) { int i; if(L->length==0) { printf("顺序表为空表"); return false; } if(pos<1||pos>L->length) { printf("删除位置无效"); } *item=L->items[pos-1]; for(int i=pos-1;i<L->length-1;i++) { L->items[i]=L->items[i+1]; } L->length--; return true; }
查找指定元素在顺序表中的位置
//查找制定元素在顺序表中的位置 int Find(SqList L,int item) { int pos=0; if(ListEmpty(&L)) { printf("顺序表为空表,无法进行查找操作"); return 0; } while(pos<L.length&&L.items[pos]!=item) { pos++; } if(pos<L.length) return pos+1; else return 0; }
获取顺序表中指定位置上的数据元素
//获得顺序表中指定位置上的数据元素 int GetElem(SqList *L,int pos,int *item) { if(ListEmpty(L)) return 0; if(pos<1||pos>L->length) return 0; *item=L->items[pos-1]; return 1; }
- 遍历顺序表
//遍历顺序表 void TravereList(SqList *L) { int pos =0; while(pos<L->length) { printf("item1: %d",L->items[pos]); pos++; } }c语言版本:
#include <iostream> using namespace std; #define LISTSIZE 100 typedef struct { int items[LISTSIZE]; int length; } SqList; //初始化顺序表,表的长度设置为0 void InitList(SqList *L) { L->length=0; } //顺序表的长度 int ListLength(SqList * L) { return L->length; } //判断顺序表是否为空 bool ListEmpty(SqList *L) { if(L->length==0) return true; else return false; } //向顺序表中插入数据元素 bool ListInsert(SqList *L,int pos,int item) { int i; if(L->length==LISTSIZE) { printf("顺序列表已满,无法进行插入操作"); return false; } if(pos<1||pos>L->length+1) { printf("插入位置不合法"); return false; } for(i=L->length-1;i>=pos-1;i--) { L->items[i+1]=L->items[i]; } L->items[pos-1]=item; L->length++; return true; } //删除顺序表中的元素 bool ListDelete(SqList *L,int pos,int *item) { int i; if(L->length==0) { printf("顺序表为空表"); return false; } if(pos<1||pos>L->length) { printf("删除位置无效"); } *item=L->items[pos-1]; for(int i=pos-1;i<L->length-1;i++) { L->items[i]=L->items[i+1]; } L->length--; return true; } //查找制定元素在顺序表中的位置 int Find(SqList L,int item) { int pos=0; if(ListEmpty(&L)) { printf("顺序表为空表,无法进行查找操作"); return 0; } while(pos<L.length&&L.items[pos]!=item) { pos++; } if(pos<L.length) return pos+1; else return 0; } //获得顺序表中指定位置上的数据元素 int GetElem(SqList *L,int pos,int *item) { if(ListEmpty(L)) return 0; if(pos<1||pos>L->length) return 0; *item=L->items[pos-1]; return 1; } //遍历顺序表 void TravereList(SqList *L) { int pos =0; while(pos<L->length) { printf("item1: %d",L->items[pos]); pos++; } } int main() { SqList Fibonacci; cout<<"建立顺序表"<<endl; InitList(&Fibonacci); for(int i=0;i<7;) { int num; cin>>num; if(ListInsert(&Fibonacci,i+1,num)) i++; } TravereList(&Fibonacci); int item; ListDelete(&Fibonacci,7,&item); TravereList(&Fibonacci); return 0; }c++版本:
#include<iostream> using namespace std; template <typename T> class sqlist{ public: sqlist(int maxsize=10):Maxsize(maxsize) { elements=new T[maxsize]; length=0; } //打印顺序表的长度 int listLength() { return length; } //判断顺序表是否为空 bool IsEmpty() { return length==0; } //顺序表中插入元素 void InsertElement(T elem,int position) { if(IsEmpty()) { elements[length++]=elem; } else { for(int i=length;i>=position;i--) elements[i]=elements[i-1]; elements[position-1]=elem; length++; } } //顺序表中删除元素 void DelElement(T elem,int position) { T del_elem=elements[position-1]; for(int i=position-1;i<length-1;i++) elements[i]=elements[i+1]; length--; } //查找元素的位置 int FindElement(T elem) { int i; for(i=0;i<length;i++) { if(elements[i]==elem) { std::cout<<"i: "<<i<<std::endl; break; } } if(i==length) { std::cout<<"find not"<<std::endl; return -1; } else { std::cout<<"find yes"<<std::endl; return i; } } //打印 void Printf() { for(int i=0;i<length;i++) std::cout<<elements[i]<<" "; std::cout<<std::endl; } private: int Maxsize;//最大容量 T *elements;//元素初始地址 int length;//当前有效长度 }; int main() { sqlist<int> sq(20); sq.InsertElement(10,2); sq.Printf(); sq.InsertElement(30,1); sq.Printf(); sq.InsertElement(50,1); sq.Printf(); sq.InsertElement(100,2); sq.Printf(); sq.DelElement(30,3); sq.Printf(); sq.FindElement(100); return 0; }
- 用一组任意的存储单元存储线性表中的数据元素。
- 相比顺序存储结构,链式存储结构中,除了需要存储数据元素信息之外,还需要存储它的后继元素的存储地址(指针)。
- 单链表结点的物理位置不一定连续,单链表逻辑上通过指针实现连续。
- 单链表有一个头结点和一个尾结点,并且只有尾结点没有后继结点,其他结点有且仅有一个后继结点。
- 只要知道了链表的头结点,就可以遍历整个链表。
- 单链表的每一个结点包含两部分:数据域和指针域。
- 表头:用来存放第一个结点的地址。
- 表尾:表尾没有后继,所以尾结点的指针域为空指针(NULL)。
typedef struct node{ int data;//数据域 node * next;//指针域 }LNode,*LinkList;//LinkList是指向LNode类型数据的指针类型定义
- LinkList是指向LNode类型数据的指针类型定义 ,也就是说,在定义一个指向LNode类型数据的指针变量时,语句
LNode *L;
和
LinkList L;
是等价的。
- class ListNode{
- public:
- ListNode * next;
- int data;
- };
- class LinkList
- {
- public:
- LinkList()
- {
- node=new ListNode;
- node->next=NULL;
- }
- ~LinkList()
- {
- delete node;
- }
- void CreateLinkListBack(int n);
- void CreateLinkListHead(int n);
- void InsertNode(int position,int elem);
- void removeNode(ListNode* p);
- ListNode* findNode(int value);
- void PrintLinkList();
- public:
- ListNode *node;
- };
- //初始化链表
- LinkList init_list()
- {
- LinkList L=new LNode;
- if(!L)
- return NULL;
- L->next=NULL;//指针域置空
- return L;
- }
- //打印链表
- void Printf_list(LinkList &L)
- {
- LinkList temp=L->next;
- while(temp!=NULL)
- {
- cout<<temp->data<<"->";
- temp=temp->next;
- }
- }
步骤:
- 先创建一个新节点s(LinkList),并给数据域赋值,
- 新节点的指针域指向L-next,
- L的指针域next指向s。
- //插入数据(头插)
- void create_LinkList(LinkList &L,int n)
- {
- while(n--)
- {
- LinkList s=new LNode;
- cin>>s->data;
- s->next=L->next;
- L->next=s;
- }
- }
注意:使用头插法插入数据后,链表中数据的顺序和插入前的数据顺序相反。
步骤:
- 先让r节点指向尾结点,
- 创建一个新节点s(LinkList),并给数据域赋值,且s->next为NULL,因为s为尾结点,
- r的指针域指向s,
- 更新尾节点,即r=s。
- //插入数据(尾插)
- void create_LinkList_back(LinkList &L,int n)
- {
- LinkList r=L;
- while(n--)
- {
- LinkList s=new LNode;
- cin>>s->data;
- s->next=NULL;
- r->next=s;
- r=s;
-
- }
-
- }
注意:使用尾插法插入数据后,链表中数据的顺序和插入前的数据顺序相同。
- //插入数据
- void InsertList(LinkList q,int e)
- {
- LinkList p=new LNode;
- p->data=e;
-
- p->next=q->next;
- q->next=p;
-
- }
- LinkList Get_elem(LinkList &L,int e)
- {
- LinkList temp=L->next;
- while(temp!=NULL)
- {
- if(e==temp->data)
- {
- return temp;
- }
- temp=temp->next;
- }
- return NULL;
-
- }
- #include<iostream>
-
- using namespace std;
-
- typedef struct node{
- int data;//数据域
- struct node * next;//指针域
- }LNode,*LinkList;//LinkList是指向LNode类型数据的指针类型定义
-
- //初始化链表
- LinkList init_list()//引用
- {
- LinkList L=new LNode;
- if(!L)
- return NULL;
- L->next=NULL;//指针域置空
- return L;
- }
- //插入数据(头插)
- void create_LinkList(LinkList &L,int n)
- {
- while(n--)
- {
- LinkList s=new LNode;
- cin>>s->data;
- s->next=L->next;
- L->next=s;
- }
- }
- //插入数据(尾插)
- void create_LinkList_back(LinkList &L,int n)
- {
- LinkList r=L;
- while(n--)
- {
- LinkList s=new LNode;
- cin>>s->data;
- s->next=NULL;
- r->next=s;
- r=s;
-
- }
-
- }
- //打印链表
- void Printf_list(LinkList &L)
- {
- LinkList temp=L->next;
- while(temp!=NULL)
- {
- cout<<temp->data<<"->";
- temp=temp->next;
- }
- cout<<endl;
- }
- //插入数据
- void InsertList(LinkList q,int e)
- {
- LinkList p=new LNode;
- p->data=e;
-
- p->next=q->next;
- q->next=p;
-
- }
- LinkList Get_elem(LinkList &L,int e)
- {
- LinkList temp=L->next;
- while(temp!=NULL)
- {
- if(e==temp->data)
- {
- return temp;
- }
- temp=temp->next;
- }
- return NULL;
-
- }
- int main()
- {
- LinkList L=init_list();
- if(!L)
- {
- cout<<"初始化失败"<<endl;
- return 0;
- }
- cout<<"初始化成功"<<endl;
- int num;
- cout<<"请输入插入的数量:"<<endl;
- cin>>num;
- create_LinkList_back(L,num);
- Printf_list(L);
- int elem;
- LinkList elem_list;
- cout<<"请输入需要查找的数"<<endl;
- cin>>elem;
- elem_list=Get_elem(L,elem);
- while(!elem_list)
- {
- cout<<"没有查找到,请重新输入"<<endl;
- cin>>elem;
- elem_list=Get_elem(L,elem);
- }
- cout<<"找到相应数据,数据地址为:"<<elem_list<<endl;
- if(elem_list!=NULL)
- {
- cout<<"请输入需要插入的数"<<endl;
- int elem_insert;
- cin>>elem_insert;
- InsertList(elem_list,elem_insert);
- Printf_list(L);
- }
- return 0;
- }
- #include <iostream>
- using namespace std;
- class ListNode{
- public:
- ListNode * next;
- int data;
- };
- class LinkList
- {
- public:
- LinkList()
- {
- node=new ListNode;
- node->next=NULL;
- }
- ~LinkList()
- {
- delete node;
- }
- void CreateLinkListBack(int n);
- void CreateLinkListHead(int n);
- void InsertNode(int position,int elem);
- void removeNode(ListNode* p);
- ListNode* findNode(int value);
- void PrintLinkList();
- public:
- ListNode *node;
- };
- //头插
- void LinkList::CreateLinkListHead(int n)
- {
- while(n--)
- {
- //插入的数据
- ListNode* l=new ListNode;
- cin>>l->data;
- l->next=node->next;
- node->next=l;
- }
- }
- //尾插
- void LinkList::CreateLinkListBack(int n)
- {
- ListNode* r=node;
- while(n--)
- {
- ListNode* l=new ListNode;
- cin>>l->data;
- l->next=NULL;
- r->next=l;
- r=l;
- }
-
- }
- //在第i个位置插入元素
- void LinkList::InsertNode(int position,int elem)
- {
- int j;
- ListNode* p=node->next;
- for(j=1;j<position-1;j++)
- {
- p=p->next;
- if(p==NULL)
- break;
- }
- if(p==NULL &&j<(position-1))
- return ;
- // while(p)
- // {
- // j++;
- // if(j==position)
- // break;
- // p=p->next;
- // }
- ListNode* q=new ListNode;
- q->data=elem;
- q->next=p->next;
- p->next=q;
- }
- //移除节点
- void LinkList::removeNode(ListNode* p)
- {
- if(p==NULL)
- return;
- ListNode* temp=node;
- while(temp->next!=p)
- {
- temp=temp->next;
- }
- temp->next=p->next;
- delete p;
- }
- //寻找某节点
- ListNode* LinkList::findNode(int value)
- {
- ListNode* temp=node->next;
- while(temp)
- {
- if(temp->data==value)
- return temp;
- temp=temp->next;
- }
- return NULL;
-
- }
- //打印链表
- void LinkList::PrintLinkList()
- {
- ListNode* temp=node->next;
- while(temp)
- {
- cout<<temp->data<<"->";
- temp=temp->next;
- }
- std::cout<<std::endl;
- }
-
- int main()
- {
- LinkList list;
- list.CreateLinkListHead(5);
- list.PrintLinkList();
- list.InsertNode(4,9);
- list.PrintLinkList();
- ListNode* address=list.findNode(2);
- list.removeNode(address);
- list.PrintLinkList();
- return 0;
- }
栈(stack)是一种元素满足后进先出(Last in first out, LIFO)规则的线性表。
- 栈的本质是一种线性表, 但是具有其特殊的操作要求——元素后进先出。这种要求也决定了栈的操作是在表尾进行
- 栈底(bottom):栈的表头
- 栈顶(top):将栈的表尾,所以栈的所有操作都是在栈顶进行的。
- 添加元素,称为入栈(push);删除元素,称为出栈(pop)。
栈可以用顺序存储实现,也可以用链式存储实现,分别成为顺序栈和链栈。但一般使用顺序存储实现,因为栈不允许在栈中间进行插入和删除,需要准寻栈特有的规则。
- typedef struct SqStack_dynamic{
- int* base;//栈底
- int* top;//栈顶
- }SqStack_dynamic;
- typedef struct SqStack_static{
- int data[Maxsize];
- int top;//栈顶
- }SqStack_static;
- class stack_static{
- public:
- stack_static()
- {
- MaxSize=10;
- top=0;
- data= new int[MaxSize];
- }
- void push(int e);
- void pop(int &e);
- void GetTop(int &e);
- private:
- int MaxSize;
- int top;
- int *data;
- };
- void InitStack(SqStack_dynamic &stack)
- {
- stack.base= new int[Maxsize];
- stack.top=stack.base;
- }
- void push(SqStack_dynamic &stack,int e)
- {
- if((stack.top-stack.base)>=Maxsize)
- return;
- *stack.top=e;
- stack.top++;
- }
- void stack_static::push(int e)
- {
- data[top]=e;
- top++;
- }
- void pop(SqStack_dynamic &stack,int &e)
- {
- if(stack.base==stack.top)
- return;
- stack.top--;
- e=*stack.top;
- }
- void stack_static::pop(int &e)
- {
- top--;
- e=data[top];
- }
- int GetTop(SqStack_dynamic &stack)
- {
- if(stack.base!=stack.top)
- return *(stack.top-1);
- else
- return -1;
- }
- void stack_static::GetTop(int &e)
- {
- if(top!=MaxSize)
- e=data[top-1];
- else
- e=-1;
- }
- #include<iostream>
- using namespace std;
- #define Maxsize 100
- typedef struct SqStack_dynamic{
- int* base;//栈底
- int* top;//栈顶
- }SqStack_dynamic;
-
- class stack_static{
- public:
- stack_static()
- {
- MaxSize=10;
- top=0;
- data= new int[MaxSize];
- }
- void push(int e);
- void pop(int &e);
- void GetTop(int &e);
- private:
- int MaxSize;
- int top;
- int *data;
- };
- void stack_static::push(int e)
- {
- data[top]=e;
- top++;
- }
- void stack_static::pop(int &e)
- {
- top--;
- e=data[top];
- }
- void stack_static::GetTop(int &e)
- {
- if(top!=MaxSize)
- e=data[top-1];
- else
- e=-1;
- }
- void InitStack(SqStack_dynamic &stack)
- {
- stack.base= new int[Maxsize];
- stack.top=stack.base;
- }
- void push(SqStack_dynamic &stack,int e)
- {
- if((stack.top-stack.base)>=Maxsize)
- return;
- *stack.top=e;
- stack.top++;
- }
- void pop(SqStack_dynamic &stack,int &e)
- {
- if(stack.base==stack.top)
- return;
- stack.top--;
- e=*stack.top;
- }
- int GetTop(SqStack_dynamic &stack)
- {
- if(stack.base!=stack.top)
- return *(stack.top-1);
- else
- return -1;
- }
- int main()
- {
- SqStack_dynamic stack;
- InitStack(stack);
- push(stack,2);
- push(stack,5);
- push(stack,10);
- std::cout<<"------dynamic stack-----"<<std::endl;
-
- int num;
- pop(stack,num);
- std::cout<<num<<" ";
- pop(stack,num);
- std::cout<<num<<" ";
- pop(stack,num);
- std::cout<<num<<" ";
-
- stack_static stack_s;
- stack_s.push(5);
- stack_s.push(10);
- stack_s.push(20);
- std::cout<<std::endl;
- std::cout<<"------static stack-----"<<std::endl;
- int num_s;
- stack_s.pop(num_s);
- std::cout<<num_s<<" ";
- stack_s.pop(num_s);
- std::cout<<num_s<<" ";
- stack_s.pop(num_s);
- std::cout<<num_s<<" ";
-
- return 0;
- }
树是指由 n(n≥0)个结点组成的有穷集合 D 与 D 上的关系的集合 R构成的结构,通常我们用 T 表示。树需要满足以下 3 个条件:
- 当 n=0 时,该结点集合为空,该树被称为空树。
- 在任意的非空树中,有且仅有一个根结点 root。
- 当 n>1 时 ,除根结点以外的其余结点可以分为 m(m>0)个不相交的子集D1,D2,D3,…,Dm, 其中每一个这样的子集 Di(i≤m)本身又是一棵树, 称为根结点 root的子树
注意:
- 树的定义是一个递归定义,因为树是由根结点和子树构成的,而每一个子树也是一棵树。
- 从图中我们还了解,树结构在形式上最主要的特点就是分层特点和具有一定的排列顺序。
结点的度
结点拥有的直接子树数目。如图 A结点的度为3,B结点的度为2,c结点的度为1,D结点的度为3,E、F、G、H、I 以及J度都为0
树的度
树中各结点度的最大值称为该树的度。如上图,树的度为3.
分支结点
度不为 0 的结点称为分支结点或普通结点。
度为 0 的结点称为叶子结点或终端结点。由此可知叶子结点没有子结点。
结点的层次
从树的根结点开始,根结点为第 1 层,根结点的子结点为第 2 层,第 2 层结点的子结点为第 3 层……
树的深度
树中结点的最大层次数被定义为该树的深度或高度。
森林
n(n≥0)棵不相交的树的集合称为森林。
顺序存储将二叉树的每一个节点和数组的编号一一对应,根据这个编号,可以找到该结点的父结点和孩子结点
BinaryTree[0]表示该树的根结点,从根结点开始我们可以按照性质 6 去检索该树的所有结点,比如一个有 20 个结点的
二叉树, 根据性质 6 编号为 10 的结点的父结点为编号为 5 的结点,其左孩子结点为编号为20 的结点,其没有右孩子结点。由此可以看出:
- 如果二叉树是一棵完全二叉树的话,顺序结构的优点就非常明显,它能紧凑的存储二叉树,而且可以随机存取二叉树的某个结点,只需要根据性质 6 计算出该结点的元素下标即可;
- 如果是非完全二叉树,则顺序存储结构就存在空间的浪费,它会为不存在的结点分配空间,而且如果二叉树规模很大,在实际应用中,内存里也很难找出相应的连续存储空间。
二叉树的节点一般定义为:数据部分、左子树指针和右子树指针,用指针将节点串起来,其中 l 表示左孩子指针, r 表示右孩子指针,∧表示空指针
优点:
- 能够很直观地表示二叉树的逻辑结构;
- 在二叉树不是完全二叉树的时候,链式结构不会像顺序存储结构一样产生空结点,而且链式存储结构能很好地利用内存中的碎片空间,提高内存空间利用效率。
缺点:
- 链式存储结构不能随机存取某个结点,要找到某个结点,必须从根结点开始沿着指针往叶子结点遍历。
参考:
- #include<iostream>
- using namespace std;
- class BinaryTreeNode{
- public:
- //init
- BinaryTreeNode(){
- data=NULL;
- lchild=NULL;
- rchild=NULL;
- }
- BinaryTreeNode(int n){
- data=new int;
- *data=n;
- lchild=NULL;
- rchild=NULL;
- }
- private:
- int *data;//data
- BinaryTreeNode* lchild;//left child tree
- BinaryTreeNode* rchild;//right child tree
- };
- int main()
- {
- BinaryTreeNode bt(5);
- return 0;
- }
- //递归
- void preorderTraversal(BinaryTreeNode *node)
- {
- if(!node)
- return;
- std::cout<<node->data<<" ";
- preorderTraversal(node->lchild);
- preorderTraversal(node->rchild);
- }
- //迭代
- void preoder(BinaryTreeNode *root)
- {
- BinaryTreeNode *cur=root;
- std::stack<BinaryTreeNode *>s;
-
- while(cur||!s.empty())
- {
- //遍历直到最左叶子节点
- while(cur)
- {
- std::cout<<cur->data<<" ";
- s.push(cur);
- cur=cur->lchild;
- }
- //while结束时,cur=NULL
- //cur为左子节点
- cur=s.top();
- s.pop();
- cur=cur->rchild;
- }
-
- }
- void midorderTraversal(BinaryTreeNode *node)
- {
- if(!node)
- return;
- preorderTraversal(node->lchild);
- std::cout<<node->data<<" ";
- preorderTraversal(node->rchild);
- }
- void midoder(BinaryTreeNode *root)
- {
- BinaryTreeNode *cur=root;
- std::stack<BinaryTreeNode *>s;
-
- while(cur||!s.empty())
- {
- //遍历直到最左叶子节点
- while(cur)
- {
- s.push(cur);
- cur=cur->lchild;
- }
- //while结束时,cur=NULL
- //cur为左子节点
- cur=s.top();
- std::cout<<cur->data<<" ";
- s.pop();
- cur=cur->rchild;
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。