说明
(此系列帖子记录数据结构学习成果,如侵犯视频作者权益,立删)
作者账号 哔哩哔哩:离忧夏天
基于二分查找的核心方法Rank=>用于寻找元素
public int Rank(Key key)
{
//在[l~r]范围里寻找key
int l = 0;
int r = N - 1;
while (l <= r)
{
int mid = l + (r - l) / 2;
if (key.CompareTo(keys[mid]) < 0)
r = mid - 1; //mid左侧查找key
else if (key.CompareTo(keys[mid]) > 0)
l = mid + 1; //mid右侧查找key
else //key.CompareTo(keys[mid]) == 0
return mid;
}
return l;//未找到key,返回l
}
有序数组
方法 | 有序数组 |
---|---|
Rank | (私有方法用于查询传入参数key所对应的索引 |
Add | 添加元素 |
Remove | 移除元素 |
Min | 返回列表最小值 |
Max | 返回列表最大值 |
Select | 根据传入的索引,返回对应的数 |
Contains | 是否包含元素 |
Floor | 找出小于或等于key的最大键 |
Ceiling | 找出大于或等于key的最小键 |
ResetCapacity | (私有方法)调整数组容量大小 |
(支持存储一种数据)
有序数组里的数据首先必须是支持比较的(否则无法进行排序),即实现key实现IComparable <key>
接口
需要注意的是,对于查找key的操作,
- 如果是命中查询:索引i一定在数组中
- 如果是未命中查询:索引i不一定在数组中,这是因为未命中查询时,l > r,可能存在r=N-1,l =N,导致了索引i越界。
因此在调用Rank方法后,我们需要判断索引 i 是否在数组中。
namespace List
{
//where Key:IComparable<Key> 对Key进行泛型约束,限定Key类型,不能是任意类型
class SortedArray1<Key> where Key : IComparable<Key>
{
private Key[] keys;
private int N;
public SortedArray1(int capacity)
{
keys = new Key[capacity];
}
public SortedArray1() : this(10) { }
public int Count =>N;
public bool IsEmpty => N == 0;
public int Rank(Key key)
{
//在[l~r]范围里寻找key
int l = 0;
int r = N - 1;
while (l <= r)
{
int mid = l + (r - l) / 2;
if (key.CompareTo(keys[mid]) < 0)
r = mid - 1; //mid左侧查找key
else if (key.CompareTo(keys[mid]) > 0)
l = mid + 1; //mid右侧查找key
else //key.CompareTo(keys[mid]) == 0
return mid;
}
return l;//未找到key,返回l
}
public void Add(Key key)
{
int i = Rank(key);
if (N == keys.Length)
ResetCapacity(2 * keys.Length);
if (i < N && keys[i].CompareTo(key) == 0)
return;
for (int j = N - 1; j >= i; j--)
keys[j + 1] = keys[j];
keys[i] = key;
N++;
}
public void Remove(Key key)
{
if (IsEmpty)
return;
int i = Rank(key);
if (i == N || keys[i].CompareTo(key) != 0)
return;
for (int j = i + 1; j <= N - 1; j++)
keys[j - 1] = keys[j];
N--;
keys[N] = default(Key);
if (N == keys.Length / 4)
ResetCapacity(keys.Length / 2);
}
public Key Min()
{
if (IsEmpty)
throw new ArgumentException("数组为空");
return keys[0];
}
//获取数组最大值
public Key Max()
{
if (IsEmpty)
throw new ArgumentException("数组为空");
return keys[N - 1];
}
//获取数组最大值
public Key Select(int k)
{
if (k < 0 || k >= N)
throw new ArgumentException("索引越界");
return keys[k];
}
public bool Contains(Key key)
{
int i = Rank(key);
if (i < N && keys[i].CompareTo(key) == 0)
return true;
return false;
}
//找出小于或等于key的最大键
public Key Floor(Key key)
{
int i = Rank(key);
if (i < N && keys[i].CompareTo(key) == 0)
return keys[i];
if (i == 0)
throw new ArgumentException("没有找到小于或等于" + key + "的最大键");
else
return keys[i - 1];
}
//找出大于或等于key的最小键
public Key Ceiling(Key key)
{
int i = Rank(key);
if (i == N)
throw new ArgumentException("没有找到大于或等于" + key + "的最小键");
else
return keys[i];
}
//调整数组容量的大小
private void ResetCapacity(int newCapacity)
{
Key[] newKeys = new Key[newCapacity];
for (int i = 0; i < N; i++)
newKeys[i] = keys[i];
keys = newKeys;
}
//输出数组类的信息
public override string ToString()
{
StringBuilder res = new StringBuilder();
res.Append("[");
for (int i = 0; i < N; i++)
{
res.Append(keys[i]);
if (i != N - 1)
res.Append(", ");
}
res.Append("]");
return res.ToString();
}
}
}
(支持存储两种数据)
和一种数据的类似,只不过现在支持传入两个参数,但是key仍然必须是支持比较的
namespace List
{
class SortedArray2<Key,Value> where Key : IComparable<Key>
{
private Key[] keys;
private Value[] values;
private int N;
public SortedArray2(int capacity)
{
keys = new Key[capacity];
values = new Value[capacity];
}
public SortedArray2() : this(10) { }
public int Count { get { return N; } }
public bool IsEmpty => N == 0;
public int Rank(Key key)
{
//在[l-r]中寻找key
int l = 0;
int r = N-1;
while (l <= r)
{
int mid = l + (r - l) / 2;
if (key.CompareTo(keys[mid]) < 0)
r = mid - 1;
else if (key.CompareTo(keys[mid]) > 0)
l = mid + 1;
else
return mid;//找到key并返回索引下标
}
return l;
}
public Value Get(Key key)
{
if (IsEmpty)
throw new ArgumentException("数组为空");
int i =Rank(key);
if (i<N && keys[i].CompareTo(key) == 0)
return values[i];
else
throw new ArgumentException("键"+key+ "不存在");
}
public void Add(Key key,Value value)
{
int i = Rank(key);
if (N == keys.Length)
ResetCapacity(2 * keys.Length);
if (i < N && keys[i].CompareTo(key) == 0)
{
values[i] = value;
return;
}
for (int j = N - 1; j >= i; j--)
{
keys[j + 1] = keys[j];
values[j + 1] = values[j];
}
keys[i] = key;
values[i] = value;
N++;
}
public void Remove(Key key)
{
if (IsEmpty)
{
return;
}
int i = Rank(key);
if (i == N || keys[i].CompareTo(key) != 0)
return;
for (int j = i + 1; j <= N - 1; j++)
{
keys[j - 1] = keys[j];
values[j-1] = values[j];
}
N--;
keys[N] = default(Key);
values[N] = default(Value);
if (N == keys.Length / 4)
ResetCapacity(keys.Length / 2);
}
//获取最小键
public Key Min()
{
if (IsEmpty)
throw new ArgumentException("数组为空");
return keys[0];
}
//获取最大键
public Key Max()
{
if (IsEmpty)
throw new ArgumentException("数组为空");
return keys[N-1];
}
//选出排名为k的键
public Key Select(int k)
{
if (k == 0 || k >= N)
throw new ArgumentException("索引越界");
return keys[k];
}
//查找是否在数组中
public bool Contains(Key key)
{
int i = Rank(key);
if (i < N && keys[i].CompareTo(key) == 0)
return true;
return false;
}
//找出小于或等于key的最大键
public Key Floor(Key key)
{
int i = Rank(key);
if (i < N && keys[i].CompareTo(key) == 0)
return keys[i];
if (i == 0)
throw new ArgumentException("没有找到小于和等于" + key + "的最大值");
else
return keys[i - 1];
}
//找出大于或等于key的最大键
public Key Ceiling(Key key)
{
int i = Rank(key);
if (i == N)
throw new ArgumentException("没有找到大于和等于" + key + "的最大值");
else
return keys[i];
}
//调整数组容量的大小
private void ResetCapacity(int newCapacity)
{
Key[] newKeys = new Key[newCapacity];
Value[] newValues = new Value[newCapacity];
for (int i = 0; i < N; i++)
{
newKeys[i] = keys[i];
newValues[i] = values[i];
}
keys = newKeys;
values = newValues;
}
//输出有序数组的信息
public override string ToString()
{
StringBuilder res = new StringBuilder();
res.Append("[");
for (int i = 0; i < N; i++)
{
res.Append("{" + keys[i] + "," + values[i] + "}");
if (i != N - 1)
res.Append(", ");
}
res.Append("]");
return res.ToString();
}
}
}