一、数组(最简单的数据结构)

定义:占据一块连续内存并按照顺序存储数据。创建时先指定大小,分配内存。

优点:时间效率高。实现简单的hash(下标为key,对应的数据为value)

缺点:空间效率差。如果我们只在数组中存一个数字,也先分配所有的内存。

扩展:动态数组(解决空间效率差),手段:扩容后,复制内容到新的数组,释放之前的内存。时间性能变差,因此,要尽量减少改变数组容量的次数。

数组与指针:声明一个数组时,数组名字也是一个指针,指向数组的第一个元素。

例题:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序,请完成一个函数,输入这样一个二维数组和一个整数,判断数组中是否含有整数。

思路:

写一个bool Find(int* matrix, int rows, int columns, int number)函数,将一个矩阵的右上角的值a和这个整数b进行对比.

if(a==b) return true;

else if (a>b) 去掉当前列,在剩下的列中进行查找。

else 去掉当前行,在剩下的行中进行查找。

#include <iostream>
using namespace std;
bool Find(int* matrix, int rows, int columns, int number)
{
bool found = false; if(matrix != NULL&& rows > 0 && columns > 0)
{
int row = 0;
int column = columns - 1;
while(row < rows && column >=0)
{
if(matrix[row * columns + column] == number)
{
found = true;
break;
}
else if(matrix[row * columns + column] > number)
-- column;
else
++ row;
}
} return found;
}
//========测试代码=============
void Test(char * testName, int * matrix, int rows, int columns, int number, bool expected)
{
if(testName != NULL)
printf("%s begins: ",testName);
bool result=Find(matrix, rows, columns, number);
if(result == expected)
printf("Passed.\n");
else
printf("Failed.\n");
}
// 1 2 8 9
// 2 4 9 12
// 4 7 10 13
// 6 8 11 15
// 要查找的数在数组中
void Test1()
{
int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
Test("Test1", (int*)matrix, 4, 4, 7, true);
} // 1 2 8 9
// 2 4 9 12
// 4 7 10 13
// 6 8 11 15
// 要查找的数不在数组中
void Test2()
{
int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
Test("Test2", (int*)matrix, 4, 4, 5, false);
} // 1 2 8 9
// 2 4 9 12
// 4 7 10 13
// 6 8 11 15
// 要查找的数是数组中最小的数字
void Test3()
{
int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
Test("Test3", (int*)matrix, 4, 4, 1, true);
} // 1 2 8 9
// 2 4 9 12
// 4 7 10 13
// 6 8 11 15
// 要查找的数是数组中最大的数字
void Test4()
{
int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
Test("Test4", (int*)matrix, 4, 4, 15, true);
} // 1 2 8 9
// 2 4 9 12
// 4 7 10 13
// 6 8 11 15
// 要查找的数比数组中最小的数字还小
void Test5()
{
int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
Test("Test5", (int*)matrix, 4, 4, 0, false);
} // 1 2 8 9
// 2 4 9 12
// 4 7 10 13
// 6 8 11 15
// 要查找的数比数组中最大的数字还大
void Test6()
{
int matrix[][4] = {{1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}};
Test("Test6", (int*)matrix, 4, 4, 16, false);
} // 鲁棒性测试,输入空指针
void Test7()
{
Test("Test7", NULL, 0, 0, 16, false);
}
void main()
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();
}

java代码:

public class Find {

    public Find() {
// TODO Auto-generated constructor stub
}
public boolean find(int[][] a,int b,int rows,int columns){
if(a==null||rows<0||columns<0)
return false;
int row=0,column=columns-1;
while(row<rows&&column>=0){
if(a[row][column]==b)
return true;
else if(a[row][column]<b)
column--;
else
row++;
}
return false;
} }

二.字符串

定义:若干字符组成的序列

c++/c与Java中字符串的对比:c/c++中每个字符串都是以'\0'作为结尾;Java中却不是这样的,Java中的一切都是对象,对象有长度,编译器可以确定输出的字符个数。

题目:请实现一个函数,把字符串中的每一个空格替换成'%20',例如,输入为"we are happy",则输出为:"we%20are%20happy"

思路:要弄清楚两点:第一,在原串上面干,字符串的长度变长。第二,在新串上面干,自己分配足够地内存。

从头开始遍历字符串,在插入字符后,后面的字符会后移。因此我们采用从后面开始遍历。

先遍历一次字符串,统计字符串中空格的总数,计算替换后字符串的总长度。用指针p1和p2分别指向原字符串的尾部和替换后字符串的尾部。

