1、栈和队列的区别
栈是限定只能在表的一端进行插入和删除操作的线性表。
队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。
1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap。
2.HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以).。
3.HashTable有一个contains(Object value),功能和containsValue(Object value)功能一样。
4.HashTable使用Enumeration,HashMap使用Iterator。 以上只是表面的不同,它们的实现也有很大的不同。
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
而HashMap重新计算hash值,而且用与代替求模:
单链表:链表有头指针和结束指针。
双向链表:一个元素有两个指针,一个是指向前一个元素,另一个是指向后一个元素。
6、描述下二叉树和二叉树的插入与删除
7、static的作用
1)隐藏功能,对于static修饰的函数和全局变量而言
2)保持持久性功能,对于static修饰的局部变量而言
首先保证代码质量。
其次保证代码的可维护。
上述解法当数组中元素的值比较大但数组大小较小时,在很大程度上造成空间的浪费。所以对上述解法改进,采用Hash表判断某个元素是否已经出现过。
栈是限定只能在表的一端进行插入和删除操作的线性表。
队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。
除了它们各自的基本操作集不同外,主要区别是对插入和删除操作的"限定"。 栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出"的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。
栈的基本操作除了在栈顶进行插入或删除外,还有栈的初始化、判空及取栈顶元素等。
1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap。
2.HashTable不允许null值(key和value都不可以),HashMap允许null值(key和value都可以).。
3.HashTable有一个contains(Object value),功能和containsValue(Object value)功能一样。
4.HashTable使用Enumeration,HashMap使用Iterator。 以上只是表面的不同,它们的实现也有很大的不同。
5.HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
6.哈希值的使用不同,HashTable直接使用对象的hashCode,代码是这样的:int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
而HashMap重新计算hash值,而且用与代替求模:
int hash = hash(k);
int i = indexFor(hash, table.length);
static int hash(Object x) {
int h = x.hashCode();
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
static int indexFor(int h, int length) {
return h & (length-1);
}
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。
单链表:链表有头指针和结束指针。
双向链表:一个元素有两个指针,一个是指向前一个元素,另一个是指向后一个元素。
单链表和双链表查找第一个元素的时间复杂度都是O(1),查找最后一个元素时单链表时间复杂度是O(n),双向链表时间复杂度是O(1)。
#include <iostream>
#include <vector>
using namespace std;
// 链表结构
struct List
{
int data;
struct List *next;
};
// 创建链表
void CreateList(List *&head)
{
for(int i = 0; i < 10; i++)
{
List *node = new List();
node->data = i;
node->next = head->next;
head->next = node;
}
}
// 逆序输出链表
void DisplayListReverse(const List *head)
{
if(head != NULL)
{
vector<int> ivec;
List *p = head->next;
while(p)
{
ivec.push_back(p->data);
p = p->next;
}
for(int i = ivec.size() - 1; i >= 0; --i)
{
cout << ivec[i] << " ";
}
cout << endl;
}
else
{
cout << "List is empty!" << endl;
}
}
int main()
{
List *head = new List();
CreateList(head);
DisplayListReverse(head);
return 0;
}
6、描述下二叉树和二叉树的插入与删除
// Tree.h
#include <iostream>
using namespace std;
#ifndef _TREE_H_
#define _TREE_H_
template <class TYPE>
class Tree
{
public:
Tree();
bool insert(const TYPE &x);
bool search(const TYPE &x) const;
bool del(const TYPE &x);
void display() const;
private:
struct TreeNode
{
TYPE data;
TreeNode *left;
TreeNode *right;
};
TreeNode *root;
bool insert(TreeNode *&root, const TYPE &x);
bool search(const TreeNode *root, const TYPE &x) const;
bool del(TreeNode *&root, const TYPE &x);
void display(TreeNode *root) const;
};
#endif
template <class TYPE>
Tree<TYPE>::Tree()
{
root = NULL;
}
template <class TYPE>
bool Tree<TYPE>::insert(const TYPE &x)
{
return insert(root, x);
}
template <class TYPE>
bool Tree<TYPE>::insert(TreeNode *&root, const TYPE &x)
{
if(root == NULL)
{
root = new TreeNode;
root->left = NULL;
root->right = NULL;
root->data = x;
return true;
}
else if(root->data == x)
return false;
else if(root->data > x)
return insert(root->left, x);
else
return insert(root->right, x);
}
template <class TYPE>
bool Tree<TYPE>::del(const TYPE &x)
{
return del(root, x);
}
template <class TYPE>
bool Tree<TYPE>::del(TreeNode *&root, const TYPE &x)
{
if(root == NULL)
{
return false;
}
else if(root != NULL && root->data == x)
{
TreeNode* oldNode = root;
if(root->left == NULL)
{
if(root->right == NULL)
{
root = NULL;
oldNode = NULL;
delete root;
delete oldNode;
return true;
}
else
{
oldNode = NULL;
root = root->right;
root->right = root->right;
delete oldNode;
return true;
}
}
else if(root->right == NULL)
{
if(root->left == NULL)
{
root = NULL;
oldNode = NULL;
delete oldNode;
delete root;
return true;
}
else
{
oldNode = NULL;
root = root->left;
root->left = root->left;
delete oldNode;
return true;
}
}
else
{
TreeNode* newNode = root;
oldNode = NULL;
root = root->left;
root->left = root->left;
root->right = root->right;
if(newNode->right != NULL)
root->right->right = newNode->right;
delete oldNode;
return true;
}
}
else if(root->data > x)
return del(root->left, x);
else
return del(root->right, x);
}
template <class TYPE>
bool Tree<TYPE>::search(const TYPE &x) const
{
search(root, x);
}
template <class TYPE>
bool Tree<TYPE>::search(const TreeNode *root, const TYPE &x) const
{
if(root == NULL)
return false;
else if(root->data == x)
return true;
else if(root->data > x)
return search(root->left, x);
else
return search(root->right, x);
}
template <class TYPE>
void Tree<TYPE>::display() const
{
display(root);
}
template <class TYPE>
void Tree<TYPE>::display(TreeNode *root) const
{
if(root != NULL)
{
display(root->left);
cout << root->data << " ";
display(root->right);
}
}
//DriveTree.cpp
#include <iostream>
#include "Tree.h"
using namespace std;
int main(int argc, char **argv)
{
Tree<int> tree;
for(int i = 0; i < 10; i++)
tree.insert(i);
tree.display();
cout << endl;
if(!tree.del(16))
cout << "指定删除的元素16不存在!" << endl;
tree.display();
cout << endl;
return 0;
}
7、static的作用
1)隐藏功能,对于static修饰的函数和全局变量而言
2)保持持久性功能,对于static修饰的局部变量而言
因为存放在静态区,全局和局部的static修饰的变量,都默认初始化为0
首先保证代码质量。
其次保证代码的可维护。
再此保证代码的可扩展。
// 位图法,设置辅助数组标记当前元素是否已经存在于数组中
// 删除数组中重复的元素
#include <iostream>
using namespace std;
// 设数组元素最大值为1000
#define MAX 1000
int main()
{
int i = 0;
int a[] = {12, 25, 298, 12, 999, 1000, 99, 1000, 24, 26};
int flag[MAX] = {0};
int len = sizeof(a) / sizeof(*a); // 数组中元素的个数
while(i < len)
{
if(flag[a[i] - 1] == 1) // 当前元素已经存在于数组中
{
for(int j = i; j < len; j++) // 删除重复的当前元素
a[j] = a[j + 1];
len--; // 将数组长度减1
}
else // 当前元素在数组中第一次出现
{
flag[a[i] - 1] = 1; // 设置标记,标志该元素已经存在于数组中
i++;
}
}
for(i = 0; i < len; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}
上述解法当数组中元素的值比较大但数组大小较小时,在很大程度上造成空间的浪费。所以对上述解法改进,采用Hash表判断某个元素是否已经出现过。
#include <stdio.h>
#include <stdlib.h>
#define SUCCESS 1
#define UNSUCCESS 0
#define HASHSIZE 1103
// Hash表结构
struct HashTable
{
struct HashNode *first;
} hash[HASHSIZE];
struct HashNode
{
int key;
struct HashNode *next;
} *node;
// 将值为n的元素插入Hash表
void InsertHash(int n)
{
int j = n % HASHSIZE;
node = (struct HashNode *)malloc(sizeof(struct HashNode));
node->key = n;
if(hash[j].first != NULL)
{
node->next = hash[j].first;
hash[j].first = node;
}
else
{
node->next = NULL;
hash[j].first = node;
}
}
// 查找值为key的元素是否在Hash表中
int SearchHash(int key)
{
node = hash[key % HASHSIZE].first;
while(node)
{
if(node->key == key)
{
return SUCCESS;
break;
}
node = node->next;
}
return UNSUCCESS;
}
int main()
{
int i = 0, j;
int a[] = {12, 25, 298, 12, 999, 1000, 99, 1000, 24, 26};
int len = sizeof(a) / sizeof(*a);
while(i < len)
{
if(SearchHash(a[i]) == SUCCESS) // 元素已经存在,删除重复元素
{
for(j = i; j < len; j++)
a[j] = a[j + 1];
len--;
}
else // 元素不存在,插入Hash表中
{
InsertHash(a[i]);
i++;
}
}
for(i = 0; i < len; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}