一、 概述
1. 数据结构中的基本概念
数据是程序操作的对象,用于描述客观事物。数据的特点是可以被输入计算机。数据是一个抽象的概念,将其进行分类后得到程序设计语言的类型。
数据元素是组成数据的基本单位。数据项,一个数据元素由若干数据项组成。数据对象,性质相同的数据元素的集合。
数据结构指数据对象中数据元素之间的关系。比如,数组中各个元素之间存在固定的线性关系。
数据的逻辑结构是数据元素之间的逻辑关系。即从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的。逻辑结构分为4类,集合,数据元素间同属于一个集合;线性结构,一个对一个,如线性表、栈、队列;树形结构,一个对多个,如树;网状结构,多个对多个,如图。
数据的物理结构,物理结构也称存储结构,是数据的逻辑结构在计算机存储器内的表示或映像,依赖于计算机。存储结构分为4大类,顺序、链式、索引和散列。顺序存储结构借助元素在存储器中的相对位置来表示数据元素间的逻辑关系。链式存储结构借助指示元素存储地址的指针表示数据元素间的逻辑关系。
2. 算法
算法是特定问题求解步骤的描述。在计算机中表现为指令的有限序列。算法是独立存在的一种解决问题的方法和思想。对于算法而言,语言不重要,思想重要。
算法和数据结构的区别,数据结构只是静态的描述了数据元素之间的关系。高效的程序需要在数据结构的基础上设计和选择算法。程序等于数据结构加上算法。
算法是为了解决实际问题而设计的。数据结构是算法需要处理的问题载体。数据结构与算法相辅相成。
算法的特性,输入,算法具有0个或多个输入;输出,算法至少有1个或多个输出;有穷性,算法在有限的步骤之后会自动结束而不会无限循环;确定性,算法中的每一步都有确定的含义,不会出现二义性;可行性,算法的每一步都是可行的。
算法效率的度量
事后统计法,比较不同算法对同一组输入数据的运行处理时间。缺陷,为了获得不同算法的运行时间必须编写相应程序,运行时间严重依赖硬件以及运行时的环境因素;算法的测试数据的选取相当困难。事后统计法虽然直观,但实施困难且缺陷多。
事前分析估算,依据统计的方法对算法效率进行估算。影响算法效率的主要因素,算法采用的策略和方法;问题的输入规模;编译器所产生的代码;计算机执行速度。
大O表示法,算法效率严重依赖于操作operation数量。在判断时首先关注操作数量的最高次项。操作数量的估算可以作为时间复杂度的估算。比如,O(5) = O(10),O(2n+1) = O(2n)= O(n),O(n2+n+1) =O(n2),O(3n3+1) =O(3n3) = O(n3)。
执行次数函数 | 阶 | 非正式术语 |
12 | O(1) | 常数阶 |
2n+3 | O(n) | 线性阶 |
3n2+2n+1 | O(n2) | 平方阶 |
5log2n+20 | O(logn) | 对数阶 |
2n+3nlog2n+19 | O(nlogn) | nlogn阶 |
6n3+2n2+3n+4 | O(n3) | 立方阶 |
2n | O(2n) | 指数阶 |
O(1)< O(logn)< O(nlogn)< O(nlogn)<O(n2)< O(n3)< O(2n)< O(n!)< O(nn)
算法的空间复杂度
算法的空间复杂度通过计算算法的存储空间实现。S(n)= O(f(n))。n为问题规模,f(n)为在问题规模为n时所占存储空间的函数。大O表示法同样适用于算法的空间复杂度。当算法执行时所需要的空间是常数时,空间复杂度为O(1)。
空间与时间的策略,多数情况下,算法执行时所用的时间更令人关注。如果有必要,可以通过增加空间复杂度来降低时间复杂度。同理,也可以通过增加时间复杂度来降低空间复杂度。
案例,求出1000个1-1000的随机数中出现次数最多的数字。
#include "iostream"
using namespace std;
#include "map"
void initArray(int arr[], int size)
{
for (int i= 0; i < size; i++)
{
inttmp = rand()%1000;
arr[i]= tmp;
}
}
void showArray(int arr[], int size)
{
for (int i= 0; i < size; i++)
{
cout<< arr[i] << " ";
if(i % 10 == 9)
{
cout<< endl;
}
}
}
void bubbleSort(int arr[], int size)
{
for (int i= 0; i < size - 1; i++)
{
for(int j = 0; j < size - 1 - i; j++)
{
if(arr[j] > arr[j + 1])
{
inttmp = arr[j];
arr[j] = arr[j + 1];
arr[j+ 1] = tmp;
}
}
}
}
map<int,int> getMap(int arr[], int size)
{
map<int,int> m1;
for (int i= 0; i < size; i++)
{
m1.insert(pair<int,int> (arr[i], 0));
}
return m1;
}
void printMap(map<int,int> m)
{
int i = 0;
for(map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
if(i % 9 == 0)
{
cout<< endl;
}
cout<< it->first << ":" << it->second <<" ";
i++;
}
cout<< endl;
}
void coutArray(int arr[],int size,map<int, int> *m)
{
for (int i =0; i < size; i++)
{
for(map<int, int>::iterator it = (*m).begin(); it != (*m).end(); it++)
{
if(arr[i] == it->first)
{
it->second++;
break;
}
}
}
}
map<int,int> findMaxInMap(map<int, int> m)
{
map<int,int>::iterator it = m.begin();
int maxKey= it->first;
int max =it->second;
for(map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
if(max < it->second)
{
maxKey= it->first;
max= it->second;
}
}
map<int,int> res;
res.insert(pair< int, int > (maxKey, max));
return res;
}
//空间换时间的算法
map<int,int> roomCTime(int arr[], int size)
{
map<int,int> res;
inttmp[1000] = { 0 };
int max =0;
for (int i= 0; i < size; i++)
{
intindex = arr[i] - 1;
tmp[index]++;
}
for (int i= 0; i < 1000; i++)
{
if(max < tmp[i])
{
max = tmp[i];
}
}
for (int i= 0; i < 1000; i++)
{
if(max == tmp[i])
{
res.insert(pair<int,int>(i + 1, max));
break;
}
}
return res;
}
void test1()
{
intarr[1000] = { 0 };
initArray(arr,1000);
showArray(arr,1000);
bubbleSort(arr,1000);
cout<< "冒泡排序后:" << endl<< endl;
showArray(arr,1000);
map<int,int> m1;
m1 =getMap(arr, 1000);
printMap(m1);
coutArray(arr,1000, &m1);
cout<< "数数组后:" << endl;
printMap(m1);
map<int,int> res;
res =findMaxInMap(m1);
map<int,int>::iterator it = res.begin();
cout<< "出现最多的数为:" << it->first<< ",出现的次数为:" <<it->second << endl;
}
void test2()
{
intarr[1000] = { 0 };
initArray(arr,1000);
showArray(arr,1000);
bubbleSort(arr,1000);
cout<< "冒泡排序后:" << endl<< endl;
showArray(arr,1000);
cout<< "数数组后:" << endl;
map<int,int> res = roomCTime(arr, 1000);
map<int,int>::iterator it = res.begin();
cout<< "出现最多的数为:" << it->first<< ",出现的次数为:" <<it->second << endl;
}
void main()
{
test2();
system("pause");
}
二、 线性表
1. 基本概念
线性表是0个或多个数据元素的集合。线性表中的数据元素之间是有顺序的。线性表中的数据元素个数是有限的。线性表中的数据元素的类型必须相同。数学上,线性表是具有相同类型的n个数据元素的有限序列。a0为线性表的第一个元素,只有一个后继。an为线性表的最后一个元素,只有一个前驱。除a0和an外的其他元素ai,既有前驱,也有后继。线性表能够逐项访问和顺序存取。
2. 线性表的顺序存储
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。
案例
编写头文件SeqList.h
#ifndef __MY_SEQLIST_H__
#define __MY_SEQLIST_H__
typedef void SeqList;
typedef void SeqListNode;
SeqList* SeqList_Create(int capacity);
void SeqList_Destroy(SeqList* list);
void SeqList_Clear(SeqList* list);
int SeqList_Length(SeqList* list);
int SeqList_Capacity(SeqList* list);
int SeqList_Insert(SeqList* list, SeqListNode* node, intpos);
SeqListNode* SeqList_Get(SeqList* list, int pos);
SeqListNode* SeqList_Delete(SeqList* list, int pos);
#endif //__MY_SEQLIST_H__
编写实现文件SeqList.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "seqlist.h"
typedef struct _tag_SeqList
{
int length;
intcapacity;
unsignedint *node;
}TSeqList;
SeqList* SeqList_Create(int capacity)
{
int ret =0;
TSeqList*tmp = NULL;
tmp =(TSeqList*)malloc(sizeof(TSeqList));
if (tmp ==NULL)
{
ret= -1;
printf("funcSeqList_Create err:%d\n", ret);
returnNULL;
}
memset(tmp,0, sizeof(TSeqList));
tmp->node= (unsigned int*)malloc(sizeof(unsigned int*)* capacity);
if(tmp->node == NULL)
{
ret= -1;
printf("funcSeqList_Create err: malloc err %d\n", ret);
returnNULL;
}
tmp->capacity= capacity;
tmp->length= 0;
return tmp;
}
void SeqList_Destroy(SeqList* list)
{
TSeqList*tlist = NULL;
if (list ==NULL)
{
return;
}
tlist =(TSeqList*)list;
if(tlist->node != NULL)
{
free(tlist->node);
}
free(tlist);
return ;
}
void SeqList_Clear(SeqList* list)
{
TSeqList*tlist = NULL;
if (list ==NULL)
{
return;
}
tlist =(TSeqList*)list;
tlist->length= 0;
return ;
}
int SeqList_Length(SeqList* list)
{
TSeqList*tlist = NULL;
if (list ==NULL)
{
return-1;
}
tlist =(TSeqList*)list;
returntlist->length;
}
int SeqList_Capacity(SeqList* list)
{
TSeqList*tlist = NULL;
if (list ==NULL)
{
return-1;
}
tlist =(TSeqList*)list;
returntlist->capacity;
}
int SeqList_Insert(SeqList* list, SeqListNode* node, intpos)
{
TSeqList*tlist = NULL;
int ret =0;
if (list ==NULL || node == NULL || pos < 0)
{
ret= -1;
printf("funcSeqList_Insert:%d\n", ret);
return-1;
}
tlist =(TSeqList*)list;
if(tlist->length >= tlist->capacity)
{
ret= -2;
printf("funcSeqList_Insert tlist->length >= tlist->capacity:%d\n", ret);
return-1;
}
if (pos> tlist->length && pos < tlist->capacity)
{
pos= tlist->length;
}
for (int i= tlist->length; i > pos; i--)
{
tlist->node[i]= tlist->node[i - 1];
}
tlist->node[pos]= (unsigned int)node;
tlist->length++;
return 0;
}
SeqListNode* SeqList_Get(SeqList* list, int pos)
{
TSeqList*tlist = NULL;
int ret =0;
if (list ==NULL || pos < 0)
{
ret= -1;
printf("funcSeqList_Get:%d\n", ret);
returnNULL;
}
tlist =(TSeqList*)list;
returntlist->node[pos];
}
SeqListNode* SeqList_Delete(SeqList* list, int pos)
{
TSeqList*tlist = NULL;
SeqListNode*tmp = NULL;
int ret =0;
if (list ==NULL || pos < 0)
{
ret= -1;
printf("funcSeqList_Delete:%d\n", ret);
returnNULL;
}
tlist =(TSeqList*)list;
if (pos> tlist->length)
{
ret= -2;
printf("funcSeqList_Delete pos > tlist->length:%d\n", ret);
returnNULL;
}
tmp =(SeqListNode*)tlist->node[pos];
for (int i= pos; i < tlist->length; i++)
{
tlist->node[i]= tlist->node[i + 1];
}
tlist->length--;
return tmp;
}
测试
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include "seqlist.h"
#include <string.h>
typedef struct Teacher
{
int age;
charname[50];
}Teacher;
void test1()
{
int ret =0;
SeqList*list = NULL;
list =SeqList_Create(5);
if (list ==NULL)
{
printf("funcSeqList_Create err:%d\n", ret);
return;
}
Teachert1,t2,t3,t4,t5;
t1.age =22;
strcpy(t1.name,"");
t2.age =23;
strcpy(t2.name,"");
t3.age =24;
strcpy(t3.name,"");
t4.age =25;
strcpy(t4.name,"");
t5.age =26;
strcpy(t5.name,"");
ret =SeqList_Insert(list, (SeqListNode*)&t1, 0);
ret =SeqList_Insert(list, (SeqListNode*)&t2, 0);
ret =SeqList_Insert(list, (SeqListNode*)&t3, 0);
ret =SeqList_Insert(list, (SeqListNode*)&t4, 0);
ret =SeqList_Insert(list, (SeqListNode*)&t5, 0);
for (int i= 0; i < SeqList_Length(list); i++)
{
Teacher*tmp = (Teacher*)SeqList_Get(list, i);
if(tmp == NULL)
{
return;
}
printf("age:%d ", tmp->age);
}
printf("\n");
while(SeqList_Length(list) > 0)
{
SeqList_Delete(list,0);
for(int i = 0; i < SeqList_Length(list); i++)
{
Teacher*tmp = (Teacher*)SeqList_Get(list, i);
if(tmp == NULL)
{
return;
}
printf("age:%d ", tmp->age);
}
printf("\n");
}
}
void main()
{
test1();
system("pause");
}
线性表顺序存储的优点和缺点
优点,无需为线性表中的逻辑关系增加额外的空间,可以快速的获取表中合法位置的元素。
缺点,插入和删除操作需要移动大量元素,当线性表长度变化较大时难以确定存储空间的容量。
3. 线性表的链式存储
链式存储,为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了存储本身的信息外,还需要存储指示其直接后继的信息。
单链表,n个结点链结成一个链表,即为线性表的链式存储结构。因为此链表的每个结点中只包含一个指针域,所以叫做单链表。单链表正是通过每个结点的指针域将线性表的数据元素按其逻辑次序链接在一起。
表头结点,链表中的第一个结点,包含指向第一个数据元素的指针以及链表自身的一些信息。数据结点,链表中代表数据元素的结点,包含指向下一个数据元素的指针和数据元素的信息。尾结点,链表中的最后一个数据结点,其下一元素指针为空,表示无后继。
优点,无需一次性定制链表的容量,插入和删除操作元素无需移动数据元素。
缺点,数据元素必须保存后继元素的位置信息,获取指定数据的元素操作需要顺序访问之前的元素。
案例
编写LinkList.h文件
#ifndef _MYLINKLIST_H_
#define _MYLINKLIST_H_
typedef void LinkList;
typedef struct _tag_LinkListNode
{
struct_tag_LinkListNode* next;
}LinkListNode;
LinkList* LinkList_Create();
void LinkList_Destroy(LinkList* list);
void LinkList_Clear(LinkList* list);
int LinkList_Length(LinkList* list);
int LinkList_Insert(LinkList* list, LinkListNode* node,int pos);
LinkListNode* LinkList_Get(LinkList* list, int pos);
LinkListNode* LinkList_Delete(LinkList* list, int pos);
#endif
编写实现文件LinkList.c
#include "linklist.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
typedef struct _tag_LinkList
{
LinkListNodeheader;
int length;
}TLinkList;
LinkList* LinkList_Create()
{
TLinkList*ret = NULL;
ret =(TLinkList*)malloc(sizeof(TLinkList));
memset(ret,0, sizeof(TLinkList));
ret->length= 0;
ret->header.next= NULL;
return ret;
}
void LinkList_Destroy(LinkList* list)
{
if (list !=NULL)
{
free(list);
list= NULL;
}
return ;
}
void LinkList_Clear(LinkList* list)
{
TLinkList*tlist = NULL;
if (list ==NULL)
{
return;
}
tlist =(TLinkList*)list;
tlist->length= 0;
tlist->header.next= NULL;
return ;
}
int LinkList_Length(LinkList* list)
{
TLinkList*tlist = NULL;
if (list ==NULL)
{
return;
}
tlist =(TLinkList*)list;
returntlist->length;
}
int LinkList_Insert(LinkList* list, LinkListNode* node,int pos)
{
int ret =0;
TLinkList*tlist = NULL;
LinkListNode*current = NULL;
if (list ==NULL || node == NULL || pos < 0)
{
ret= -1;
printf("funcLinkList_Insert err:%d\n", ret);
returnret;
}
tlist =(TLinkList*)list;
current =&(tlist->header);
for (int i= 0; i < pos && current->next != NULL; i++)
{
current= current->next;
}
node->next= current->next;
current->next= node;
tlist->length++;
return ret;
}
LinkListNode* LinkList_Get(LinkList* list, int pos)
{
int ret =0;
TLinkList*tlist = NULL;
LinkListNode*current = NULL;
if (list ==NULL || pos < 0)
{
ret= -1;
printf("funcLinkList_Insert err:%d\n", ret);
returnNULL;
}
tlist =(TLinkList*)list;
current =&(tlist->header);
current =current->next;
for (int i= 0; i < pos && current->next != NULL; i++)
{
current= current->next;
}
returncurrent;
}
LinkListNode* LinkList_Delete(LinkList* list, int pos)
{
TLinkList*tlist = NULL;
LinkListNode*current = NULL;
LinkListNode*ret = NULL;
if (list ==NULL || pos < 0)
{
ret= -1;
printf("funcLinkList_Insert list == NULL || pos < 0 err:%d\n", ret);
returnNULL;
}
tlist =(TLinkList*)list;
if (pos>= tlist->length)
{
ret= -2;
printf("funcLinkList_Insert pos >= tlist->length err:%d\n", ret);
returnNULL;
}
current =&(tlist->header);
for (int i= 0; i < pos && current->next != NULL; i++)
{
current= current->next;
}
ret =current->next;
current->next= ret->next;
tlist->length--;
return ret;
}
测试
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "linklist.h"
typedef struct _Teacher
{
LinkListNodenode;
int age;
charname[64];
}Teacher;
void test1()
{
Teacher t1,t2, t3, t4, t5;
t1.age =10;
t2.age =13;
t3.age =23;
t4.age =25;
t5.age =26;
LinkList*list = NULL;
int length= 0, ret = 0;
list =LinkList_Create();
if (list ==NULL)
{
return;
}
length =LinkList_Length(list);
printf("length:%d\n",length);
ret =LinkList_Insert(list, (LinkListNode*)&t1, 0);
ret =LinkList_Insert(list, (LinkListNode*)&t2, 0);
ret =LinkList_Insert(list, (LinkListNode*)&t3, 0);
ret =LinkList_Insert(list, (LinkListNode*)&t4, 0);
ret =LinkList_Insert(list, (LinkListNode*)&t5, 0);
for (int i= 0; i < LinkList_Length(list); i++)
{
Teacher*tmp = (Teacher *)LinkList_Get(list, i);
if(tmp == NULL)
{
return;
}
printf("tmp->age:%d", tmp->age);
}
printf("\n");
while(LinkList_Length(list)>0)
{
Teacher*tmp = (Teacher *)LinkList_Delete(list, 1);
if(tmp == NULL)
{
return;
}
printf("tmp->age:%d", tmp->age);
}
LinkList_Destroy(list);
}
void main()
{
test1();
system("pause");
}
4. 循环链表
循环链表,将单链表中最后一个数据元素的next指针指向第一个元素。
优点,功能更强。循环链表只是在单链表的基础上做了一个加强。循环链表可以完全取代单链表的使用。循环链表的next和current操作可以高效的遍历链表中的所有元素。
缺点,代码复杂度提高了。
案例
编写clelist.h文件
#ifndef _CIRCLELIST_H_
#define _CIRCLELIST_H_
typedef void CircleList;
/*
typedef struct _tag_CircleListNode CircleListNode;
struct _tag_CircleListNode
{
CircleListNode*next;
};
*/
typedef struct _tag_CircleListNode
{
struct_tag_CircleListNode * next;
}CircleListNode;
CircleList* CircleList_Create();
void List_Destroy(CircleList* list);
void CircleList_Clear(CircleList* list);
int CircleList_Length(CircleList* list);
int CircleList_Insert(CircleList* list, CircleListNode*node, int pos);
CircleListNode* CircleList_Get(CircleList* list, intpos);
CircleListNode* CircleList_Delete(CircleList* list, intpos);
//add
CircleListNode* CircleList_DeleteNode(CircleList* list,CircleListNode* node);
CircleListNode* CircleList_Reset(CircleList* list);
CircleListNode* CircleList_Current(CircleList* list);
CircleListNode* CircleList_Next(CircleList* list);
#endif
编写circlelist.c文件
#include <stdio.h>
#include <malloc.h>
#include "circlelist.h"
typedef struct _tag_CircleList
{
CircleListNodeheader;
CircleListNode*slider;
int length;
} TCircleList;
CircleList* CircleList_Create() // O(1)
{
TCircleList*ret = (TCircleList*)malloc(sizeof(TCircleList));
if (ret ==NULL)
{
returnNULL;
}
ret->length= 0;
ret->header.next= NULL;
ret->slider= NULL;
return ret;
}
void CircleList_Destroy(CircleList* list) // O(1)
{
if (list ==NULL)
{
return;
}
free(list);
}
void CircleList_Clear(CircleList* list) // O(1)
{
TCircleList*sList = (TCircleList*)list;
if (sList== NULL)
{
return;
}
sList->length= 0;
sList->header.next= NULL;
sList->slider= NULL;
}
int CircleList_Length(CircleList* list) // O(1)
{
TCircleList*sList = (TCircleList*)list;
int ret =-1;
if (list ==NULL)
{
returnret;
}
ret =sList->length;
return ret;
}
int CircleList_Insert(CircleList* list, CircleListNode*node, int pos) // O(n)
{
int ret =0, i=0;
TCircleList*sList = (TCircleList*)list;
if (list ==NULL || node== NULL || pos<0)
{
return-1;
}
//if( ret )
{
CircleListNode*current = (CircleListNode*)sList;
for(i=0;(i<pos) && (current->next != NULL); i++)
{
current= current->next;
}
//current->next0号节点的地址
node->next= current->next; //1
current->next= node; //2
//若第一次插入节点
if(sList->length == 0 )
{
sList->slider= node;
}
sList->length++;
//若头插法 current仍然指向头部
//(原因是:跳0步,没有跳走)
if(current == (CircleListNode*)sList )
{
//获取最后一个元素
CircleListNode*last = CircleList_Get(sList, sList->length - 1);
last->next= current->next; //3
}
}
return ret;
}
CircleListNode* CircleList_Get(CircleList* list, int pos)// O(n)
{
TCircleList*sList = (TCircleList*)list;
CircleListNode*ret = NULL;
int i = 0;
if(list==NULL || pos<0)
{
returnNULL;
}
//if((sList != NULL) && (pos >= 0) && (sList->length > 0) )
{
CircleListNode*current = (CircleListNode*)sList;
for(i=0;i<pos; i++)
{
current= current->next;
}
ret= current->next;
}
return ret;
}
CircleListNode* CircleList_Delete(CircleList* list, intpos) // O(n)
{
TCircleList*sList = (TCircleList*)list;
CircleListNode*ret = NULL;
int i = 0;
if( (sList!= NULL) && (pos >= 0) && (sList->length > 0) )
{
CircleListNode*current = (CircleListNode*)sList;
CircleListNode*last = NULL;
for(i=0;i<pos; i++)
{
current= current->next;
}
//若删除第一个元素(头结点)
if(current == (CircleListNode*)sList )
{
last= (CircleListNode*)CircleList_Get(sList, sList->length - 1);
}
//求要删除的元素
ret= current->next;
current->next= ret->next;
sList->length--;
//判断链表是否为空
if(last != NULL )
{
sList->header.next= ret->next;
last->next= ret->next;
}
//若删除的元素为游标所指的元素
if(sList->slider == ret )
{
sList->slider= ret->next;
}
//若删除元素后,链表长度为0
if(sList->length == 0 )
{
sList->header.next= NULL;
sList->slider= NULL;
}
}
return ret;
}
CircleListNode* CircleList_DeleteNode(CircleList* list,CircleListNode* node) // O(n)
{
TCircleList*sList = (TCircleList*)list;
CircleListNode*ret = NULL;
int i = 0;
if( sList!= NULL )
{
CircleListNode*current = (CircleListNode*)sList;
//查找node在循环链表中的位置i
for(i=0;i<sList->length; i++)
{
if(current->next == node )
{
ret= current->next;
break;
}
current= current->next;
}
//如果ret找到,根据i去删除
if(ret != NULL )
{
CircleList_Delete(sList,i);
}
}
return ret;
}
CircleListNode* CircleList_Reset(CircleList* list) //O(1)
{
TCircleList*sList = (TCircleList*)list;
CircleListNode*ret = NULL;
if( sList!= NULL )
{
sList->slider= sList->header.next;
ret= sList->slider;
}
return ret;
}
CircleListNode* CircleList_Current(CircleList* list) //O(1)
{
TCircleList*sList = (TCircleList*)list;
CircleListNode*ret = NULL;
if( sList!= NULL )
{
ret= sList->slider;
}
return ret;
}
//把当前位置返回,并且游标下移
CircleListNode* CircleList_Next(CircleList* list) // O(1)
{
TCircleList*sList = (TCircleList*)list;
CircleListNode*ret = NULL;
if( (sList!= NULL) && (sList->slider != NULL) )
{
ret= sList->slider;
sList->slider= ret->next;
}
return ret;
}
测试
#include <stdio.h>
#include <stdlib.h>
#include "CircleList.h"
struct Value
{
CircleListNodeheader;
int v;
};
void main()
{
int i = 0;
CircleList*list = CircleList_Create();
structValue v1;
structValue v2;
structValue v3;
structValue v4;
structValue v5;
structValue v6;
structValue v7;
structValue v8;
v1.v = 1;
v2.v = 2;
v3.v = 3;
v4.v = 4;
v5.v = 5;
v6.v = 6;
v7.v = 7;
v8.v = 8;
CircleList_Insert(list,(CircleListNode*)&v1, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v2, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v3, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v4, CircleList_Length(list));
//CircleList_Insert(list,(CircleListNode*)&v5, 5);
//CircleList_Delete(list,0);
for(i=0;i<2*CircleList_Length(list); i++)
{
structValue* pv = (struct Value*)CircleList_Get(list, i);
printf("%d\n",pv->v);
}
printf("\n");
while(CircleList_Length(list) > 0 )
{
structValue* pv = (struct Value*)CircleList_Delete(list, 0);
printf("%d\n",pv->v);
}
printf("\n");
//
// CircleList_Insert(list,(CircleListNode*)&v1, CircleList_Length(list));
// CircleList_Insert(list,(CircleListNode*)&v2, CircleList_Length(list));
// CircleList_Insert(list,(CircleListNode*)&v3, CircleList_Length(list));
// CircleList_Insert(list,(CircleListNode*)&v4, CircleList_Length(list));
// CircleList_Insert(list,(CircleListNode*)&v5, CircleList_Length(list));
// CircleList_Insert(list,(CircleListNode*)&v6, CircleList_Length(list));
// CircleList_Insert(list,(CircleListNode*)&v7, CircleList_Length(list));
// CircleList_Insert(list,(CircleListNode*)&v8, CircleList_Length(list));
//
// for(i=0;i<CircleList_Length(list); i++)
// {
// structValue* pv = (struct Value*)CircleList_Next(list);
//
// printf("%d\n",pv->v);
// }
printf("\n");
//重置游标
CircleList_Reset(list);
while(CircleList_Length(list) > 0 )
{
structValue* pv = NULL;
for(i=1;i<3; i++)
{
CircleList_Next(list);
}
pv= (struct Value*)CircleList_Current(list);
printf("%d\n",pv->v);
CircleList_DeleteNode(list,(CircleListNode*)pv);
}
CircleList_Destroy(list);
system("pause");
return ;
}
解决约瑟夫问题
#include <stdio.h>
#include <stdlib.h>
#include "circlelist.h"
struct Value
{
CircleListNodeheader;
int v;
};
void main11()
{
int i = 0;
CircleList*list = CircleList_Create();
structValue v1, v2, v3, v4, v5, v6, v7, v8;
v1.v = 1; v2.v = 2; v3.v= 3; v4.v = 4;
v5.v = 5; v6.v = 6; v7.v= 7; v8.v = 8;
CircleList_Insert(list,(CircleListNode*)&v1, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v2, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v3, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v4, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v5, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v6, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v7, CircleList_Length(list));
CircleList_Insert(list,(CircleListNode*)&v8, CircleList_Length(list));
for(i=0;i<CircleList_Length(list); i++)
{
//获取游标所指元素,然后游标下移
structValue* pv = (struct Value*)CircleList_Next(list);
printf("%d\n",pv->v);
}
printf("\n");
//重置游标
CircleList_Reset(list);
while(CircleList_Length(list) > 0 )
{
structValue* pv = NULL;
for(i=1;i<3; i++)
{
CircleList_Next(list);
}
pv= (struct Value*)CircleList_Current(list);
printf("%d\n",pv->v);
CircleList_DeleteNode(list,(CircleListNode*)pv);
}
CircleList_Destroy(list);
system("pause");
return ;
}
5. 双向链表
在单链表的结点中增加一个指向其前驱的pre指针。
优点,双向链表在单链表的基础上增加了指向前驱的指针,功能上双向链表可以完全取代单链表的使用。双向链表的next、pre和current操作可以高效的遍历链表中的所有元素。
缺点,代码复杂。
案例
编写dlinklist.h文件
#ifndef _MY_DLINKLIST_H_
#define _MY_DLINKLIST_H_
typedef void DLinkList;
typedef struct _tag_DLinkListNode
{
struct_tag_DLinkListNode* next;
struct_tag_DLinkListNode* pre;
}DLinkListNode;
DLinkList* DLinkList_Create();
void DLinkList_Destroy(DLinkList* list);
void DLinkList_Clear(DLinkList* list);
int DLinkList_Length(DLinkList* list);
int DLinkList_Insert(DLinkList* list, DLinkListNode*node, int pos);
DLinkListNode* DLinkList_Get(DLinkList* list, int pos);
DLinkListNode* DLinkList_Delete(DLinkList* list, intpos);
DLinkListNode* DLinkList_DeleteNode(DLinkList* list,DLinkListNode* node);
DLinkListNode* DLinkList_Reset(DLinkList* list);
DLinkListNode* DLinkList_Current(DLinkList* list);
DLinkListNode* DLinkList_Next(DLinkList* list);
DLinkListNode* DLinkList_Pre(DLinkList* list);
#endif
编写dlinklist.c文件
#include "stdio.h"
#include "malloc.h"
#include "dlinklist.h"
typedef struct _tag_DLinkList
{
DLinkListNodeheader;
DLinkListNode*slider;
int length;
}TDLinkList;
DLinkList* DLinkList_Create()
{
TDLinkList*ret = (TDLinkList*)malloc(sizeof(TDLinkList));
if (ret !=NULL)
{
ret->length= 0;
ret->header.pre= NULL;
ret->header.next= NULL;
ret->slider= NULL;
}
return ret;
}
void DLinkList_Destroy(DLinkList* list)
{
if (list !=NULL)
{
free(list);
}
return ;
}
void DLinkList_Clear(DLinkList* list)
{
TDLinkList*tlist = NULL;
if (list !=NULL)
{
tlist= (TDLinkList*)list;
tlist->length= 0;
tlist->header.next= NULL;
tlist->header.pre= NULL;
tlist->slider= NULL;
}
return;
}
int DLinkList_Length(DLinkList* list)
{
TDLinkList*tlist = (TDLinkList*)list;
int ret =-1;
if (tlist!= NULL)
{
ret= tlist->length;
}
return ret;
}
int DLinkList_Insert(DLinkList* list, DLinkListNode*node, int pos)
{
TDLinkList*tlist = (TDLinkList*)list;
int ret =0;
if (list ==NULL || node == NULL || pos < 0)
{
ret= -1;
returnret;
}
DLinkListNode*current = (DLinkListNode*)tlist;
DLinkListNode*next = NULL;
for (int i= 0; i < pos&¤t->next != NULL; i++)
{
current= current->next;
}
next =current->next;
current->next= node;
node->next= next;
if (next !=NULL)
{
next->pre= node;
}
node->pre= current;
if (tlist->length== 0)
{
tlist->slider= node;
}
if (current== (DLinkListNode *)tlist)
{
node->pre= NULL;
}
tlist->length++;
return ret;
}
DLinkListNode* DLinkList_Get(DLinkList* list, int pos)
{
TDLinkList*tlist = (TDLinkList*)list;
DLinkListNode*ret = NULL;
if (list ==NULL || pos < 0 || pos >= tlist->length)
{
returnNULL;
}
DLinkListNode*current = (DLinkListNode*)tlist;
for (int i= 0; i < pos&¤t->next != NULL; i++)
{
current= current->next;
}
ret =current->next;
return ret;
}
DLinkListNode* DLinkList_Delete(DLinkList* list, int pos)
{
TDLinkList*tlist = (TDLinkList*)list;
DLinkListNode*ret = NULL;
if (list ==NULL || pos < 0 || pos >= tlist->length)
{
returnNULL;
}
DLinkListNode*current = (DLinkListNode*)tlist;
DLinkListNode*next = NULL;
for (int i= 0; i < pos&¤t->next != NULL; i++)
{
current= current->next;
}
ret =current->next;
next =ret->next;
current->next= next;
if (next !=NULL)
{
next->pre= current;
if(current == (DLinkListNode*)tlist)
{
next->pre= NULL;
}
}
if(tlist->slider == ret)
{
tlist->slider= next;
}
tlist->length--;
return ret;
}
DLinkListNode* DLinkList_DeleteNode(DLinkList* list,DLinkListNode* node)
{
TDLinkList*tlist = (TDLinkList*)list;
DLinkListNode*ret = NULL;
int index =0;
if (tlist!= NULL)
{
DLinkListNode*current = (DLinkListNode*)tlist;
for(int i = 0; i < tlist->length; i++)
{
if(current->next == node)
{
ret= current->next;
index= i;
break;
}
current= current->next;
}
if(ret != NULL)
{
DLinkList_Delete(tlist,index);
}
}
return ret;
}
DLinkListNode* DLinkList_Reset(DLinkList* list)
{
TDLinkList*tlist = (TDLinkList*)list;
DLinkListNode*ret = NULL;
if (tlist!= NULL)
{
tlist->slider= tlist->header.next;
ret= tlist->slider;
}
return ret;
}
DLinkListNode* DLinkList_Current(DLinkList* list)
{
TDLinkList*tlist = (TDLinkList*)list;
DLinkListNode*ret = NULL;
if (tlist!= NULL)
{
ret= tlist->slider;
}
return ret;
}
DLinkListNode* DLinkList_Next(DLinkList* list)
{
TDLinkList*tlist = (TDLinkList*)list;
DLinkListNode*ret = NULL;
if (tlist!= NULL && tlist->slider != NULL)
{
ret= tlist->slider;
tlist->slider= ret->next;
}
return ret;
}
DLinkListNode* DLinkList_Pre(DLinkList* list)
{
TDLinkList*tlist = (TDLinkList*)list;
DLinkListNode*ret = NULL;
if (tlist!= NULL && tlist->slider != NULL)
{
ret= tlist->slider;
tlist->slider= ret->pre;
}
return ret;
}
测试
#include "stdio.h"
#include "stdlib.h"
#include "dlinklist.h"
struct value
{
DLinkListNodenode;
int v;
};
void main()
{
DLinkList*list = DLinkList_Create();
structvalue* pv = NULL;
structvalue v1, v2, v3, v4, v5;
v1.v = 1;
v2.v = 2;
v3.v = 3;
v4.v = 4;
v5.v = 5;
DLinkList_Insert(list,(DLinkListNode*)&v1, DLinkList_Length(list));
DLinkList_Insert(list,(DLinkListNode*)&v2, DLinkList_Length(list));
DLinkList_Insert(list,(DLinkListNode*)&v3, DLinkList_Length(list));
DLinkList_Insert(list,(DLinkListNode*)&v4, DLinkList_Length(list));
DLinkList_Insert(list,(DLinkListNode*)&v5, DLinkList_Length(list));
for (int i= 0; i < DLinkList_Length(list); i++)
{
pv= (struct value*)DLinkList_Get(list, i);
printf("%d\n",pv->v);
}
DLinkList_Delete(list,DLinkList_Length(list) - 1);
DLinkList_Delete(list,0);
for (int i= 0; i < DLinkList_Length(list); i++)
{
pv= (struct value*)DLinkList_Next(list);
printf("%d\n",pv->v);
}
DLinkList_Reset(list);
DLinkList_Next(list);
pv =(struct value*)DLinkList_Current(list);
printf("%d\n",pv->v);
DLinkList_DeleteNode(list,(DLinkListNode*)pv);
pv =(struct value*)DLinkList_Current(list);
printf("%d\n",pv->v);
DLinkList_Pre(list);
pv =(struct value*)DLinkList_Current(list);
printf("%d\n",pv->v);
printf("length:%d\n",DLinkList_Length(list));
DLinkList_Destroy(list);
system("pause");
}
三、 栈
1. 基本概念
栈是一种特殊的线性表。栈仅能在线性表的一端进行操作。栈顶top,允许操作的一端;栈底bottom,不允许操作的一端。
栈的特殊之处在与限制了这个线性表的插入和删除位置。它始终只在栈顶进行。这也就使得,栈底是固定的,最先进栈的只能在栈底。
栈的插入操作,叫做进栈,也称压栈、入栈。栈的删除操作,叫做出栈,也叫做弹栈。
2. 栈的顺序存储
由于栈的顺序存储实际上是线性表的顺序存储,只是在压栈和入栈时从线性表的尾部进行插入和删除操作。
利用上述线性表的顺序存储的案例。
编写seqstack.h文件
#ifndef __MY_SEQSTACK_H__
#define __MY_SEQSTACK_H__
typedef void SeqStack;
SeqStack* SeqStack_Create(int capacity);
void SeqStack_Destroy(SeqStack* stack);
void SeqStack_Clear(SeqStack* stack);
int SeqStack_Size(SeqStack* stack);
int SeqStack_Capacity(SeqStack* stack);
int SeqStack_Push(SeqStack* stack, void* item);
void* SeqStack_Pop(SeqStack* stack);
void* SeqStack_Top(SeqStack* stack);
#endif
编写seqstack.c文件
#include "stdio.h"
#include "stdlib.h"
#include "seqstack.h"
#include "seqlist.h"
SeqStack* SeqStack_Create(int capacity)
{
returnSeqList_Create(capacity);
}
void SeqStack_Destroy(SeqStack* stack)
{
SeqList_Destroy(stack);
return;
}
void SeqStack_Clear(SeqStack* stack)
{
SeqList_Clear(stack);
return;
}
int SeqStack_Size(SeqStack* stack)
{
returnSeqList_Length(stack);
}
int SeqStack_Capacity(SeqStack* stack)
{
returnSeqList_Capacity(stack);
}
int SeqStack_Push(SeqStack* stack, void* item)
{
if(SeqList_Length(stack) >= SeqList_Capacity(stack))
{
printf("栈已满\n");
return-1;
}
returnSeqList_Insert(stack, item, SeqList_Length(stack));
}
void* SeqStack_Pop(SeqStack* stack)
{
SeqListNode*ret = NULL;
if(SeqList_Length(stack) < 0)
{
returnret;
}
ret =SeqList_Delete(stack, SeqList_Length(stack)-1);
return ret;
}
void* SeqStack_Top(SeqStack* stack)
{
returnSeqList_Get(stack, SeqList_Length(stack)-1);
}
测试
#include "stdio.h"
#include "stdlib.h"
#include "seqstack.h"
void main()
{
SeqStack*stack = NULL;
stack =SeqStack_Create(10);
int a[15];
if (stack== NULL)
{
return;
}
for (int i= 0; i < 15; i++)
{
a[i]= i;
SeqStack_Push(stack,&a[i]);
}
printf("capacity:%d\n",SeqStack_Capacity(stack));
printf("length:%d\n",SeqStack_Size(stack));
printf("top:%d\n",*((int *)SeqStack_Top(stack)));
while(SeqStack_Size(stack) > 0)
{
int*tmp = (int*)SeqStack_Pop(stack);
printf("%d\n",*tmp);
}
system("pause");
}
3. 栈的链式存储
栈的链式存储,简称为链栈。使用单链表可以栈的链式存储,考虑到遍历到链尾的内存开销,使用链首作为栈顶。
案例
使用上述单链表的案例。
编写linkstack.h文件
#ifndef __MY_LINKSTACK_H__
#define __MY_LINKSTACK_H__
typedef void LinkStack;
LinkStack* LinkStack_Create();
void LinkStack_Destroy(LinkStack* stack);
void LinkStack_Clear(LinkStack* stack);
int LinkStack_Size(LinkStack* stack);
int LinkStack_Push(LinkStack* stack, void* item);
void* LinkStack_Pop(LinkStack* stack);
void* LinkStack_Top(LinkStack* stack);
#endif
编写linkstack.c文件
#include "stdio.h"
#include "stdlib.h"
#include "linklist.h"
#include "linkstack.h"
typedef struct _tag_LinkStackNode
{
LinkListNodenode;
void* item;
}TLinkStackNode;
LinkStack* LinkStack_Create()
{
returnLinkList_Create();
}
void LinkStack_Destroy(LinkStack* stack)
{
LinkStack_Clear(stack);
LinkList_Destroy(stack);
return ;
}
void LinkStack_Clear(LinkStack* stack)
{
if (stack== NULL)
{
printf("stack== NULL");
return;
}
while(LinkStack_Size(stack) > 0)
{
LinkStack_Pop(stack);
}
return ;
}
int LinkStack_Size(LinkStack* stack)
{
returnLinkList_Length(stack);
}
int LinkStack_Push(LinkStack* stack, void* item)
{
TLinkStackNode*tmp = NULL;
int ret =0;
tmp =(TLinkStackNode*)malloc(sizeof(TLinkStackNode));
if (tmp ==NULL)
{
ret= -1;
printf("tmp== NULL err:%d", ret);
return-1;
}
memset(tmp,0, sizeof(TLinkStackNode));
tmp->item= item;
ret =LinkList_Insert(stack, (LinkListNode*)tmp, 0);
if (ret !=0)
{
printf("funcLinkList_Insert(stack, (LinkListNode*)tmp, 0) err:%d\n", ret);
if(tmp != NULL)
{
free(tmp);
}
returnret;
}
return ret;
}
void* LinkStack_Pop(LinkStack* stack)
{
TLinkStackNode*tmp = NULL;
void* item= NULL;
int ret =0;
tmp =(TLinkStackNode*)LinkList_Delete(stack, 0);
if (tmp ==NULL)
{
printf("栈为空\n");
returntmp;
}
item =tmp->item;
free(tmp);
returnitem;
}
void* LinkStack_Top(LinkStack* stack)
{
TLinkStackNode*tmp = NULL;
void* item= NULL;
tmp =(TLinkStackNode*)LinkList_Get(stack, 0);
if (tmp ==NULL)
{
printf("栈为空\n");
returntmp;
}
item =tmp->item;
returnitem;
}
测试
#include "stdio.h"
#include "stdlib.h"
#include "linkstack.h"
void main()
{
int a[10];
int ret =0;
LinkStack*stack = NULL;
stack =LinkStack_Create();
if (stack== NULL)
{
ret= -1;
printf("stack== NULL err:%d\n", ret);
return;
}
for (int i= 0; i < 10; i++)
{
a[i]= i;
LinkStack_Push(stack,&a[i]);
}
printf("size:%d\n",LinkStack_Size(stack));
printf("top:%d\n",*((int*)LinkStack_Top(stack)));
while(LinkStack_Size(stack) > 0)
{
inttmp = *((int*)LinkStack_Pop(stack));
printf("tmp:%d\n",tmp);
}
LinkStack_Destroy(stack);
system("pause");
}
4. 栈的应用
1) 应用1,就近匹配
一般,编译器都具有检测括号是否匹配的能力。
实现编译器中的符号成对检测,比如
#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0;}
思路,从第一个字符开始扫描,当遇见普通字符时略过,当遇见左符号时压入栈中,当遇见右符号时从栈中弹出栈顶符号,并进行匹配,匹配成功,继续读入下一个字符,匹配失败,立即停止,并报错。扫描结束,检测无误,所有字符扫描完毕,且栈为空,检测有误,匹配失败或所有字符扫描结束但栈非空。
当需要检测成对出现又互不相邻的事物时,可以利用栈的后进先出的特性。
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "linkstack.h"
int isLeft(char c)
{
int ret =0;
switch (c)
{
case'<':
case '(':
case '[':
case '{':
case '\'':
case '\"':
ret= 1;
break;
default:
ret= 0;
break;
}
return ret;
}
int isRight(char c)
{
int ret =0;
switch (c)
{
case'>':
case ')':
case ']':
case '}':
case '\'':
case'\"':
ret= 1;
break;
default:
ret= 0;
break;
}
return ret;
}
int match(char left,char right)
{
int ret =0;
switch(left)
{
case'<':
ret= (right == '>');
break;
case '(':
ret= (right == ')');
break;
case '[':
ret= (right == ']');
break;
case '{':
ret= (right == '}');
break;
case '\'':
ret= (right == '\'');
break;
case'\"':
ret= (right == '\"');
break;
default:
ret= 0;
break;
}
return ret;
}
int scanner(const char* code)
{
LinkStack* stack = NULL;
stack =LinkStack_Create();
int ret =0;
int i = 0;
while (code[i]!= '\0')
{
if(isLeft(code[i]))
{
LinkStack_Push(stack,(void*)(code+i));
}
if(isRight(code[i]))
{
char*c = (char*)LinkStack_Pop(stack);
if(c == NULL || !match(*c, code[i]))
{
printf("%cdoesnt match\n",code[i]);
ret= 0;
break;
}
}
i++;
}
if(LinkStack_Size(stack) == 0 && code[i] == '\0')
{
printf("succeed\n");
ret= 1;
}
else
{
printf("invalidcode\n");
ret= 0;
}
LinkStack_Destroy(stack);
return ret;
}
void main()
{
char* code= "#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0;";
int ret =scanner(code);
printf("%d\n",ret);
system("pause");
}
2) 应用2,中缀、后缀
中缀符合人类思考习惯,后缀符合计算机运算。人类5+4计算机5 4 +;人类1+2*3计算机1 2 3 + *。
将中缀表达式转换为后缀表达式。
使用栈,算法
遍历中缀表达式中的数字和符号。
对于数字,直接输出。
对于符号
左括号,进栈;
运算符号,与栈顶符号进行优先级比较,若栈顶符号优先级低,此符号进栈(默认栈顶是左括号,左括号优先级最低),若栈顶符号优先级不低,将栈顶符号弹出并输出,之后进栈。
右括号,将栈顶符号弹出并输出,直到匹配到左括号。
遍历结束,将栈中的所有符号弹出并输出。
中缀转后缀的案例
#include "stdio.h"
#include "stdlib.h"
#include "linkstack.h"
int isNumber(char c)
{
return (c>= '0' && c <= '9');
}
int isOperator(char c)
{
return (c== '+') || (c == '-') || (c == '*') || (c == '/');
}
int isLeft(char c)
{
return c =='(';
}
int isRight(char c)
{
return c ==')';
}
int priority(char c)
{
int ret =0;
if ((c =='+') || (c == '-'))
{
ret= 1;
}
if ((c =='*') || (c == '/'))
{
ret= 2;
}
return ret;
}
void output(char c)
{
if (c !='\0')
{
printf("%c", c);
}
}
void transform(const char* exp)
{
int i = 0;
LinkStack*stack = LinkStack_Create();
while(exp[i] != '\0')
{
if(isNumber(exp[i]))
{
output(exp[i]);
}
elseif (isOperator(exp[i]))
{
while(priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)))
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Push(stack,(void *)(int)exp[i]);
}
elseif (isLeft(exp[i]))
{
LinkStack_Push(stack,(void *)(int)exp[i]);
}
elseif (isRight(exp[i]))
{
while(!isLeft((char)(int)LinkStack_Top(stack)))
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Pop(stack);
}
else
{
printf("invalidexpression\n");
break;
}
i++;
}
while((LinkStack_Size(stack) > 0) && (exp[i] == '\0'))
{
output((char)(int)LinkStack_Pop(stack));
}
LinkStack_Destroy(stack);
}
void main()
{
transform("8+(21-1)*2");
system("pause");
}
3) 应用3,后缀计算
算法
遍历后缀表达式中的数字和符号
对于数字,进栈。
对于符号,从栈中弹出右操作数;对于符号,从栈中弹出左操作出数;根据符号进行运算;将运算结果压入栈中。
遍历结束,栈中的唯一数字为计算结果。
#include "stdio.h"
#include "stdlib.h"
#include "linkstack.h"
int isNumber(char c)
{
return (c>= '0' && c <= '9');
}
int isOperator(char c)
{
return (c== '+') || (c == '-') || (c == '*') || (c == '/');
}
int value(char c)
{
return (c -'0');
}
int express(char left, char right, char operator)
{
int ret =0;
switch(operator)
{
case '+':
ret= left + right;
break;
case '-':
ret= left - right;
break;
case '*':
ret= left * right;
break;
case '/':
ret= left / right;
break;
default:
break;
}
return ret;
}
int computer(const char* exp)
{
LinkStack*stack = LinkStack_Create();
int ret =0;
int i = 0;
while(exp[i] != '\0')
{
if(isNumber(exp[i]))
{
LinkStack_Push(stack,(void*)value(exp[i]));
}
elseif (isOperator(exp[i]))
{
int right =(int)LinkStack_Pop(stack);
intleft = (int)LinkStack_Pop(stack);
intresult = express(left, right, exp[i]);
LinkStack_Push(stack,(void*)result);
}
else
{
printf("invalidexpression\n");
break;
}
i++;
}
if(LinkStack_Size(stack) == 1 && exp[i] == '\0')
{
ret= (int)LinkStack_Pop(stack);
}
else
{
printf("invalidexpression\n");
}
LinkStack_Destroy(stack);
return ret;
}
void main()
{
printf("8+(3-1)*5= %d\n", computer("831-5*+"));
system("pause");
}
四、 队列
1. 基本概念
队列是一种先进先出的线性表,简称FIFO。队列仅在线性表的两端进行操作。对头,取出元素的一端。队尾,插入元素的一端。队列不允许在中间部位进行操作。
队列在程序设计中使用频繁。键盘进行各种输入,到显示器上的输出,就是队列的典型应用。
2. 队列的顺序存储
队列的顺序存储,可以通过模拟线性表的顺序存储实现。
使用上述的线性表顺序存储的例子。
编写seqqueue.h文件
#ifndef _MY_SEQQUEUE_H_
#define _MY_SEQQUEUE_H_
typedef void SeqQueue;
SeqQueue* SeqQueue_Create(int capacity);
void SeqQueue_Destroy(SeqQueue* queue);
void SeqQueue_Clear(SeqQueue* queue);
int SeqQueue_Append(SeqQueue* queue, void* item);
void* SeqQueue_Retrieve(SeqQueue* queue);
void* SeqQueue_Header(SeqQueue* queue);
int SeqQueue_Length(SeqQueue* queue);
int SeqQueue_Capacity(SeqQueue* queue);
#endif;
编写seqqueue.c文件
#include "seqqueue.h"
#include "stdio.h"
#include "stdlib.h"
#include "seqlist.h"
SeqQueue* SeqQueue_Create(int capacity)
{
returnSeqList_Create(capacity);
}
void SeqQueue_Destroy(SeqQueue* queue)
{
returnSeqList_Destroy(queue);
}
void SeqQueue_Clear(SeqQueue* queue)
{
returnSeqList_Clear(queue);
}
int SeqQueue_Append(SeqQueue* queue, void* item)
{
returnSeqList_Insert(queue, item, SeqQueue_Length(queue));
}
void* SeqQueue_Retrieve(SeqQueue* queue)
{
returnSeqList_Delete(queue,0);
}
void* SeqQueue_Header(SeqQueue* queue)
{
returnSeqList_Get(queue,0);
}
int SeqQueue_Length(SeqQueue* queue)
{
returnSeqList_Length(queue);
}
int SeqQueue_Capacity(SeqQueue* queue)
{
returnSeqList_Capacity(queue);
}
测试
#include "stdio.h"
#include "stdlib.h"
#include "seqqueue.h"
void main()
{
SeqQueue*queue = NULL;
int a[10];
queue =SeqQueue_Create(10);
if (queue== NULL)
{
return;
}
for (int i= 0; i < 10; i++)
{
a[i]= i;
SeqQueue_Append(queue,&a[i]);
}
printf("lengh:%d\n",SeqQueue_Length(queue));
printf("capacity:%d\n",SeqQueue_Capacity(queue));
printf("heademl:%d\n",*((int *)SeqQueue_Header(queue)));
while(SeqQueue_Length(queue) > 0)
{
inttmp = *((int*)SeqQueue_Retrieve(queue));
printf("%d", tmp);
}
printf("\n");
SeqQueue_Destroy(queue);
system("pause");
}
3. 队列的链式存储
队列的链式存储,通过使用线性表的链式存储模式实现。使用前面案例中的线性表的链式存储。
案例
编写linkqueue.h文件
#ifndef _MY_LINKQUEUE_H_
#define _MY_LINKQUEUE_H_
typedef void LinkQueue;
LinkQueue* LinkQueue_Create();
void LinkQueue_Destroy(LinkQueue* queue);
void LinkQueue_Clear(LinkQueue* queue);
int LinkQueue_Append(LinkQueue* queue, void* item);
void* LinkQueue_Retrieve(LinkQueue* queue);
void* LinkQueue_Header(LinkQueue* queue);
int LinkQueue_Length(LinkQueue* queue);
#endif;
编写linkqueue.c文件
#include "stdio.h"
#include "stdlib.h"
#include "linkqueue.h"
#include "linklist.h"
typedef struct _tag_LinkQueueNode
{
LinkListNodenode;
void* item;
}TLinkQueueNode;
LinkQueue* LinkQueue_Create()
{
returnLinkList_Create();
}
void LinkQueue_Destroy(LinkQueue* queue)
{
LinkQueue_Clear(queue);
LinkList_Destroy(queue);
return ;
}
void LinkQueue_Clear(LinkQueue* queue)
{
while(LinkQueue_Length(queue) > 0)
{
LinkQueue_Retrieve(queue,0);
}
LinkList_Clear(queue);
return ;
}
int LinkQueue_Append(LinkQueue* queue, void* item)
{
int ret =0;
TLinkQueueNode*node = NULL;
node =(TLinkQueueNode*)malloc(sizeof(TLinkQueueNode));
if (node ==NULL)
{
ret= -1;
printf("funcLinkQueue_Append malloc err:%d\n", ret);
returnret;
}
memset(node,0, sizeof(TLinkQueueNode));
node->item= item;
ret = LinkList_Insert(queue,(LinkListNode*)node,LinkList_Length(queue));
if (ret !=0)
{
printf("funcLinkList_Insert err:%d\n", ret);
if(node != NULL)
{
free(node);
}
returnret;
}
return ret;
}
void* LinkQueue_Retrieve(LinkQueue* queue)
{
int* ret =NULL;
int errcode= 0;
TLinkQueueNode*node = NULL;
node =(TLinkQueueNode*)LinkList_Delete(queue, 0);
if (node ==NULL)
{
errcode= -1;
printf("funcLinkQueue_Retrieve node == NULL err:%d\n", errcode);
returnNULL;
}
ret =node->item;
if (node !=NULL)
{
free(node);
}
return ret;
}
void* LinkQueue_Header(LinkQueue* queue)
{
TLinkQueueNode*node = NULL;
void* ret =NULL;
int errcode= 0;
node =(TLinkQueueNode*)LinkList_Get(queue, 0);
if (node ==NULL)
{
errcode= -1;
printf("funcLinkQueue_Header err:%d", errcode);
returnret;
}
ret =node->item;
return ret;
}
int LinkQueue_Length(LinkQueue* queue)
{
returnLinkList_Length(queue);
}
测试
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "linkqueue.h"
void main()
{
int a[10];
LinkQueue*queue = NULL;
queue =LinkQueue_Create();
if (queue== NULL)
{
return;
}
for (int i= 0; i < 10; i++)
{
a[i]= i;
LinkQueue_Append(queue,&a[i]);
}
printf("length:%d\n",LinkQueue_Length(queue));
printf("header:%d\n",*((int*)LinkQueue_Header(queue)));
while(LinkQueue_Length(queue) > 0)
{
inttmp = *((int*)LinkQueue_Retrieve(queue));
printf("tmp:%d", tmp);
}
printf("\n");
LinkQueue_Destroy(queue);
system("pause");
}
五、 树
1. 树的基本概念
由一个或多个(n>=0)结点组成的有限集合T,有且仅有一个结点称为根(root),当n>1时,其余的结点分为m(m>=0)个互不相交的有限集合T1,T2,…,Tm。每个集合本身又是棵树,被称作这个根的子树。
相关术语
根,根结点,没有前驱。
叶子,终端结点,没有后继。
森林,指m棵不相交的数的集合,例如删除A后的子树个数。
有序树,结点各子树从左至右有序,不能互换。
无序树,结点各子树可互换位置。
双亲,即上层的那个结点,直接前驱,parents。
孩子,即下层结点的子树,直接后继,children。
兄弟,同一双亲下的同层结点,孩子之间互称兄弟,sibling。
堂兄弟,即双亲位于同一层的结点,当并非同一双亲,cousin。
祖先,即从根到该结点所经分支的所有结点。
子孙,即该结点下层子树中的任一结点。
结点,即树的数据元素。
结点的度,结点挂接的子树数。有几个直接后继就是几度,亦称次数。
结点的层次,从根到该结点的层数,根结点算第一层。
终端结点,即度为0的结点,即叶子。
分支结点,除树根以外的结点,也称为内部结点。
树的度,所有结点度中的最大值。
树的深度,指所有结点中最大的层数。
树的表示法,有,图形表示法,嵌套集合表示法,广义表表示法,目录表示法,左孩子-右兄弟表示法。
树的逻辑结构,一对多,有多个直接后继(如家谱树、目录树等),但只有一个根结点,且子树之间互不相交。
树的存储结构,有顺序存储、链式存储等方式。树的顺序存储,规定为从上至下、从左至右将树的结点依次存入内存,缺陷是复原困难,所以没有实用价值。树的链式存储,可用多重链表,一个前驱指针,n个后继指针。树中结点类型可以设计为等长的或不等长的,等长的太浪费,不等长的结构太复杂。
树采用顺序存储或者链式链式存储都有很难解决的缺陷。为了简化问题,先研究最简单、最有规律的树,然后将一般的树转化为这种简单的树。
树的运算,普通树若不转化为二叉树,则运算很难实现。二叉树的运算仍然是插入、删除、修改、查找、排序等,但这些操作必须建立在对树结点能够遍历的基础上。
2. 二叉树
二叉树是n(n>=0)个结点的有限集合,由一个根结点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成。逻辑结构,一对二。基本特征,每个结点最多只有两棵子树;左子树和右子树次序不能颠倒。
二叉树的性质
性质1,在二叉树的第i层上至多有2i-1个结点(i>0)。
性质2,深度为k的二叉树至多有2k-1个结点(k>0)。
性质3,对于任何一棵二叉树,若2度的结点数有n2个。则叶子数(n0)必定为n2+1,即n0= n2+1。
满二叉树,一棵深度为k且有2k-1个结点的二叉树。特点,每层都充满了结点。
完全二叉树,深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应。
完全二叉树的特点就是,只有最后一层叶子不满,且全部集中在左边。这其实是顺序二叉树的含义。
研究这两种特殊形式的意义是,它们在顺序存储方式下可以复原。
对于两种特殊形式的二叉树,还特别具备以下2个性质
性质4,具有n个结点的完全二叉树的深度必为|_log2n_|+1。即log2n向下取整+1。
性质5,对完全二叉树,若从上至下、从左至右编号,则编号为i的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2(i=1时为根除外)。
二叉树的存储结构,按二叉树的结点从上而下、从左至右编号,用一组连续的存储单元存储。如果是完全或满二叉树可以做到唯一复原。因为,下标值为i的双亲,其左孩子的下标值必为2i,其右孩子的下标值必为2i+1。
对于不是完全二叉树或满二叉树的树,为了便于顺序存储时复原,一律转为完全二叉树,方发很简单,将各层空缺处统统补上虚结点,其内容为空。缺点是浪费空间,插入和删除不方便。
树的链式存储结构,用二叉链表可方便表示,一般从根结点开始存储。相应地,访问树中结点时也只能从根开始。如果需要倒查某结点的双亲,可以再增加一个双亲域(直接前驱)指针,将二叉链表变成三叉链表。
3. 树的表示法
常见的表示法有,二叉链表示法,三叉链表示法,双亲表示法。
二叉链表示法案例
typedef struct BiTNode
{
int data;
struct BiTNode*lChild, *rChild;
}BiTNode,*BiTree;
void test1()
{
BiTNode t1,t2, t3, t4, t5, t6;
t1.data =1;
t2.data =2;
t3.data =3;
t4.data =4;
t5.data =5;
t6.data =6;
t1.lChild =&t2;
t1.rChild =&t3;
t2.lChild =&t4;
t2.rChild =&t5;
}
void test2()
{
BiTree p1,p2, p3, p4, p5;
p1 =(BiTree)malloc(sizeof(BiTree));
p2 =(BiTree)malloc(sizeof(BiTree));
p3 =(BiTree)malloc(sizeof(BiTree));
p4 =(BiTree)malloc(sizeof(BiTree));
p5 =(BiTree)malloc(sizeof(BiTree));
p1->data= 1;
p2->data= 2;
p3->data= 3;
p4->data= 4;
p5->data= 5;
p1->lChild= p2;
p1->rChild= p3;
p2->lChild= p4;
p2->rChild= p5;
BiTree tmp= p1->lChild;
printf("%d\n",tmp->data);
}
void main()
{
test2();
system("pause");
}
三叉链表示法案例
typedef struct BiTNode
{
int data;
struct BiTNode*lChild, *rChild;
structBiTNode *parent;
}BiTNode, *BiTree;
void test1()
{
BiTNode t1,t2, t3, t4, t5, t6;
t1.data =1;
t2.data =2;
t3.data =3;
t4.data =4;
t5.data =5;
t6.data =6;
t1.lChild =&t2;
t2.parent =&t1;
t1.rChild =&t3;
t3.parent =&t2;
t2.lChild =&t4;
t4.parent =&t2;
t2.rChild =&t5;
t5.parent =&t2;
}
void test2()
{
BiTree p1,p2, p3, p4, p5;
p1 =(BiTree)malloc(sizeof(BiTree));
p2 =(BiTree)malloc(sizeof(BiTree));
p3 =(BiTree)malloc(sizeof(BiTree));
p4 =(BiTree)malloc(sizeof(BiTree));
p5 =(BiTree)malloc(sizeof(BiTree));
p1->data= 1;
p2->data= 2;
p3->data= 3;
p4->data= 4;
p5->data= 5;
p1->lChild= p2;
p2->parent= p1;
p1->rChild= p3;
p3->parent= p1;
p2->lChild= p4;
p4->parent= p2;
p2->rChild= p5;
p5->parent= p2;
BiTree tmp= p1->lChild;
printf("%d\n",tmp->data);
}
void main()
{
test2();
system("pause");
}
双亲表示法案例
#define MAX_TREE_SIZE 100
typedef struct BPTNode
{
int data;
intparentPosition;
int LRTag;
}BPTNode;
typedef struct BPTree
{
BPTNodenodes[MAX_TREE_SIZE];
intnum_node;
int root;
}BPTree;
void test31()
{
BPTreetree;
tree.nodes[0].parentPosition= 1000;
tree.nodes[0].data= 'a';
tree.nodes[1].parentPosition= 0;
tree.nodes[1].data= 'b';
tree.nodes[1].LRTag= 1;
tree.nodes[2].parentPosition= 0;
tree.nodes[2].data= 'c';
tree.nodes[2].LRTag= 2;
}
void main()
{
test31();
system("pause");
}
4. 二叉树的遍历
二叉树由根、左子树、右子树构成,定义为DLR。DLR的组合定义了六种可能的遍历方案:LDR,LRD,DLR,DRL,RLD,RDL。
若限定先左后右,则有三种实现方案,DLR先序遍历,LDR中序遍历,LRD后序遍历。先中后的意思是访问结点D是先子树出现还是后于子树出现。
先序遍历,即先根再左再右。中序遍历,即先左再根再右。后序遍历,即先左再右再根。
案例
#include "stdio.h"
#include "stdlib.h"
typedef struct BiTNode
{
int data;
structBiTNode *lChild, *rChild;
}BiTNode, *BiTree;
void preOrder(BiTNode *root)
{
if (root ==NULL)
{
return;
}
printf("%d", root->data);
BiTNode* l= NULL;
l =root->lChild;
preOrder(l);
BiTNode* r= NULL;
r =root->rChild;
preOrder(r);
}
void inOrder(BiTNode *root)
{
if (root ==NULL)
{
return;
}
BiTNode* l= NULL;
l =root->lChild;
inOrder(l);
printf("%d", root->data);
BiTNode* r= NULL;
r =root->rChild;
inOrder(r);
}
void postOrder(BiTNode *root)
{
if (root ==NULL)
{
return;
}
BiTNode* l= NULL;
l =root->lChild;
postOrder(l);
BiTNode* r= NULL;
r =root->rChild;
postOrder(r);
printf("%d", root->data);
}
void test41()
{
BiTNode t1,t2, t3, t4, t5, t6;
memset(&t1,0, sizeof(BiTNode));
memset(&t2,0, sizeof(BiTNode));
memset(&t3,0, sizeof(BiTNode));
memset(&t4,0, sizeof(BiTNode));
memset(&t5,0, sizeof(BiTNode));
t1.data =1;
t2.data =2;
t3.data =3;
t4.data =4;
t5.data =5;
t6.data =6;
t1.lChild =&t2;
t1.rChild =&t3;
t2.lChild =&t4;
t2.rChild =&t5;
preOrder(&t1);
printf("\n");
inOrder(&t1);
printf("\n");
postOrder(&t1);
}
void main()
{
test41();
system("pause");
}
5. 树的基本操作
1) 计算树叶子结点
输出叶子结点,用任何一种遍历算法,凡是所有指针均为空者,则为叶子,进行统计和打印。
#include "stdio.h"
#include "stdlib.h"
typedef struct BiTNode
{
int data;
structBiTNode *lChild, *rChild;
}BiTNode, *BiTree;
void preOrder(BiTNode *root)
{
if (root ==NULL)
{
return;
}
printf("%d", root->data);
BiTNode* l= NULL;
l =root->lChild;
preOrder(l);
BiTNode* r= NULL;
r =root->rChild;
preOrder(r);
}
void inOrder(BiTNode *root)
{
if (root ==NULL)
{
return;
}
BiTNode* l= NULL;
l =root->lChild;
inOrder(l);
printf("%d", root->data);
BiTNode* r= NULL;
r =root->rChild;
inOrder(r);
}
void postOrder(BiTNode *root)
{
if (root ==NULL)
{
return;
}
BiTNode* l= NULL;
l =root->lChild;
postOrder(l);
BiTNode* r= NULL;
r =root->rChild;
postOrder(r);
printf("%d", root->data);
}
int sum = 0;
void countLeaf(BiTNode *root)
{
if (root !=NULL)
{
if(root->lChild == NULL && root->rChild == NULL)
{
sum++;
}
if(root->lChild != NULL)
{
countLeaf(root->lChild);
}
if(root->rChild != NULL)
{
countLeaf(root->rChild);
}
}
}
void countLeaf2(BiTNode *root,int *sum)
{
if (root !=NULL)
{
if(root->lChild == NULL && root->rChild == NULL)
{
(*sum)++;
}
if(root->lChild != NULL)
{
countLeaf(root->lChild,sum);
}
if(root->rChild != NULL)
{
countLeaf(root->rChild,sum);
}
}
}
void countLeaf3(BiTNode *root, int *sum)
{
if (root !=NULL)
{
if(root->lChild != NULL)
{
countLeaf(root->lChild,sum);
}
if(root->rChild != NULL)
{
countLeaf(root->rChild,sum);
}
if(root->lChild == NULL && root->rChild == NULL)
{
(*sum)++;
}
}
}
void test41()
{
BiTNode t1,t2, t3, t4, t5, t6;
memset(&t1,0, sizeof(BiTNode));
memset(&t2,0, sizeof(BiTNode));
memset(&t3,0, sizeof(BiTNode));
memset(&t4,0, sizeof(BiTNode));
memset(&t5,0, sizeof(BiTNode));
t1.data =1;
t2.data =2;
t3.data =3;
t4.data =4;
t5.data =5;
t6.data =6;
t1.lChild =&t2;
t1.rChild =&t3;
t2.rChild =&t4;
t3.lChild =&t5;
preOrder(&t1);
printf("\n");
inOrder(&t1);
printf("\n");
postOrder(&t1);
printf("\n");
//countLeaf(&t1);
printf("countLeaf:%d\n",sum);
//countLeaf2(&t1,&sum);
printf("countLeaf2:%d\n",sum);
countLeaf3(&t1,&sum);
printf("countLeaf3:%d\n",sum);
}
void main()
{
test41();
system("pause");
}
2) 求树的高度
#include "stdio.h"
#include "stdlib.h"
typedef struct BiTNode
{
int data;
structBiTNode *lChild, *rChild;
}BiTNode, *BiTree;
void preOrder2(BiTNode *root)
{
if (root ==NULL)
{
return;
}
printf("%d", root->data);
BiTNode* l= NULL;
l =root->lChild;
preOrder2(l);
BiTNode* r= NULL;
r =root->rChild;
preOrder2(r);
}
int depth(BiTNode* root)
{
int ldepth= 0;
int rdepth= 0;
int tdepth= 0;
if (root ==NULL)
{
tdepth= 0;
returntdepth;
}
ldepth =depth(root->lChild);
rdepth =depth(root->rChild);
tdepth =ldepth > rdepth ? ldepth : rdepth;
returntdepth + 1;
}
void main()
{
BiTNode t1,t2, t3, t4, t5, t6;
memset(&t1,0, sizeof(BiTNode));
memset(&t2,0, sizeof(BiTNode));
memset(&t3,0, sizeof(BiTNode));
memset(&t4,0, sizeof(BiTNode));
memset(&t5,0, sizeof(BiTNode));
t1.data =1;
t2.data =2;
t3.data =3;
t4.data =4;
t5.data =5;
t6.data =6;
t1.lChild =&t2;
t1.rChild =&t3;
t2.rChild =&t4;
t3.lChild =&t5;
preOrder2(&t1);
printf("\n");
inttreedepth = 0;
treedepth =depth(&t1);
printf("depth:%d\n",treedepth);
system("pause");
}
3) 求copy树
#include "stdio.h"
#include "stdlib.h"
typedef struct BiTNode
{
int data;
structBiTNode *lChild, *rChild;
}BiTNode, *BiTree;
void preOrder2(BiTNode *root)
{
if (root ==NULL)
{
return;
}
printf("%d", root->data);
BiTNode* l= NULL;
l =root->lChild;
preOrder2(l);
BiTNode* r= NULL;
r =root->rChild;
preOrder2(r);
}
int depth(BiTNode* root)
{
int ldepth= 0;
int rdepth= 0;
int tdepth= 0;
if (root ==NULL)
{
tdepth= 0;
returntdepth;
}
ldepth =depth(root->lChild);
rdepth =depth(root->rChild);
tdepth =ldepth > rdepth ? ldepth : rdepth;
returntdepth + 1;
}
BiTNode* copyTree(BiTNode* root)
{
BiTNode*newRoot = NULL;
BiTNode*newLeft = NULL;
BiTNode*newRight = NULL;
if (root ==NULL)
{
returnNULL;
}
if (root->lChild!= NULL)
{
newLeft= copyTree(root->lChild);
}
else
{
newLeft= NULL;
}
if(root->rChild != NULL)
{
newRight= copyTree(root->rChild);
}
else
{
newRight= NULL;
}
newRoot =(BiTNode*)malloc(sizeof(BiTNode));
if (newRoot== NULL)
{
returnNULL;
}
newRoot->lChild= newLeft;
newRoot->rChild= newRight;
newRoot->data= root->data;
returnnewRoot;
}
void test52()
{
BiTNode t1,t2, t3, t4, t5, t6;
memset(&t1,0, sizeof(BiTNode));
memset(&t2,0, sizeof(BiTNode));
memset(&t3,0, sizeof(BiTNode));
memset(&t4,0, sizeof(BiTNode));
memset(&t5,0, sizeof(BiTNode));
t1.data =1;
t2.data =2;
t3.data =3;
t4.data =4;
t5.data =5;
t6.data =6;
t1.lChild =&t2;
t1.rChild =&t3;
t2.rChild =&t4;
t3.lChild =&t5;
preOrder2(&t1);
printf("\n");
BiTNode*root = copyTree(&t1);
preOrder2(root);
printf("\n");
}
void main()
{
test52();
system("pause");
}
6. 树的非递归遍历
在中序遍历中,当左子树为空或者左子树已经访问完毕后,再访问根。访问完毕根以后,再访问右子树。
对于一个结点中根、左右子树,先走到的后访问,后走到的先访问,可以采用栈结构。
结点所有路径情况,步骤1,如果结点有左子树,该结点入栈,如果没有左子树,访问该结点;步骤2,如果结点有右子树,重复步骤1,如果没有右子树,结点访问完毕,根据栈顶指示回退,访问栈顶元素,并访问右子树,重复步骤1;如果栈为空,表示遍历结束。
入栈的结点表示,本身并没有被访问过,同时右子树也没有被访问过。
非递归遍历中序算法案例
#include "iostream"
using namespace std;
#include "stack"
typedef struct BiTNode
{
int data;
structBiTNode *lChild, *rChild;
}BiTNode, *BiTree;
BiTNode* goLeft(BiTNode* node, stack<BiTNode*>&s)
{
if (node ==NULL)
{
returnNULL;
}
while(node->lChild != NULL)
{
s.push(node);
node= node->lChild;
}
returnnode;
}
void inOrder2(BiTNode* node)
{
BiTNode*ret = NULL;
stack<BiTNode*>s;
ret =goLeft(node, s);
while (ret)
{
printf("%d", ret->data);
if(ret->rChild != NULL)
{
ret= goLeft(ret->rChild, s);
}
elseif (!s.empty())
{
ret= s.top();
s.pop();
}
else
{
ret= NULL;
}
}
}
void main()
{
BiTNode t1,t2, t3, t4, t5, t6;
memset(&t1,0, sizeof(BiTNode));
memset(&t2,0, sizeof(BiTNode));
memset(&t3,0, sizeof(BiTNode));
memset(&t4,0, sizeof(BiTNode));
memset(&t5,0, sizeof(BiTNode));
t1.data =1;
t2.data =2;
t3.data =3;
t4.data =4;
t5.data =5;
t6.data =6;
t1.lChild =&t2;
t1.rChild =&t3;
t2.rChild =&t4;
t3.lChild =&t5;
inOrder2(&t1);
system("pause");
}
利用自己的api函数实现
使用上述链式存储和链式栈存储的文件
#include "stdio.h"
#include "stdlib.h"
#include "linkstack.h"
typedef struct BiTNode
{
int data;
structBiTNode *lChild, *rChild;
}BiTNode, *BiTree;
BiTNode* goLeft(BiTNode* node, LinkStack* s)
{
if (node ==NULL)
{
returnNULL;
}
while(node->lChild != NULL)
{
LinkStack_Push(s,(void *)node);
node= node->lChild;
}
returnnode;
}
void inOrder2(BiTNode* node)
{
BiTNode*ret = NULL;
LinkStack*stack = NULL;
stack =LinkStack_Create();
ret =goLeft(node, stack);
while (ret)
{
printf("%d", ret->data);
if(ret->rChild != NULL)
{
ret= goLeft(ret->rChild, stack);
}
elseif (LinkStack_Size(stack) > 0)
{
ret= (BiTNode*)LinkStack_Pop(stack);
}
else
{
ret= NULL;
}
}
}
void main()
{
BiTNode t1,t2, t3, t4, t5, t6;
memset(&t1,0, sizeof(BiTNode));
memset(&t2,0, sizeof(BiTNode));
memset(&t3,0, sizeof(BiTNode));
memset(&t4,0, sizeof(BiTNode));
memset(&t5,0, sizeof(BiTNode));
t1.data =1;
t2.data =2;
t3.data =3;
t4.data =4;
t5.data =5;
t6.data =6;
t1.lChild =&t2;
t1.rChild =&t3;
t2.rChild =&t4;
t3.lChild =&t5;
inOrder2(&t1);
system("pause");
}
7. 二叉树的创建和释放
#号方法创建
利用#号来占位树中的空结点。比如根1左2(左4)右3(左5),使用#号表示为124###35###。
创建树、释放树代码案例
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
typedef struct BiTNode
{
char data;
structBiTNode *lchild, *rchild;
}BiTNode, *BiTree;
BiTNode* createBiTNode()
{
char h;
int ret =0;
BiTNode*node = NULL;
BiTNode* pL= NULL;
BiTNode* pR= NULL;
scanf("%c",&h);
if (h =='#')
{
returnNULL;
}
else
{
node= (BiTNode *)malloc(sizeof(BiTNode));
pL= (BiTNode *)malloc(sizeof(BiTNode));
pR= (BiTNode *)malloc(sizeof(BiTNode));
if(node == NULL||pL == NULL||pR == NULL)
{
ret= -1;
printf("funccreateBiTNode node == NULL||pL == NULL||pR == NULL err:%d", ret);
returnNULL;
}
memset(node,0, sizeof(BiTNode));
memset(pL,0, sizeof(BiTNode));
memset(pR,0, sizeof(BiTNode));
node->data= h;
pL= createBiTNode();
if(pL != NULL)
{
node->lchild= pL;
}
else
{
node->lchild= NULL;
}
pR= createBiTNode();
if(pR != NULL)
{
node->rchild= pR;
}
else
{
node->rchild= NULL;
}
returnnode;
}
}
BiTNode* createBiTNode2()
{
char h;
int ret =0;
BiTNode*node = NULL;
scanf("%c",&h);
if (h =='#')
{
returnNULL;
}
else
{
node= (BiTNode *)malloc(sizeof(BiTNode));
if(node == NULL )
{
ret= -1;
printf("funccreateBiTNode node == NULL||pL == NULL||pR == NULL err:%d", ret);
returnNULL;
}
memset(node,0, sizeof(BiTNode));
node->data= h;
node->lchild= createBiTNode2();
node->rchild= createBiTNode();
returnnode;
}
}
void freeTree(BiTNode* node)
{
if (node ==NULL)
{
return;
}
if(node->lchild != NULL)
{
freeTree(node->lchild);
node->lchild= NULL;
}
if(node->rchild != NULL)
{
freeTree(node->rchild);
node->rchild= NULL;
}
if (node !=NULL)
{
free(node);
node= NULL;
}
}
void preOrder(BiTNode *root)
{
if (root ==NULL)
{
return;
}
printf("%c", root->data);
BiTNode* l= NULL;
l =root->lchild;
preOrder(l);
BiTNode* r= NULL;
r =root->rchild;
preOrder(r);
}
void main()
{
BiTNode* t= NULL;
t =(BiTNode*)malloc(sizeof(BiTNode));
BiTNode*root = NULL;
root =createBiTNode2();
preOrder(root);
freeTree(root);
system("pause");
}
8. 二叉树线索树
普通二叉树只能找到结点的左右孩子信息,而该结点的直接前驱和直接后继只能在遍历过程中获得。
如果可将遍历后对应的有关前驱和后继预存起来,则从第一个结点开始就能很快顺藤摸瓜而遍历整个树了。
若结点有左子树,则lchild指向其左孩子;否则,lchild指向其直接前驱(即线索ltag);若结点有右子树,则rchild指向其右孩子;否则,rchild指向其直接后继(即线索rtag)。当tag域为0时,表示正常情况;当tag域为1时,表示线索情况。
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct BiTNode
{
int data;
structBiTNode* lchild;
structBiTNode* rchild;
int ltag;
int rtag;
}BiTNode;
BiTNode* createBiTNode2()
{
char h;
int ret =0;
BiTNode*node = NULL;
scanf("%c",&h);
if (h =='#')
{
returnNULL;
}
else
{
node= (BiTNode *)malloc(sizeof(BiTNode));
if(node == NULL)
{
ret= -1;
printf("funccreateBiTNode node == NULL||pL == NULL||pR == NULL err:%d", ret);
returnNULL;
}
memset(node,0, sizeof(BiTNode));
node->data= h;
node->lchild= createBiTNode2();
node->rchild= createBiTNode2();
returnnode;
}
}
void freeTree(BiTNode* node)
{
if (node ==NULL)
{
return;
}
if(node->lchild != NULL)
{
freeTree(node->lchild);
node->lchild= NULL;
}
if(node->rchild != NULL)
{
freeTree(node->rchild);
node->rchild= NULL;
}
if (node !=NULL)
{
free(node);
node= NULL;
}
}
BiTNode* pre;
int visit(int data)
{
if (data ==0)
{
return-1;
}
printf("node->data:%d", data);
return 0;
}
void inThreading(BiTNode* p)
{
if (p!=NULL)
{
inThreading(p->lchild);
if(p->lchild == NULL)
{
p->ltag= 1;
p->lchild= pre;
}
if(pre->rchild != NULL)
{
pre-> rtag = 1;
pre-> rchild = p;
}
pre= p;
inThreading(p->rchild);
}
}
int inOrderThreading(BiTNode* tree, BiTNode* t)
{
int ret =0;
if (tree ==NULL)
{
ret= -1;
returnret;
}
tree->ltag= 0;
tree->rtag= 1;
tree->rchild= tree;
if (t ==NULL)
{
tree->lchild= tree;
}
else
{
tree->lchild= t;
pre= tree;
inThreading(t);
pre->rchild= tree;
pre->rtag= 1;
tree->rchild= pre;
}
return ret;
}
int inOrderTraverse(BiTNode* node)
{
int ret =0;
BiTNode*tmp;
tmp =node->lchild;
visit(tmp->data);
while (tmp!= node)
{
while(tmp->ltag == 1)
{
tmp= tmp->lchild;
}
if(tmp == NULL)
{
ret= -1;
returnret;
}
while(tmp->rtag == 1 && tmp->rchild != node)
{
tmp= tmp->rchild;
if(tmp != NULL)
{
visit(tmp->data);
}
}
tmp= tmp->rchild;
}
return ret;
}
void main()
{
BiTNode*root, *tmp;
root =(BiTNode*)malloc(sizeof(BiTNode));
tmp =(BiTNode*)malloc(sizeof(BiTNode));
printf("按照前序输入二叉树,比如ABDH##I##EJ###CF##G##\n");
root =createBiTNode2();
inOrderThreading(tmp,root);
printf("中序遍历二叉树线索数:\n");
inOrderTraverse(tmp);
printf("\n");
system("pause");
}
9. 霍夫曼树
组建一个网络,耗费最小带权路径长度wpl,这个二叉树是霍夫曼树。
霍夫曼是一种特殊的二叉树。应用于信息编码和数据压缩领域。是现代压缩算法的基础。
六、 常用的排序算法
1. 概念
排序是计算机内经常进行的一种操作,其目的是将一组无序的数据元素调整为有序的数据元素。
排序中的关键操作。比较,任意两个数据元素通过比较操作确定先后次序。交换,数据元素之间需要交换才能得到预期效果。
内排序,整个排序过程不需要访问外存便能完成。外排序,待排序的数据元素数量很大,整个序列的排序过程不可能在内存中完成。
排序的审判。时间性能,关键性能差异体现在比较和交换的数量。辅助存储空间,为完成排序操作需要的额外的存储空间;必要时可以空间换时间。算法的实现复杂性,过于复杂的排序法会影响代码的可读性和可维护性,也可能影响排序的性能。
排序是数据元素从无序到有序的过程。排序具有稳定性,是选择排序算法的因素之一。比较和交换是排序的基本操作。多关键字排序与单关键字排序无本质区别。排序的时间性能是区分排序算法好坏的主要因素。
2. 选择法
思路,每一趟在后面n-i个待排的数据元素中选出关键字,最小的元素,作为有序元素序列的第i个元素。
过程,首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将它与第一个记录交换。再通过n-2次比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换。重复上述操作,共进行n-1趟排序后,排序结束。
#include "stdio.h"
#include "stdlib.h"
void printfArray(int array[], int size)
{
for (int i= 0; i < size; i++)
{
printf("%d", array[i]);
}
printf("\n");
}
void selectSort(int array[], int size)
{
int tmp;
for (int i= 0; i < size - 1; i++)
{
for(int j = i; j < size - 1; j++)
{
if(array[i]>array[j + 1])
{
tmp= array[i];
array[i]= array[j + 1];
array[j+ 1] = tmp;
}
}
}
}
void main()
{
int array[]= { 12, 33, 42, 2, 15, 345 };
int size =sizeof(array) / sizeof(*array);
printfArray(array,size);
selectSort(array,size);
printfArray(array,size);
system("pause");
}
3. 插入排序
过程,整个排序过程为n-1趟插入,即先将序列中第1个记录看成是一个有序序列。然后从第2个记录开始,逐个进行插入,直至整个序列有序。
实质,对线性表执行n-1次插入,只是先要找到插入位置。
#include "stdio.h"
#include "stdlib.h"
void printfArray(int array[], int size)
{
for (int i= 0; i < size; i++)
{
printf("%d ", array[i]);
}
printf("\n");
}
void insertSort(int array[], int size)
{
int k = -1;
int tmp =-1;
for (int i= 0; i < size; i++)
{
k= i;
tmp= array[k];
for(int j = i - 1; (j >= 0) && (array[j]>tmp); j--)
{
array[j+ 1] = array[j];
k= j;
}
array[k]= tmp;
}
}
void main()
{
int array[]= { 12, 33, 42, 2, 15, 345 };
int size =sizeof(array) / sizeof(*array);
printfArray(array,size);
insertSort(array,size);
printfArray(array,size);
system("pause");
}
4. 冒泡排序
#include "stdio.h"
#include "stdlib.h"
void printfArray(int array[], int size)
{
for (int i= 0; i < size; i++)
{
printf("%d", array[i]);
}
printf("\n");
}
void bubbleSort(int array[], int size)
{
intexchange = 1;
for (int i= 0;(i < size-1) && exchange; i++)
{
exchange= 0;
for(int j = 0; j < size - i - 1; j++)
{
if(array[j] > array[j + 1])
{
exchange= 1;
inttmp = array[j];
array[j]= array[j + 1];
array[j+ 1] = tmp;
}
}
}
}
void main()
{
int array[]= { 12, 33, 42, 2, 15, 345 };
int size =sizeof(array) / sizeof(*array);
printfArray(array,size);
bubbleSort(array,size);
printfArray(array,size);
system("pause");
}
5. 希尔排序
过程,先去一个正整数d1<n,把所有相隔d1的记录放一组,组内进行直接插入排序,然后取d2<d1,重复上述分组和排序操作,直至di=1,即所有记录放进一个组中排序为止。
希尔排序是不稳定的。
#include "stdio.h"
#include "stdlib.h"
void printfArray(int array[], int size)
{
for (int i= 0; i < size; i++)
{
printf("%d", array[i]);
}
printf("\n");
}
void shellSort(int array[], int size)
{
int k = -1;
int tmp =-1;
int gap =size;
do
{
gap= gap / 3 + 1;
for(int i = gap; i<size; i += gap)
{
k= i;
tmp= array[k];
for(int j = i - gap; (j >= 0) && (array[j]>tmp); j -= gap)
{
array[j+ gap] = array[j];
k= j;
}
array[k]= tmp;
}
} while(gap > 1);
}
void main()
{
int array[]= { 12, 33, 42, 2, 15, 345 };
int size =sizeof(array) / sizeof(*array);
printfArray(array,size);
shellSort(array,size);
printfArray(array,size);
system("pause");
}
6. 快速排序
思路,快速排序是对冒泡排序的一种改进,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,基准数据排在这两个子序列的中间。然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
#include "stdio.h"
#include "stdlib.h"
void printfArray(int array[], int size)
{
for (int i= 0; i < size; i++)
{
printf("%d", array[i]);
}
printf("\n");
}
void swap(int array[], int low, int high)
{
int tmp =array[low];
array[low]= array[high];
array[high]= tmp;
}
int partition(int array[], int low, int high)
{
int pv =array[low];
while (low< high)
{
while((low < high) && (array[high] >= pv))
{
high--;
}
swap(array,low, high);
while((low < high) && (array[low] <= pv))
{
low++;
}
swap(array,low, high);
}
return low;
}
void quickSort(int array[], int low, int high)
{
if (low< high)
{
intpivot = partition(array, low, high);
quickSort(array,low, pivot - 1);
quickSort(array,pivot + 1, high);
}
}
void main()
{
int array[]= { 12, 33, 42, 2, 15, 345 };
int size =sizeof(array) / sizeof(*array);
printfArray(array,size);
quickSort(array,0, size-1);
printfArray(array,size);
system("pause");
}
7. 归并排序
思路,将两个或两个以上的有序序列合并成一个新的有序序列,有序序列v[1]…v[m]和v[m+1]…v[n],这种归并方法称为2路归并。将3个有序序列归并为一个新的序列,称为3路归并。将多个有序序列归并为一个新的序列,称为多路归并。
#include "stdio.h"
#include "stdlib.h"
void printfArray(int array[], int size)
{
for (int i= 0; i < size; i++)
{
printf("%d", array[i]);
}
printf("\n");
}
void swap(int array[], int low, int high)
{
int tmp =array[low];
array[low]= array[high];
array[high]= tmp;
}
void merge(int src[], int des[], int low, int mid, inthigh)
{
int i =low;
int j = mid+ 1;
int k =low;
while ((i<= mid) && (j <= high))
{
if(src[i] < src[j])
{
des[k++]= src[i++];
}
else
{
des[k++]= src[j++];
}
}
while (i<= mid)
{
des[k++]= src[i++];
}
while (j<= high)
{
des[k++]= src[j++];
}
}
void mergeSort(int src[], int des[], int low, int high,int max)
{
if (low ==high)
{
des[low]= src[low];
}
else
{
intmid = (low + high) / 2;
int*space = (int*)malloc(sizeof(int)*max);
if(space != NULL)
{
mergeSort(src,space, low, mid, max);
mergeSort(src,space, mid + 1, high, max);
merge(space,des, low, mid, high);
}
free(space);
}
}
void main()
{
int array[]= { 12, 33, 42, 2, 15, 345 };
int size =sizeof(array) / sizeof(*array);
printfArray(array,size);
mergeSort(array,array, 0, size - 1, size);
printfArray(array,size);
system("pause");
}
七、 c++数据结构模板库
1. 顺序存储模板库
编写类模板头文件SeqList.h
#pragma once
template <typename T>
class SeqList
{
public:
SeqList(intcapacity);
~SeqList();
public:
intgetLength();
intgetCapacity();
intinsert(T &t, int pos);
int get(intpos, T &t);
int del(intpos, T &t);
intclear();
private:
int length;
intcapacity;
T* pArray;
};
编写模板类的实现文件SeqList.cpp
#include "SeqList.h"
template <typename T>
SeqList<T>::SeqList(int capacity)
{
pArray =new T[capacity];
this->capacity= capacity;
this->length= 0;
}
template <typename T>
SeqList<T>::~SeqList()
{
delete[]pArray;
pArray =NULL;
length = 0;
capacity =0;
}
template <typename T>
int SeqList<T>::getLength()
{
returnthis->length;
}
template <typename T>
int SeqList<T>::getCapacity()
{
returncapacity;
}
template <typename T>
int SeqList<T>::insert(T &t, int pos)
{
int i = 0;
if (pos< 0)
{
return-1;
}
for (i =length; i>pos; i--)
{
pArray[i]= pArray[i - 1];
}
pArray[i] =t;
this->length++;
return 0;
}
template <typename T>
int SeqList<T>::get(int pos, T &t)
{
if (pos< 0)
{
return-1;
}
t =pArray[pos];
return 0;
}
template <typename T>
int SeqList<T>::del(int pos, T &t)
{
if (pos< 0)
{
return-1;
}
t =pArray[pos];
for (int i= pos; i<this->length - 1; i++)
{
pArray[i]= pArray[i + 1];
}
this->length--;
return 0;
}
template <typename T>
int SeqList<T>::clear()
{
this->length= 0;
return 0;
}
测试
#include "iostream"
using namespace std;
#include "SeqList.cpp"
typedef struct Teacher
{
int age;
charname[64];
}Teacher;
void test1()
{
Teacher t1,t2, t3, t4, tmp;
t1.age =11;
t2.age =12;
t3.age =13;
t4.age =14;
SeqList<Teacher>list(10);
list.insert(t1,0);
list.insert(t2,0);
list.insert(t3,0);
list.insert(t4,0);
for (int i= 0; i < list.getLength(); i++)
{
list.get(i,tmp);
cout<< "tmp:age->" << tmp.age << endl;
}
cout<< "清空线性表" << endl;
while(list.getLength()> 0)
{
list.del(0,tmp);
cout<< "tmp:age->" << tmp.age << endl;
}
}
void test2()
{
Teacher t1,t2, t3, t4;
Teacher*p1, *p2, *p3, *p4;
Teacher*tmp = NULL;
tmp = newTeacher;
t1.age =11;
t2.age =12;
t3.age =13;
t4.age =14;
p1 =&t1;
p2 = &t2;
p3 =&t3;
p4 =&t4;
SeqList<Teacher>list(10);
list.insert(*p1,0);
list.insert(*p2,0);
list.insert(*p3,0);
list.insert(*p4,0);
for (int i= 0; i < list.getLength(); i++)
{
list.get(i,*tmp);
cout<< "tmp:age->" << tmp->age << endl;
}
cout<< "清空线性表" << endl;
list.clear();
//*
list.insert(*p1,0);
list.insert(*p2,0);
list.insert(*p3,0);
list.insert(*p4,0);
//*/
while(list.getLength() > 0)
{
list.del(0,*tmp);
cout<< "tmp:age->" << tmp->age << endl;
}
}
void main()
{
test2();
system("pause");
}
2. 链式存储模板库
创建头文件LinkList.h
#pragma once
template <typename T>
struct Node
{
T t;
Node<T>*next;
};
template <typename T>
class LinkList
{
public:
LinkList();
~LinkList();
public:
intclear();
intlength();
intinsert(T &t, int pos);
int get(intpos,T &t);
int del(intpos,T &t);
private:
Node<T>*header;
int len;
};
创建LinkList.cpp
#include "LinkList.h"
template <typename T>
LinkList<T>::LinkList()
{
this->header= new Node<T>;
this->header->next= NULL;
this->len= 0;
}
template <typename T>
LinkList<T>::~LinkList()
{
Node<T>*tmp = NULL;
while(header != NULL)
{
tmp= header->next;
deleteheader;
header= tmp;
}
len = 0;
header =NULL;
}
template <typename T>
int LinkList<T>::clear()
{
Node<T>*tmp = NULL;
while(header != NULL)
{
tmp= header->next;
deleteheader;
header= tmp;
}
header =new Node<T>;
header->next= NULL;
this->len= 0;
return 0;
}
template <typename T>
int LinkList<T>::length()
{
return len;
}
template <typename T>
int LinkList<T>::insert(T &t, int pos)
{
Node<T>*current = NULL;
current =header;
for (int i= 0; i < pos; i++)
{
current= current->next;
}
Node<T>*node = new Node<T>;
if (node ==NULL)
{
return-1;
}
node->t= t;
node->next= NULL;
node->next= current->next;
current->next= node;
len++;
return 0;
}
template <typename T>
int LinkList<T>::get(int pos, T &t)
{
Node<T>*current = NULL;
current =header;
for (int i= 0; i < pos; i++)
{
current= current->next;
}
t =current->next->t;
return 0;
}
template <typename T>
int LinkList<T>::del(int pos, T &t)
{
Node<T>*current = NULL;
Node<T>*ret = NULL;
current =header;
for (int i= 0; i < pos; i++)
{
current= current->next;
}
ret =current->next;
t =ret->t;
current->next= ret->next;
len--;
delete ret;
return 0;
}
测试
#include "iostream"
using namespace std;
#include "LinkList.cpp"
typedef struct Teacher
{
int age;
charname[64];
}Teacher;
void testlinklist1()
{
Teacher t1,t2, t3, t4, tmp;
t1.age =11;
t2.age =12;
t3.age =13;
t4.age =14;
LinkList<Teacher>list = LinkList<Teacher>();
list.insert(t1,0);
list.insert(t2,0);
list.insert(t3,0);
list.insert(t4,0);
for (int i= 0; i < list.length(); i++)
{
list.get(i,tmp);
cout<< "tmp:age->" << tmp.age << endl;
}
cout<< "清空线性表" << endl;
while(list.length() > 0)
{
list.del(0,tmp);
cout<< "tmp:age->" << tmp.age << endl;
}
}
void testlinklist2()
{
Teacher t1,t2, t3, t4;
Teacher*p1, *p2, *p3, *p4;
Teacher*tmp = NULL;
tmp = newTeacher;
t1.age =11;
t2.age =12;
t3.age =13;
t4.age =14;
p1 =&t1;
p2 =&t2;
p3 =&t3;
p4 =&t4;
LinkList<Teacher>list = LinkList<Teacher>();
list.insert(*p1,0);
list.insert(*p2,0);
list.insert(*p3,0);
list.insert(*p4,0);
for (int i= 0; i < list.length(); i++)
{
list.get(i,*tmp);
cout << "tmp:age->"<< tmp->age << endl;
}
cout<< "清空线性表" << endl;
list.clear();
//*
list.insert(*p1,0);
list.insert(*p2,0);
list.insert(*p3,0);
list.insert(*p4,0);
//*/
while(list.length() > 0)
{
list.del(0,*tmp);
cout<< "tmp:age->" << tmp->age << endl;
}
}
void main()
{
testlinklist2();
system("pause");
}
将上述模板类添加元素可复制的功能
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std;
#include "LinkList.cpp"
typedef struct Teacher
{
public:
int age;
charname[64];
char* pdes;
public:
Teacher()
{
age= 0;
memset(name,0, sizeof(name));
pdes= NULL;
}
~Teacher()
{
if(pdes != NULL)
{
free(pdes);
}
}
Teacher(constTeacher &t2)
{
pdes= (char*)malloc(100);
strcpy(this->pdes,t2.pdes);
strcpy(this->name,t2.name);
this->age= t2.age;
}
public:
Teacher& operator=(const Teacher &t2)
{
if(pdes == t2.pdes)
{
return*this;
}
if(pdes != NULL)
{
free(pdes);
pdes= NULL;
}
pdes= (char*)malloc(100);
strcpy(this->pdes,t2.pdes);
strcpy(this->name,t2.name);
this->age= t2.age;
return*this;
}
}Teacher;
void testlinklist1()
{
Teacher t1,t2, t3, t4, tmp;
t1.age =11;
t2.age =12;
t3.age =13;
t4.age =14;
t1.pdes =(char*)malloc(100);
strcpy(t1.pdes,"t1");
t2.pdes =(char*)malloc(100);
strcpy(t2.pdes,"t2");
t3.pdes =(char*)malloc(100);
strcpy(t3.pdes,"t3");
t4.pdes =(char*)malloc(100);
strcpy(t4.pdes,"t4");
LinkList<Teacher>list = LinkList<Teacher>();
list.insert(t1,0);
list.insert(t2,0);
list.insert(t3,0);
list.insert(t4,0);
for (int i= 0; i < list.length(); i++)
{
list.get(i,tmp);
cout<< "tmp:age->" << tmp.age << endl;
}
cout<< "清空线性表" << endl;
while(list.length() > 0)
{
list.del(0,tmp);
cout<< "tmp:age->" << tmp.age << endl;
}
}
void testlinklist2()
{
Teacher t1,t2, t3, t4;
Teacher*p1, *p2, *p3, *p4;
Teacher*tmp = NULL;
tmp = newTeacher;
t1.age =11;
t2.age =12;
t3.age =13;
t4.age =14;
p1 =&t1;
p2 =&t2;
p3 =&t3;
p4 =&t4;
LinkList<Teacher>list = LinkList<Teacher>();
list.insert(*p1,0);
list.insert(*p2,0);
list.insert(*p3,0);
list.insert(*p4,0);
for (int i= 0; i < list.length(); i++)
{
list.get(i,*tmp);
cout<< "tmp:age->" << tmp->age << endl;
}
cout<< "清空线性表" << endl;
list.clear();
//*
list.insert(*p1,0);
list.insert(*p2,0);
list.insert(*p3,0);
list.insert(*p4,0);
//*/
while(list.length() > 0)
{
list.del(0,*tmp);
cout<< "tmp:age->" << tmp->age << endl;
}
}
void main()
{
testlinklist1();
system("pause");
}
3. 栈模板类
使用上述的链式存储模板类
编写LinkStack.h文件
#pragma once
#include "LinkList.h"
template <typename T>
class LinkStack
{
public:
LinkStack();
~LinkStack();
public:
voidclear();
int size();
int push(T&t);
int pop(T&t);
int top(T&t);
private:
LinkList<T>*list;
};
编写LinkStack.cpp文件
#include "LinkStack.h"
template <typename T>
LinkStack<T>::LinkStack()
{
list = new LinkList<T>;
}
template <typename T>
LinkStack<T>::~LinkStack()
{
clear();
deletelist;
list =NULL;
}
template <typename T>
void LinkStack<T>::clear()
{
list->clear();
}
template <typename T>
int LinkStack<T>::size()
{
returnlist->length();
}
template <typename T>
int LinkStack<T>::push(T &t)
{
returnlist->insert(t, 0);
}
template <typename T>
int LinkStack<T>::pop(T &t)
{
returnlist->del(0, t);
}
template <typename T>
int LinkStack<T>::top(T &t)
{
returnlist->get(0, t);
}
测试
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std;
#include "LinkStack.cpp"
typedef struct Teacher
{
public:
int age;
charname[64];
char* pdes;
public:
Teacher()
{
age= 0;
memset(name,0, sizeof(name));
pdes= NULL;
}
~Teacher()
{
if(pdes != NULL)
{
free(pdes);
pdes= NULL;
}
}
Teacher(constTeacher &t2)
{
pdes= (char*)malloc(100);
strcpy(this->pdes,t2.pdes);
strcpy(this->name,t2.name);
this->age= t2.age;
}
public:
Teacher& operator=(const Teacher &t2)
{
if(pdes == t2.pdes)
{
return*this;
}
if(pdes != NULL)
{
free(pdes);
pdes= NULL;
}
pdes= (char*)malloc(100);
if(t2.pdes != NULL)
{
strcpy(this->pdes,t2.pdes);
}
strcpy(this->name,t2.name);
this->age= t2.age;
return*this;
}
}Teacher;
void testlinkstack1()
{
Teacher t1,t2, t3, t4, tmp;
t1.age =11;
t2.age =12;
t3.age =13;
t4.age =14;
LinkStack<Teacher>stack;
stack.push(t1);
stack.push(t2);
stack.push(t3);
stack.push(t4);
cout<< "stack->size:" << stack.size() << endl;
stack.top(tmp);
cout<< "tmp->age:" << tmp.age << endl;
while(stack.size() > 0)
{
stack.pop(tmp);
cout<< "tmp->age:" << tmp.age << " ";
}
cout<< endl;
}
void testlinkstack2()
{
}
void main()
{
testlinkstack1();
system("pause");
}