#include <iostream>
using namespace std; void ReplaceBlank(char string[],int length)
{
if(string==NULL||length<=0)
return ;
int originalLength=0;
int numberOfBlank=0;
int i=0;
while(string[i]!='\0')
{
++ originalLength;
if(string[i]==' ')
++numberOfBlank;
++i;
}
int newLength=originalLength+numberOfBlank*2;
if(newLength>length)
{
return;
}
int indexOfOriginal=originalLength;
int indexOfNew=newLength;
while(indexOfOriginal>=0&&indexOfOriginal<indexOfNew)
{
if(string[indexOfOriginal]==' ')
{
string[indexOfNew--]='0';
string[indexOfNew--]='2';
string[indexOfNew--]='%';
}
else
string[indexOfNew--]=string[indexOfOriginal];
--indexOfOriginal;
}
}
void Test(char* testName, char string[], int length, char expected[])
{
if(testName != NULL)
printf("%s begins: ", testName); ReplaceBlank(string, length); if(expected == NULL && string == NULL)
printf("passed.\n");
else if(expected == NULL && string != NULL)
printf("failed.\n");
else if(strcmp(string, expected) == 0)
printf("passed.\n");
else
printf("failed.\n");
} // 空格在句子中间
void Test1()
{
const int length = 100; char string[length] = "hello world";
Test("Test1", string, length, "hello%20world");
} // 空格在句子开头
void Test2()
{
const int length = 100; char string[length] = " helloworld";
Test("Test2", string, length, "%20helloworld");
} // 空格在句子末尾
void Test3()
{
const int length = 100; char string[length] = "helloworld ";
Test("Test3", string, length, "helloworld%20");
} // 连续有两个空格
void Test4()
{
const int length = 100; char string[length] = "hello world";
Test("Test4", string, length, "hello%20%20world");
} // 传入NULL
void Test5()
{
Test("Test5", NULL, 0, NULL);
} // 传入内容为空的字符串
void Test6()
{
const int length = 100; char string[length] = "";
Test("Test6", string, length, "");
} //传入内容为一个空格的字符串
void Test7()
{
const int length = 100; char string[length] = " ";
Test("Test7", string, length, "%20");
} // 传入的字符串没有空格
void Test8()
{
const int length = 100; char string[length] = "helloworld";
Test("Test8", string, length, "helloworld");
} // 传入的字符串全是空格
void Test9()
{
const int length = 100; char string[length] = " ";
Test("Test9", string, length, "%20%20%20");
} int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();
Test8();
Test9(); return 0;
}

Java代码:

public class ReplaceBlank {

    public ReplaceBlank() {
// TODO Auto-generated constructor stub
}
public String replaceBlank(String s){
if(s==null)
return null;
s=s.replaceAll(" ", "%20");
return s;
}
public static void main(String[] args){
String s="a b c d ed";
ReplaceBlank rb=new ReplaceBlank();
String s1=rb.replaceBlank(s);
System.out.println(s1);
}
}

相关例题:有两个排序的数组A1和A2,内存在A1的末尾有足够的多余的空间来容纳A2,请实现一个函数,把A2中地所有的数字插入到A1中并且所有的数字是排序的。

思路:同样是定义两个指针p1和p2,分别指向字数组A1和A2尾端,sp1和sp2,分别指向数组A1和A2的头部。并且设置一个指针p3指向合并后的字符串(即:A1数组)的尾端。

当满足p1>sp1和p2>sp2的同时。if(*p1>=*p2)*p3=*p1;else *p3=*p2;之后,当满足p1>sp1,*p3=*p1;当满足p2>sp2,*p3=*p2。

//合并数组
#include <stdio.h>
void mergaMatrix(int* matrix1,int* matrix2,
                 int lenofmtrx1,int lenofmtrx2,int sizeofmatrix1)
{
    if(sizeofmatrix1 != 0 && matrix1 != NULL && lenofmtrx1 !=0 
        &&  matrix2 != NULL && lenofmtrx2 != 0 ) 
    {
        int* pNewMatrix1 = matrix1 + lenofmtrx1 + lenofmtrx2 -1;
        int* pMatrix1 = matrix1 + lenofmtrx1 - 1;
        int* pMatrix2 = matrix2 +lenofmtrx2 - 1;
  
        while(pMatrix1 >= matrix1 && pMatrix2 >= matrix2)
        {
            if(*pMatrix1 >= *pMatrix2)
                *pNewMatrix1-- = *pMatrix1--;
            else
                *pNewMatrix1-- = *pMatrix2--;
        }
        while(pMatrix1 >= matrix1)
        {
            *pNewMatrix1-- = *pMatrix1--;
        }
        while(pMatrix2 >= matrix2)
        {
            *pNewMatrix1-- = *pMatrix2--;
        }
    }
    return;
}
  
//单元测试
void test(int* matrix1,int* matrix2,
          int lenofmtrx1,int lenofmtrx2,int sizeofmatrix1)
{
    if(matrix1 != NULL)
    {
        for( int i=0; i<lenofmtrx1;i++)
        {
            printf("%d ",*(matrix1+i));
        }
    }
    printf("\n");
    if(matrix2 != NULL){
        for( int i=0; i<lenofmtrx2;i++)
        {
            printf("%d ",*(matrix2+i));
        }
    }
    printf("\n");
    mergaMatrix(matrix1,matrix2,lenofmtrx1,lenofmtrx2,sizeofmatrix1);
    for( int i=0; i<lenofmtrx1+lenofmtrx2;i++)
    {
        printf("%d ",*(matrix1+i));
    }
    printf("\n");
}
//一般情况
void test1()
{
    const int sizeofmatrix1 = 100;
    int lenofmtrx1 = 3;
    int matrix1[sizeofmatrix1] = {1,3,5};
    int lenofmtrx2 = 4;
    int matrix2[] = {2,4,6,8};
    test(matrix1,matrix2,lenofmtrx1,lenofmtrx2,sizeofmatrix1);
}
//其中一个数组的书全部小于另外一个
void test2()
{
    const int sizeofmatrix1 = 100;
    int lenofmtrx1 = 3;
    int matrix1[sizeofmatrix1] = {1,3,5};
    int lenofmtrx2 = 4;
    int matrix2[] = {6,7,8,9};
    test(matrix1,matrix2,lenofmtrx1,lenofmtrx2,sizeofmatrix1);
}
//其中一个为空
void test3()
{
    const int sizeofmatrix1 = 100;
    int lenofmtrx1 = 3;
    int matrix1[sizeofmatrix1] = {1,3,5};
    test(matrix1,NULL,lenofmtrx1,0,sizeofmatrix1);
}
//两个都为空
void test4()
{
    const int sizeofmatrix1 = 100;
    test(NULL,NULL,0,0,sizeofmatrix1);
}
int main()
{
    test1();
    test2();
    test3();
    test4();
    return 0;
}

Java代码:

import java.util.Arrays;
public class Merge { public Merge() {
// TODO Auto-generated constructor stub
}
public void mergeArray(int[] a,int b[]){
if(a==null||b==null)
return;
int[] c=new int[a.length+b.length];
int k=0;
for(int i=0;i<a.length;i++){
c[k++]=a[i];
}
for(int j=0;j<b.length;j++){
c[k++]=b[j];
}
Arrays.sort(c);
for(int z:c){
System.out.print(z+" ");
}
}
public static void main(String[] args)
{
int[] a={2,4,6};
int[] b={3,5,7,9}; Merge m=new Merge();
m.mergeArray(a, b);
}
}

三.链表(创建,尾部添加,删除,打印(从头到尾),打印(从尾到头(stack),打印从尾到头(递归(会导致栈溢出))面试中最频繁的数据结构。

定义:由指针把若干个节点链接成链状的结构。

例题:从尾到头打印一个链表。

思路:

1.创建链表返回头指针ListNode* createLink(int a[],int k)(初始化头指针Head和行动指针p,当满足当前长度小于链表的长度时。创建一个节点pNew并赋初值,if(Head==NULL){Head=pNew;p=pNew;}else{p->next=pNew;p=p->next;})。

2.尾部添加无返回值void addTail(ListNode** Head,int value)(用到了指针的指针ListNode**head,创建一个节点pNew并赋初值。if(*Head==NULL){*Head=pNew;else创建行动指针p并指向头结点,找到插入节点的头一个接点,在它的后面插入节点。})。

3.删除一个已知值的节点返回空,void removeNode(ListNode** Head,int value)(同样用到指针的指针,if(Head==NULL&&*Head==NULL)初始化要删除的指针toBeDelete,if(*Head==value){toBeDelete=*Head,*Head=*Head->next)},else,初始化行动指针p并指向头指针,找到要删除的节点的头一个节点p,if(p->next!=null&&p->next->value==value){ toBeDelete=p->next,p-next=p->next->next}。)

4.打印(从头到尾)返回空,void printLink(ListNode* pHead)(初始化行动指针p并指向头节点,当满足p不为空的时候,输出p->value,并且移动p=p->next)

5.打印(从尾到头(栈))返回空,void printLinkReservese(ListNode* pHead)(定义一个栈 std::stack<ListNode *>nodes,初始化行为指针p并指向头节点,当满足p不为空时,将nodes.push(p),并且移动p=p->next;当nodes.empty不为空时,将行为指针指向顶并且输出p->value,nodes.pop();)

6.打印(从尾到头(递归)),返回空。void printLinkReservese_Recurse(ListNode *pHead)(if(pHead!=NULL){if(pHead->next!=NULL) printLinkReservse_Reservese_Recurse(pHead->next);}输出pHead->value.)

#include<iostream.h>
#include <stdio.h>
#include <stack>
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
void RemoveNode(ListNode ** pHead,int value)
{
if(pHead==NULL||*pHead==NULL)
return;
ListNode* toBeDelete=NULL;
if((*pHead)->m_nValue==value)
{
toBeDelete=*pHead;
*pHead=(*pHead)->m_pNext;
}
else
{
ListNode*p=*pHead;
while(p->m_pNext!=NULL&&p->m_pNext->m_nValue!=value)
p=p->m_pNext;
if(p->m_pNext!=NULL&&p->m_pNext->m_nValue==value)
{
toBeDelete=p->m_pNext;
p->m_pNext=p->m_pNext->m_pNext;
}
//这一步很重要,防止操作已经释放的内存空间
if(toBeDelete!=NULL)
{
delete toBeDelete;
toBeDelete=NULL;
}
}
}
void AddToTail(ListNode ** pHead,int value)
{
ListNode * pNew=new ListNode();
pNew->m_nValue=value;
pNew->m_pNext=NULL; if(*pHead==NULL)
{
*pHead=pNew;
}
else
{
ListNode * pNode = *pHead;
while(pNode->m_pNext != NULL)
pNode=pNode->m_pNext;
pNode->m_pNext=pNew;
}
} ListNode * CreateLink(int a[],int k)
{
ListNode * Head=NULL,*q=NULL;
for(int i=0;i<k;i++)
{
ListNode * pNew=new ListNode();
pNew->m_nValue=a[i];
pNew->m_pNext=NULL; if(Head==NULL)
{
Head=pNew;
q=pNew;
}
else
{
q->m_pNext=pNew;
q=q->m_pNext;
}
}
return Head;
}
//从头到尾打印列表
void printLink(ListNode * pHead)
{
ListNode *p=pHead;
while(p)
{
cout<<p->m_nValue<<" ";
p=p->m_pNext;
}
cout<<endl;
}
//从尾到头打印链表(用栈)。
void PrintListReversesingly_Iteratively(ListNode * pHead)
{
std::stack<ListNode *> nodes;
ListNode *p=pHead;
while(p)
{
nodes.push(p);
p=p->m_pNext;
}
while(!nodes.empty())
{
p=nodes.top();
cout<<p->m_nValue<<" ";
nodes.pop();
}
}
//从尾到头打印链表(用递归,隐式调用栈)。
void printListReversesingly_Recursively(ListNode * pHead)
{
if(pHead!=NULL)
{
if(pHead->m_pNext!=NULL)
{
printListReversesingly_Recursively(pHead->m_pNext);
}
}
cout<<pHead->m_nValue<<" "; } void main()
{
int a[]={1,2,3};
ListNode * Head=CreateLink(a,3);
printLink(Head); AddToTail(&Head,6);
printLink(Head);
printListReversesingly_Recursively(Head);
cout<<endl;
RemoveNode(&Head,3); printLink(Head);
PrintListReversesingly_Iteratively(Head);
cout<<endl; }

java代码实现:

import java.util.Stack;

public class Link {
public class LinkNode{
int m_nVlaue;
LinkNode m_pNext;
}
//创建链表
public LinkNode createLink(int[] a){
if(a==null){
return null;
}
LinkNode pHead=null,p=null;
for(int i=0;i<a.length;i++){
LinkNode pNode=new LinkNode();
pNode.m_nVlaue=a[i];
if(pHead==null){
pHead=pNode;
p=pHead;
}
else{
p.m_pNext=pNode;
p=p.m_pNext;
}
}
return pHead; }
//删除一个节点
public LinkNode deleteLinkNode(LinkNode pHead,int value){
if(pHead==null)
return pHead; if(pHead.m_nVlaue==value)
{
pHead=pHead.m_pNext;
}
LinkNode p=pHead;
while(p.m_pNext!=null&&p.m_pNext.m_nVlaue!=value){
p=p.m_pNext;
}
if(p.m_pNext!=null&&p.m_pNext.m_nVlaue==value)
{ p.m_pNext=p.m_pNext.m_pNext;
}
return pHead; }
public void addTail(LinkNode pHead,int value){
LinkNode pNew=new LinkNode();
pNew.m_nVlaue=value;
pNew.m_pNext=null;
LinkNode pNode=pHead; if(pHead==null)
pHead=pNew; while(pNode.m_pNext!=null){
pNode=pNode.m_pNext;
}
pNode.m_pNext=pNew; }
//逆序打印链表
public void printLinkReservse(LinkNode pHead){
if(pHead==null)
return;
Stack<Integer> stack=new Stack<Integer>();
while(pHead!=null){
stack.push(pHead.m_nVlaue);
pHead=pHead.m_pNext;
}
while(!stack.isEmpty()){
int a=stack.peek();
System.out.print(a+" ");
stack.pop();
}
}
public static void main(String[] args){
int[] a={3,4,6,7,8,9,0};
Link link=new Link();
LinkNode pHead=link.createLink(a);
link.printLinkReservse(pHead);
pHead=link.deleteLinkNode(pHead,3);
link.printLinkReservse(pHead);
link.addTail(pHead, 10);
link.printLinkReservse(pHead);
} }

四.树(二叉树(创建,打印,删除))

定义:除了根节点之外,每个结点都有一个父节点,除了叶子节点外所有的节点都有一个或者多个子节点。

二叉树:每个节点最多有两个叶子节点

遍历:按照某个顺序访问树中的所有节点。

三种常见的遍历:前序遍历,中序遍历,后续遍历(可以用递归和循环两种方式实现)

可实现的题目:二叉树的深度,树的子结构,二叉树的后续遍历。从上到下遍历二叉树(宽度优先遍历)。

二查搜索树:左子结点总是小于等于根节点,而右子节点总是大于等于根节点。找到一个节点的平均时间为O(logn)

二叉树特例:堆和红黑二叉树堆:最大堆和最小堆。可以解决(快速找最大值和最小值问题)

红黑树:将树中的节点定义为红、黑两种颜色,通过规则确保从根节点到叶子节点的最长路径不超过最短路径的两倍。在C++ 中的STL(Standard Template libary(标准模板库),set,multiset,map,multimap等数据结构都是基于红黑树实现的。)

重建二叉树

题目:输入某个二叉树的前序遍历和中序遍历的结果,重建该二叉树,假设输入前序和中序遍历的结果中没有重复的数字。例如:输出得 前序遍历为{1,2,4,7,3,5,6,8}和中序遍历{4,7,2,1,5,3,8,6},重建二叉树。

思路:

1.创建二叉树,返回值为BinaryTreeNode *,BinaryTreeNode* construct(int* preorder,int* inorder,int length)(如果前序遍历和中序遍历的头指针都不空,及length大于0,则调用函数BinaryTreeNode *ConstructCore(int*startPreorder,int*endPreorder,int*startInorder,int*endInorder)(首先将前序遍历的第一个值赋值给rootValue,初始化根节点,if(startPreorder==endPreorder){if(startInorder==endInorder&&*startPreorder==*startInorder) return root;else 抛空异常。) 据中序遍历找到根节点。定义一个行动指针指p向中序遍历的头结点。当满足p<=endInorder时,找到根节点(root),分别求出左、右子树的长度leftLength和rightLength,当leftLength和rightLength不为零时,分别创建左右子树。root->left=调用ConstructCore函数,root->right=调用ConstructCore函数。

2.打印二叉树。无返回值。首先创建要打印一个节点的函数void printTreeNode(BinaryTreeNode* pNode)(当pNode不为空时,打印pNode的值,如果pNode->left为空,打印pNode->left->value,右指针同左指针一样操作。else 抛空。),然后再创建一个函数,返回值为空。void PrintTree(BinaryTreeNode *root){如果根节点不 为空打印根节点的值,左指针不为空,递归打印左子树。右指针同理。}。

3.删除二叉树。无返回值。函数void DeleteNode(BinaryTreeNode* pRoot){如果pRoot不为空,则将左右指针分别赋值给一个新的指针,然后删除pRoot,并且置空。递归删除左右子树。}

#include <stdio.h>
#include <iostream>
using namespace std;
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight; };
BinaryTreeNode* ConstructCore(int* startPreorder,int* endPreorder,int* startInorder,int* endInorder)
{
int rootValue=startPreorder[0];
BinaryTreeNode* root=new BinaryTreeNode();
root->m_nValue=rootValue;
root->m_pLeft=root->m_pRight=NULL;
if(startPreorder==endPreorder)
{
if(startInorder==endInorder&&*startPreorder==*startInorder)
{
return root;
}
else
throw std::exception("Invalid put!");
}
//通过中序遍历序列找到根节点
int* rootInorder=startInorder;
while(rootInorder<=endInorder&&*rootInorder!=rootValue)
{
++rootInorder;
}
if(rootInorder==endInorder&&*rootInorder!=rootValue)
{
throw std::exception("Invalid put");
}
int leftLength=rootInorder-startInorder;
int rightLength=endInorder-rootInorder;
int* leftPreorderEnd=startPreorder+leftLength;
if(leftLength>0)
{
//递归构建左子树
root->m_pLeft=ConstructCore(startPreorder+1,leftPreorderEnd,startInorder,rootInorder-1);
}
if(rightLength>0)
{
//递归构建右子树
root->m_pRight=ConstructCore(leftPreorderEnd+1,endPreorder,rootInorder+1,endInorder);
}
return root; }
BinaryTreeNode* Construct(int* preorder,int* inorder,int length)
{
if(preorder==NULL||inorder==NULL||length<=0)
{
throw std::exception("Invalid put!");
}
return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
} void PrintTreeNode(BinaryTreeNode* pNode)
{
if(pNode != NULL)
{
printf("value of this node is: %d\n", pNode->m_nValue); if(pNode->m_pLeft != NULL)
printf("value of its left child is: %d.\n", pNode->m_pLeft->m_nValue);
else
printf("left child is null.\n"); if(pNode->m_pRight != NULL)
printf("value of its right child is: %d.\n", pNode->m_pRight->m_nValue);
else
printf("right child is null.\n");
}
else
{
printf("this node is null.\n");
} printf("\n");
}
//递归打印左右子树
void PrintTree(BinaryTreeNode* pRoot)
{
PrintTreeNode(pRoot); if(pRoot != NULL)
{
if(pRoot->m_pLeft != NULL)
PrintTree(pRoot->m_pLeft); if(pRoot->m_pRight != NULL)
PrintTree(pRoot->m_pRight);
}
}
//递归删除左右子树
void DestroyTree(BinaryTreeNode* pRoot)
{
if(pRoot != NULL)
{
BinaryTreeNode* pLeft = pRoot->m_pLeft;
BinaryTreeNode* pRight = pRoot->m_pRight; delete pRoot;
pRoot = NULL; DestroyTree(pLeft);
DestroyTree(pRight);
}
} void main()
{
const int length = 8;
int preorder[length] = {1, 2, 4, 7, 3, 5, 6, 8};
int inorder[length] = {4, 7, 2, 1, 5, 3, 8, 6}; BinaryTreeNode *root = Construct(preorder, inorder, length);
PrintTree(root);
DestroyTree(root);
}

java代码:

public class CreateBiTree {

        public class BiNode{
int m_nValue;
BiNode m_pLeft;
BiNode m_pRight;
}
public BiNode constructBiTree(int[] a,int start,int[] b,int end,int length){
if(a==null||b==null||a.length!=b.length||length<0)
return null;
int value=a[start];
BiNode pNode=new BiNode();
pNode.m_nValue=value;
pNode.m_pLeft=pNode.m_pRight=null;
if(length==1&&a[start]==b[end]){
return pNode;
}
//根据中序遍历的结果,找到根节点
int i=0;
while(i<length){
if(b[end-i]==value)
break;
i++;
}
if(i==length)
throw new RuntimeException("inVaild put!");
int right=i;
int left=length-i-1;
if(right>0)
pNode.m_pRight=constructBiTree(a,start+length-i,b,end,i);
if(left>0)
pNode.m_pLeft=constructBiTree(a,start+1,b,end-i-1,length-i-1);
return pNode;
}
public void printNode(BiNode pNode){
if(pNode==null)
System.out.println("this node is null");
else
System.out.println("this node is:"+pNode.m_nValue);
if(pNode.m_pLeft==null)
System.out.println("this left node is null");
else
System.out.println("this left node is:"+pNode.m_pLeft.m_nValue);
if(pNode.m_pRight==null)
System.out.println("this right node is null");
else
System.out.println("this right node is:"+pNode.m_pRight.m_nValue);
}
//打印二叉树
public void printBiTree(BiNode pNode){
printNode(pNode);
if(pNode.m_pLeft!=null)
printBiTree(pNode.m_pLeft);
if(pNode.m_pRight!=null)
printBiTree(pNode.m_pRight);
}
public static void main(String[] args){
int[] a={1,8,3,5,7,9,10};
int[] b={3,8,5,1,9,7,10};
CreateBiTree bt=new CreateBiTree();
BiNode root=bt.constructBiTree(a,0,b,6,7);
bt.printBiTree(root);
} }

五.栈与队列

栈定义:用来存储函数调用时各个函数的参数,返回地址及临时变量等。

特点:先进后出,不考虑排序。

队列特点:先进先出。

题目:用两个栈实现一个队列,队列申明如下,实现它的两个函数appendTail和deleteHead,即:队列的尾部插入节点,头部删除节点。

思路:自定义一个函数模板CQueue,它有public属性或方法:构造函数,析构函数,在尾部添加节点void appendTail(const T& node),删除队列的头节点T deleteHead().私有属性:stack<T> stack1;stack<T>stack2;由于定义CQueue,为模板的原因,在尾部添加节点实现函数为:template< typename T> void cQueue<T>::appendTail(const T& node){stack1.push(node)},删除队列头部的节点template<T> T cQueue<T> ::deleteHead()如果stack2<=0,当stack1.size()满足大于0时,将stack1,中的所有元素压入stack2.如果stack2==0,抛空。定义一个T类型的head并且赋初值为stack2.top,stack2.pop(),返回Head。

#include <iostream>
#include <stack>
#include <exception>
using namespace std; template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue(void); // 在队列末尾添加一个结点
void appendTail(const T& node); // 删除队列的头结点
T deleteHead(); private:
stack<T> stack1;
stack<T> stack2;
}; //成员函数定义.
template <typename T>
CQueue<T>::CQueue(void)
{
} template <typename T>
CQueue<T>::~CQueue(void)
{
} //向队列中插入元素.
template <typename T>
void CQueue<T>::appendTail(const T& node)
{
stack1.push(node);
} //从队列中删除元素.
template <typename T>
T CQueue<T>::deleteHead()
{
//先判断stack2是否为空.
//若其不为空,则从中弹出元素;
//若为空,则将stack1中元素依次弹出并存入stack2中.
if(stack2.size() <= 0)
while (stack1.size() > 0)
{//当stack2为空时,将stack1中所有元素存入stack2中.
T data = stack1.top();
stack1.pop();
stack2.push(data);
}
if(stack2.size() == 0)
throw new exception("queue is empty!"); T head = stack2.top();
stack2.pop(); return head;
} //测试函数.
void Test(char actual, char expected)
{
if(actual == expected)
cout << "Test passed." << endl;
else
cout << "Test failed.\n" << endl;
} int main()
{
CQueue<char> queue; queue.appendTail('a');
queue.appendTail('b');
queue.appendTail('c'); char head = queue.deleteHead();
Test(head, 'a'); head = queue.deleteHead();
Test(head, 'b'); queue.appendTail('d');
head = queue.deleteHead();
Test(head, 'c'); queue.appendTail('e');
head = queue.deleteHead();
Test(head, 'd'); head = queue.deleteHead();
Test(head, 'e'); return 0;
}

Java代码:

import java.util.Stack;

public class TwoStackToQueue<T> {
Stack<T> stack1=new Stack<T>();
Stack<T> stack2=new Stack<T>();
public void addTail(T item)
{
stack1.push(item);
}
public T deleteHead(){
if(stack2.isEmpty()){
if(!stack1.isEmpty()){
while(!stack1.isEmpty()){
T data=stack1.peek();
stack1.pop();
stack2.push(data);
}
} }
if(stack2.isEmpty())
throw new RuntimeException("inVaild put");
T data=stack2.peek();
stack2.pop();
return data;
}
public static void main(String[] args){
TwoStackToQueue<Integer> queue=new TwoStackToQueue<Integer>();
queue.addTail(3);
queue.addTail(4);
queue.addTail(5);
int data=(int)queue.deleteHead();
System.out.println(data+" "); }
}

剑指offer-第二章数据结构(数组,字符串,链表,树,栈与队列)及例题的更多相关文章

  1. 剑指offer第二章

    剑指offer第二章 1.二维数组中的查找 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含 ...

  2. 《剑指offer》第九题(用两个栈实现队列)

    // 面试题:用两个栈实现队列 // 题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail // 和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的 ...

  3. 剑指offer 面试题9:用两个栈实现队列

    题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 使用栈实现队列的下列操作:push(x) -- 将一个元素放入队列的尾部.pop() -- 从队列首部移 ...

  4. 剑指offer—第二章算法之二分查找(旋转数组的最小值)

    旋转数组的最小数字 题目:把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如:数组{3,4,5,1,2}为{1,2,3,4, ...

  5. 剑指offer第二版-3.数组中重复的数

    面试题3:数组中重复的数 题目要求: 在一个长度为n的数组中,所有数字的取值范围都在[0,n-1],但不知道有几个数字重复或重复几次,找出其中任意一个重复的数字. 解法比较: /** * Copyri ...

  6. 剑指offer—第二章算法之快速排序

    算法:排序和查找(二分查找,归并排序,快速排序),位运算等. 查找:顺序查找,哈希查找,二叉排序树查找,哈希表. 二分查找可以解决:"旋转数组中的最小数字","数字在排序 ...

  7. 剑指offer:按之字形打印二叉树(栈|双向队列+中序遍历)

    1. 题目描述 /** 请实现一个函数按照之字形打印二叉树, 即第一行按照从左到右的顺序打印, 第二层按照从右至左的顺序打印, 第三行按照从左到右的顺序打印, 其他行以此类推. */ 2. 双向队列 ...

  8. 《剑指offer》面试题7 用两个栈实现队列 Java版

    书中方法:队列是先进先出的,栈是先进后出的,试想把一串数压入A栈,接着一个个出栈并压入B栈,便会完成"头在下"到"头在上"的转变.B栈内还有元素时,直接出栈表示 ...

  9. 剑指Offer面试题:6.用两个栈实现队列

    一.题目:用两个栈实现队列 题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能. 原文是使用 ...

  10. 【剑指offer 面试题7】用两个栈实现队列

    #include <iostream> #include <stack> using namespace std; template <typename T> cl ...

随机推荐

  1. poj 3253超时

    哈夫曼树超时是因为每次都需要重排,十分浪费时间,即使是快排.

  2. centos/linux扩容Swap分区

    查看现在的swap容量 [root@node1 ~]# free -h total used free shared buff/cache available Mem: 15G 3.8G 2.1G 5 ...

  3. unbntu修改mac地址

    分享下Ubuntu下更改MAC地址的简单方法: 首先把网卡设备给 down 掉,否则会报告系统忙,无法更改. sudo ifconfig eth0 down 然后修改 MAC 地址,这一步较 Wind ...

  4. spark数据监控实战

    版权申明:转载请注明出处.文章来源:http://bigdataer.net/?p=248 排版乱?请移步原文获得更好的阅读体验   1.概述 数据准确性,稳定性,时效性是数据开发中需要重点关注的,一 ...

  5. postman(谷歌) httprequester(火狐)

    http://www.cnblogs.com/s380774061/p/4624326.html @an http://www.tuicool.com/articles/67Rnaej 测试文档券栈 ...

  6. hdu 2126 Buy the souvenirs 二维01背包方案总数

    Buy the souvenirs Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  7. scala学习手记25 - Curry化

    curry翻译为中文就是咖喱.意为使用curry可以让代码更有味道. scala里的curry化可以把函数从接收多个参数转换成接收多个参数列表.也就是说我们要编写的函数不是只有一个参数列表,这个参数列 ...

  8. ubantu中让g++支持c++11的办法

    g++ main.cpp -std=c++11 -o a 其中: main.cpp是要编译的源文件 a是编译后的文件名 注意-std=c++11不要写成-std=c11

  9. HTTP Status 500 - javax.el.PropertyNotFoundException: Property 'lkmId' not found on type cn.itcast.entity.LinkMan

    报错 type Exception report message javax.el.PropertyNotFoundException: Property 'lkmId' not found on t ...

  10. d2.js学习笔记(七)——动态SVG坐标空间

    目标 在这一章,我们将学习如何使SVG坐标空间是动态的,这样我们的数据可视化不论数据是什么,都始终是可见的. 我们会使得SVG坐标空间尺度上调或下调来适于我们的数据. 三个SVG长方形 我们就从三个长 ...