C#数据结构-Dictionary实现_鹅厂程序小哥的博客-程序员秘密

技术标签: C#  Dictionary  数据结构与算法  

在看过一篇大神写的《带你看懂Dictionary的内部实现》,对Dictionary的内部实现有了一个清晰的了解,但纸上得来终觉浅,作为程序员,还是自己调试一下代码,记忆更深刻,为此专门拷贝出C#的Dictionary源码,因为源码有很多保护级别的代码,不能直接运行。下面贴出我调试没有问题的Dictionary源码(有部分代码没有重写),并附带官方调用实例,方便断点调试。

Dictionary源码:

using System;
using System.Collections;
using System.Collections.Generic;

namespace StructScript
{
    /// <summary>
    /// 哈希表的查找算法主要分为两步:
    /// 第一步是用哈希函数将键转换为数组的一个索引,理想情况下不同的键都能转换为不同的索引值,但是实际上会有多个键哈希到到相同索引值上。
    /// 因此,第二步就是处理碰撞冲突的过程。这里有两种处理碰撞冲突的方法:separate chaining(拉链法)和linear probing(线性探测法)。
    /// </summary>

    public class DictionaryScript<TKey, TValue> : IDictionary<TKey, TValue>
    {
        protected struct Entry
        {
            public int hashCode;    //31位散列值,32最高位表示符号位,-1表示未使用
            public int next;        //下一项的索引值,-1表示结尾
            public TKey key;        //键
            public TValue value;    //值
        }

        protected int[] buckets;//处理hash碰撞,储存由键转换成的数组索引
        protected Entry[] entries;//元素数组,用于维护哈希表中的数据
        protected int count;//元素数量
        protected int freeList;//空闲的列表
        protected int freeCount;//空闲列表元素数量
        protected IEqualityComparer<TKey> comparer;//哈希表中的比较函数
        protected KeyCollection keys;//键集合
        protected ValueCollection values;//值集合
        protected const int MaxPrimeArrayLength = 0x7FEFFFFD;
        //预设素数数组
        protected static readonly int[] primes = {
            3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
            1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
            17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
            187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
            1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};

        //调用本身的构造方法
        public DictionaryScript() : this(0, null) { }

        public DictionaryScript(int capacity) : this(capacity, null) { }

        public DictionaryScript(int capacity, IEqualityComparer<TKey> comparer)
        {
            if (capacity < 0)
            {
                throw new ArgumentNullException();
            }
            if (capacity > 0)
            {
                Initialize(capacity);
            }
            this.comparer = comparer == null ? EqualityComparer<TKey>.Default : comparer;
        }

        /// <summary>
        /// 需要一个大小为M的数组来储存键值对,那么需要一个能够将任意键转为该数组范围内的索引(0到M-1)的哈希函数
        /// 这个哈希函数应该易于计算并且能够均匀分布所有的键。即对于任意键,0到M-1之间的每个整数都有相等可能性与之对应
        /// 除留余数法。这个方法选择大小为素数M的数组,对于任意正整数k,计算k除以M的余数
        /// 如果M不是素数的话,将不能有效利用键中所包含的所有信息,导致算法不能均匀地分布所有键。
        /// </summary>
        private void Initialize(int capacity)
        {
            //根据构造函数设定的初始容量,获取一个大于并接近的素数
            int size = GetPrime(capacity);
            buckets = new int[size];
            for (int i = 0; i < buckets.Length; i++)
            {
                buckets[i] = -1;
            }
            entries = new Entry[size];
            freeList = -1;
        }

        /// <summary>
        /// 根据构造函数设定的初始容量,获取一个大于并接近的素数
        /// </summary>
        public int GetPrime(int min)
        {
            if (min < 0)
                throw new ArgumentException();

            for (int i = 0; i < primes.Length; i++)
            {
                int prime = primes[i];
                if (prime >= min) return prime;
            }

            //如果超出预先的数组
            for (int i = (min | 1); i < Int32.MaxValue; i += 2)
            {
                if (IsPrime(i) && ((i - 1) % 101 != 0))
                    return i;
            }
            return min;
        }

        /// <summary>
        /// 是否是素数
        /// </summary>
        private bool IsPrime(int candidate)
        {
            if ((candidate & 1) != 0)
            {
                int limit = (int)Math.Sqrt(candidate);
                for (int divisor = 3; divisor <= limit; divisor += 2)
                {
                    if ((candidate % divisor) == 0)
                        return false;
                }
                return true;
            }
            return (candidate == 2);
        }

        /// <summary>
        /// 扩容
        /// </summary>
        private int ExpandPrime(int oldSize)
        {
            int newSize = 2 * oldSize;
            if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
            {
                return MaxPrimeArrayLength;
            }
            return GetPrime(newSize);
        }

        public TValue this[TKey key]
        {
            get
            {
                int i = FindEntry(key);
                if (i >= 0)
                {
                    return entries[i].value;
                }
                else
                {
                    throw new KeyNotFoundException();
                }
            }
            set
            {
                Insert(key, value, false);
            }
        }

        public int Count
        {
            get
            {
                return count;
            }
        }

        public KeyCollection Keys
        {
            get
            {
                if (keys == null) keys = new KeyCollection(this);
                return keys;
            }
        }

        public ValueCollection Values
        {
            get
            {
                if (values == null) values = new ValueCollection(this);
                return values;
            }
        }

        IEnumerable<TKey> IDictionary<TKey, TValue>.Keys
        {
            get
            {
                if (keys == null) keys = new KeyCollection(this);
                return keys;
            }
        }

        IEnumerable<TValue> IDictionary<TKey, TValue>.Values
        {
            get
            {
                if (values == null) values = new ValueCollection(this);
                return values;
            }
        }

        public void Add(KeyValuePair<TKey, TValue> item)
        {
            Add(item.Key, item.Value);
        }

        public void Add(TKey key, TValue value)
        {
            Insert(key, value, true);
        }

        private void Insert(TKey key, TValue value, bool add)
        {
            //key不能为空,value可以为空
            if (key == null)
            {
                throw new ArgumentNullException();
            }
            if (buckets == null)
            {
                Initialize(0);
            }
            int collisionCount = 0;
            int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
            //将HashCode的返回值转化为数组索引
            int bucketIndex = hashCode % buckets.Length;
            // 处理hash碰撞冲突
            // 如果转换出的bucketIndex大于等于0,判断buckets数组中有没有相等的,如果相等,需要处理冲突
            for (int i = buckets[bucketIndex]; i >= 0; i = entries[i].next)
            {
                //如果转换的hash值与之前已经添加的hash值相等,同时插入的key与之前的相同,处理冲突,key是唯一的,不能重复
                if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key))
                {
                    if (add)
                    {
                        throw new ArgumentException();
                    }
                    entries[i].value = value;
                    return;
                }
                collisionCount++;
            }
            //数组索引
            int index;
            //如果空链表的长度大于0,FreeList链表不为空,因此字典会优先把新增元素添加到FreeList链表所指向的位置,添加后FreeCount减1
            if (freeCount > 0)
            {
                index = freeList;
                freeList = entries[index].next;
                freeCount--;
            }
            else
            {
                //如果数组已满,需扩容
                if (count == entries.Length)
                {
                    Resize();
                    bucketIndex = hashCode % buckets.Length;
                }
                index = count;
                count++;
            }
            entries[index].hashCode = hashCode;
            //新增元素的next指向上一个元素的索引
            entries[index].next = buckets[bucketIndex];
            entries[index].key = key;
            entries[index].value = value;
            //记录新增元素的索引
            buckets[bucketIndex] = index;

            // 冲突数达到了一定的阈值,之后更新Hash值
            if (collisionCount > 100 && IsEqualityComparer(comparer))
            {
                comparer = EqualityComparer<TKey>.Default;
                Resize(entries.Length, true);
            }
        }

        private bool IsEqualityComparer(object comparer)
        {
            return (comparer == null || comparer == EqualityComparer<string>.Default);
        }

        /// <summary>
        /// 扩容数组
        /// </summary>
        private void Resize()
        {
            Resize(ExpandPrime(count), false);
        }

        private void Resize(int newSize, bool forceNewHashCodes)
        {
            int[] newBuckets = new int[newSize];
            for (int i = 0; i < newBuckets.Length; i++)
            {
                newBuckets[i] = -1;
            }
            Entry[] newEntries = new Entry[newSize];
            Array.Copy(entries, 0, newEntries, 0, count);
            if (forceNewHashCodes)
            {
                for (int i = 0; i < count; i++)
                {
                    if (newEntries[i].hashCode != -1)
                    {
                        newEntries[i].hashCode = (comparer.GetHashCode(newEntries[i].key) & 0x7FFFFFFF);
                    }
                }
            }
            for (int i = 0; i < count; i++)
            {
                if (newEntries[i].hashCode >= 0)
                {
                    int bucket = newEntries[i].hashCode % newSize;
                    newEntries[i].next = newBuckets[bucket];
                    newBuckets[bucket] = i;
                }
            }
            buckets = newBuckets;
            entries = newEntries;
        }

        public void Clear()
        {
            if (count > 0)
            {
                for (int i = 0; i < buckets.Length; i++) buckets[i] = -1;
                Array.Clear(entries, 0, count);
                freeList = -1;
                count = 0;
                freeCount = 0;
            }
        }

        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return ContainsKey(item.Key);
        }

        public bool ContainsKey(TKey key)
        {
            return FindEntry(key) >= 0;
        }

        public bool ContainsValue(TValue value)
        {
            if (value == null)
            {
                for (int i = 0; i < count; i++)
                {
                    if (entries[i].hashCode >= 0 && entries[i].value == null) return true;
                }
            }
            else
            {
                EqualityComparer<TValue> c = EqualityComparer<TValue>.Default;
                for (int i = 0; i < count; i++)
                {
                    if (entries[i].hashCode >= 0 && c.Equals(entries[i].value, value)) return true;
                }
            }
            return false;
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            return Remove(item.Key);
        }

        public bool Remove(TKey key)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }
            if (buckets != null)
            {
                int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
                int bucket = hashCode % buckets.Length;
                int last = -1;
                for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next)
                {
                    if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key))
                    {
                        //如果key在索引0,直接找到或者遍历到数组索引0找到key
                        if (last < 0)
                        {
                            // 把当前索引的bucket数组中的值重置,设置为-1
                            buckets[bucket] = entries[i].next;
                        }
                        else
                        {
                            //遍历数组时,找到key,把当前删除元素的下一个元素的索引赋值给当前删除元素的上一个元素的next
                            entries[last].next = entries[i].next;
                        }
                        entries[i].hashCode = -1;
                        entries[i].next = freeList;
                        entries[i].key = default(TKey);
                        entries[i].value = default(TValue);
                        freeList = i;
                        freeCount++;
                        return true;
                    }
                }
            }
            return false;
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            int i = FindEntry(key);
            if (i >= 0)
            {
                value = entries[i].value;
                return true;
            }
            value = default(TValue);
            return false;
        }

        private int FindEntry(TKey key)
        {
            if (key == null)
            {
                throw new ArgumentNullException();
            }

            if (buckets != null)
            {
                int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
                for (int i = buckets[hashCode % buckets.Length]; i >= 0; i = entries[i].next)
                {
                    if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) return i;
                }
            }
            return -1;
        }

        public Enumerator GetEnumerator()
        {
            return new Enumerator(this, Enumerator.KeyValuePair);
        }

        IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
        {
            return new Enumerator(this, Enumerator.KeyValuePair);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Enumerator(this, Enumerator.DictEntry);
        }

        public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
        {
            private DictionaryScript<TKey, TValue> dictionary;
            private int index;
            private KeyValuePair<TKey, TValue> current;
            private int getEnumeratorRetType;

            internal const int DictEntry = 1;
            internal const int KeyValuePair = 2;

            internal Enumerator(DictionaryScript<TKey, TValue> dictionary, int getEnumeratorRetType)
            {
                this.dictionary = dictionary;
                index = 0;
                this.getEnumeratorRetType = getEnumeratorRetType;
                current = new KeyValuePair<TKey, TValue>();
            }

            public bool MoveNext()
            {
                while ((uint)index < (uint)dictionary.count)
                {
                    if (dictionary.entries[index].hashCode >= 0)
                    {
                        current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value);
                        index++;
                        return true;
                    }
                    index++;
                }

                index = dictionary.count + 1;
                current = new KeyValuePair<TKey, TValue>();
                return false;
            }

            public KeyValuePair<TKey, TValue> Current
            {
                get { return current; }
            }

            public void Dispose()
            {
            }

            object IEnumerator.Current
            {
                get
                {
                    if (getEnumeratorRetType == DictEntry)
                    {
                        return new DictionaryEntry(current.Key, current.Value);
                    }
                    else
                    {
                        return new KeyValuePair<TKey, TValue>(current.Key, current.Value);
                    }
                }
            }

            void IEnumerator.Reset()
            {
                index = 0;
                current = new KeyValuePair<TKey, TValue>();
            }
        }


        public sealed class KeyCollection : ICollection<TKey>
        {
            private DictionaryScript<TKey, TValue> dictionary;

            public KeyCollection(DictionaryScript<TKey, TValue> dictionary)
            {
                if (dictionary == null)
                {
                    throw new ArgumentNullException();
                }
                this.dictionary = dictionary;
            }

            public KeyEnumerator GetEnumerator()
            {
                return new KeyEnumerator(dictionary);
            }

            IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator()
            {
                return new KeyEnumerator(dictionary);
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return new KeyEnumerator(dictionary);
            }

            public int Count
            {
                get { return dictionary.Count; }
            }

            public void Add(TKey item)
            {
                throw new NotSupportedException();
            }

            public void Clear()
            {
                throw new NotSupportedException();
            }

            public bool Contains(TKey item)
            {
                return dictionary.ContainsKey(item);
            }

            public void CopyTo(TKey[] array, int arrayIndex)
            {
                throw new NotSupportedException();
            }

            public bool Remove(TKey item)
            {
                throw new NotSupportedException();
            }
        }

        public struct KeyEnumerator : IEnumerator<TKey>, IEnumerator
        {
            private DictionaryScript<TKey, TValue> dictionary;
            private int index;
            private TKey currentKey;

            internal KeyEnumerator(DictionaryScript<TKey, TValue> dictionary)
            {
                this.dictionary = dictionary;
                index = 0;
                currentKey = default(TKey);
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                while ((uint)index < (uint)dictionary.count)
                {
                    if (dictionary.entries[index].hashCode >= 0)
                    {
                        currentKey = dictionary.entries[index].key;
                        index++;
                        return true;
                    }
                    index++;
                }

                index = dictionary.count + 1;
                currentKey = default(TKey);
                return false;
            }

            public TKey Current
            {
                get
                {
                    return currentKey;
                }
            }

            Object IEnumerator.Current
            {
                get
                {
                    if (index <= 0 || (index > dictionary.count))
                    {
                        throw new IndexOutOfRangeException();
                    }

                    return currentKey;
                }
            }

            void IEnumerator.Reset()
            {
                index = 0;
                currentKey = default(TKey);
            }
        }


        public sealed class ValueCollection : ICollection<TValue>
        {
            private DictionaryScript<TKey, TValue> dictionary;

            public ValueCollection(DictionaryScript<TKey, TValue> dictionary)
            {
                if (dictionary == null)
                {
                    throw new ArgumentNullException();
                }
                this.dictionary = dictionary;
            }

            public ValueEnumerator GetEnumerator()
            {
                return new ValueEnumerator(dictionary);
            }

            IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
            {
                return new ValueEnumerator(dictionary);
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return new ValueEnumerator(dictionary);
            }

            public int Count
            {
                get { return dictionary.Count; }
            }

            public void CopyTo(TValue[] array, int arrayIndex)
            {
                throw new NotSupportedException();
            }

            public void Add(TValue item)
            {
                throw new NotSupportedException();
            }

            public void Clear()
            {
                throw new NotSupportedException();
            }

            public bool Contains(TValue item)
            {
                return dictionary.ContainsValue(item);
            }

            public bool Remove(TValue item)
            {
                throw new NotSupportedException();
            }
        }

        public struct ValueEnumerator : IEnumerator<TValue>, IEnumerator
        {
            private DictionaryScript<TKey, TValue> dictionary;
            private int index;
            private TValue currentValue;

            internal ValueEnumerator(DictionaryScript<TKey, TValue> dictionary)
            {
                this.dictionary = dictionary;
                index = 0;
                currentValue = default(TValue);
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                while ((uint)index < (uint)dictionary.count)
                {
                    if (dictionary.entries[index].hashCode >= 0)
                    {
                        currentValue = dictionary.entries[index].value;
                        index++;
                        return true;
                    }
                    index++;
                }
                index = dictionary.count + 1;
                currentValue = default(TValue);
                return false;
            }

            public TValue Current
            {
                get
                {
                    return currentValue;
                }
            }

            Object IEnumerator.Current
            {
                get
                {
                    if (index <= 0 || (index > dictionary.count))
                    {
                        throw new IndexOutOfRangeException();
                    }

                    return currentValue;
                }
            }

            void IEnumerator.Reset()
            {
                index = 0;
                currentValue = default(TValue);
            }
        }
    }
}

Dictionary官方调用实例:

using System;
using System.Collections.Generic;
using System.Collections;

namespace StructScript
{
    public class TestDictionary
    {
        static void Main(string[] args)
        {
            DictionaryScript<int, string> testDic = new DictionaryScript<int, string>(6);
            testDic.Add(4, "4");
            //在容量为6的情况下,传入4和11的key,得到的hashcode都是一样的,这里就要处理hash碰撞的问题
            testDic.Add(11, "11");

            DictionaryScript<int, string> test1Dic = new DictionaryScript<int, string>(6);
            test1Dic.Add(4, "4");
            test1Dic.Add(10, "11");
            test1Dic.Add(9, "11");
            test1Dic.Add(8, "11");
            test1Dic.Add(7, "11");
            test1Dic.Add(6, "11");
            test1Dic.Add(5, "11");
            //根据构造函数设定的初始容量,获取一个大于并接近的素数7
            //C#内部有一个素数数组,在DictionaryScript的初始化函数Initialize中有具体实现
            //超出数组容量,需要扩容,这里有数组扩容操作
            test1Dic.Add(3, "11");
            string value1;
            test1Dic.TryGetValue(2, out value1);
            test1Dic.Remove(3);


            //下面是官方调用实例
            DictionaryScript<string, string> openWith = new DictionaryScript<string, string>();

            openWith.Add("txt", "notepad.exe");
            openWith.Add("bmp", "paint.exe");
            openWith.Add("dib", "paint.exe");
            openWith.Add("rtf", "wordpad.exe");

            // The Add method throws an exception if the new key is 
            // already in the dictionary.
            try
            {
                openWith.Add("txt", "winword.exe");
            }
            catch (ArgumentException)
            {
                Console.WriteLine("An element with Key = \"txt\" already exists.");
            }

            // The Item property is another name for the indexer, so you 
            // can omit its name when accessing elements. 
            Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);

            // The indexer can be used to change the value associated
            // with a key.
            openWith["rtf"] = "winword.exe";
            Console.WriteLine("For key = \"rtf\", value = {0}.",
                openWith["rtf"]);

            // If a key does not exist, setting the indexer for that key
            // adds a new key/value pair.
            openWith["doc"] = "winword.exe";

            // The indexer throws an exception if the requested key is
            // not in the dictionary.
            try
            {
                Console.WriteLine("For key = \"tif\", value = {0}.",
                    openWith["tif"]);
            }
            catch (KeyNotFoundException)
            {
                Console.WriteLine("Key = \"tif\" is not found.");
            }

            // When a program often has to try keys that turn out not to
            // be in the dictionary, TryGetValue can be a more efficient 
            // way to retrieve values.
            string value = "";
            if (openWith.TryGetValue("tif", out value))
            {
                Console.WriteLine("For key = \"tif\", value = {0}.", value);
            }
            else
            {
                Console.WriteLine("Key = \"tif\" is not found.");
            }

            // ContainsKey can be used to test keys before inserting 
            // them.
            if (!openWith.ContainsKey("ht"))
            {
                openWith.Add("ht", "hypertrm.exe");
                Console.WriteLine("Value added for key = \"ht\": {0}",
                    openWith["ht"]);
            }

            // When you use foreach to enumerate dictionary elements,
            // the elements are retrieved as KeyValuePair objects.
            Console.WriteLine();
            foreach (KeyValuePair<string, string> kvp in openWith)
            {
                Console.WriteLine("Key = {0}, Value = {1}",
                    kvp.Key, kvp.Value);
            }

            // To get the values alone, use the Values property.
            DictionaryScript<string, string>.ValueCollection valueColl =
                openWith.Values;

            // The elements of the ValueCollection are strongly typed
            // with the type that was specified for dictionary values.
            Console.WriteLine();
            foreach (string s in valueColl)
            {
                Console.WriteLine("Value = {0}", s);
            }

            // To get the keys alone, use the Keys property.
            DictionaryScript<string, string>.KeyCollection keyColl =
                openWith.Keys;

            // The elements of the KeyCollection are strongly typed
            // with the type that was specified for dictionary keys.
            Console.WriteLine();
            foreach (string s in keyColl)
            {
                Console.WriteLine("Key = {0}", s);
            }

            // Use the Remove method to remove a key/value pair.
            Console.WriteLine("\nRemove(\"doc\")");
            openWith.Remove("doc");

            if (!openWith.ContainsKey("doc"))
            {
                Console.WriteLine("Key \"doc\" is not found.");
            }


            Console.ReadLine();
        }
    }
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq826364410/article/details/79530451

智能推荐

python中学用Debug进行调试(学习笔记)_不会下雨的~云的博客-程序员秘密_pythondebug教程

一、这个是我经常在报错时,进行自己的找错。是一个比较简单的方法。debug的位置:红点标的或者:鼠标右键鼠标点一下这个位置会出现一个红点,这个红点叫断点(下图所示)(注意断点停在这时,是没有运行到这一步的。二、是几个常用的快捷方式1、F7 step into 单步调试,(进)关心函数内部是什么点击上方绿色标记的(F7)可以看到你每次运行进行的步骤2、F8 step over 单步调试(出),不关心函数内部,只关心输出(与F7的区别是遇到函数,会...

Centos7安装部署RabbitMQ及配置_滴滴打车去的博客-程序员秘密_centos7部署rabbitmq

1 简介RabbitMQ是一个开源的免费的消息队列系统,一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息。它是用Erlang编写的,并实现了高级消息队列协议(AMQP)。2 安装部署2.1 安装EPEL存储库和Erlang安装RabbitMQ是用Erlang语言编写的,在本教程中我们将安装最新版本的Erlang到服务器中。 Erlang在默认的YUM存储库中不可用,因此...

北京凯米家网络建站公司一个值得信任和托付的建站_chukefu7952的博客-程序员秘密

对于企业最最关心的问题,那就是宣传自己企业的产品,让人人都知道了解并且喜欢自己企业的产品,北京网络建站www.zhongkejixun.com能做到一语中的,一针见血,针对最最重要的问题,必然要做到最好,做的最突出。北京建站,不少企业的优先选择,这是很多企业已经实践过的,所以,北京建站...

内网渗透-msf及socks代理转发_baynk的博客-程序员秘密_msf socks

0x00 学习环境拓扑如上,现在已经拥有了WIN2008的meterpreter权限希望通过此主机进行代理转发,从而使msf能够攻击WIN7从而拿到权限。0x01 路由转发1先在meterpreter中使用route进行查看WIN2008所在的网段信息通过background回到msf,使用route增加对应路由route add 172.16.10.0 255.255.255.0 1,1是挂起的session编号。可以看到已经有路由了,用ms17-010打win7也可以成功拿到she

联想Y450A-TFO-A刷新BIOS至17CN41WW_bao6478的博客-程序员秘密

昨天上课闲得无聊,发现Y450的BIOS最新版本是17CN41WW了,我的本本买回来是17CN35WW,当时刷了SLIC2.1,没有更新BIOS到17CN38WW,都说风扇声音太大,放弃了。 这次没搜索到几个评论,只有几个人说刷了 之后,玩游戏要蓝屏,考虑了一下,还是刷新了BIOS。到现在位置,小Y正常运行,刷完后第一次开机CPU和显卡温度要比平时高,在45°左右...

分享一篇如何注册Shopee开发者的辛酸历程_风日道的博客-程序员秘密_shopee 开发者平台

要注册Shopee,需要先注册一个账户。注册地址:https://open.shopee.com/注册流程还是比较简单的。只需要邮箱能收到验证邮件就可以了。点击verify your email 就可以去设置账户密码了。注册好了,就进去开放平台,点击join us接下来比较重要的选择点如果你是第三方开发者,一定要选择Third-party Partner Platform因为Shopee Seller需要你是有虾皮店铺才可以开通。选择Third-p...

随便推点

jwt+RSA+数字签名_-随_风-的博客-程序员秘密_jwt rsa签名

文章目录Jwt数字签名签名验证非对称加密Jwt参考链接数字签名如果发送者A和接收者B使用不同的密钥,例如A发送消息的时候使用私钥对消息进行加密,B接收消息的时候使用公钥对消息进行解密。因为消息只能由A的私钥进行加密,所以这个签名一定是由A签发的,这样就没有否认的问题了。这个就是数字签名(digital signature)。签名验证通常我们使用jwt时候采用RS256 私钥/公钥 方式进行签名的 加密/解密,因为RS256是非对称加密,比较安全。因为jwt是由服务端生成并发放的,其中签名是由服

调制信号matlab仿真实验报告,信号的调制与解调实验报告-数字信号处理_恋君归期的博客-程序员秘密

信号的调制解调实验报告信号的调制解调实验报告信号的调制解调实验报告信号的调制解调实验报告 一一一一、、、、实验目的实验目的实验目的实验目的::::1、了解几种基本的信号调制解调原理;2、掌握用数字信号处理的方法实现模拟电路中信号的调制与解调的方法;3、通过理论推导得出相应结论,利用Matlab作为编程工具进行计算机验证实现,加深理解,建立概念。二二二二、、、、实验原理实验原理实验原理实验原理:::...

思科三层交换机开启ipv6路由功能_网络工程实战之三层交换机配置IPv6 DNS 示例..._鲸阮的博客-程序员秘密

组网需求如图 所示,设备SwitchA 作为IPv6 DNS Client 端和IPv6 DNS Server 配合,使得SwitchA 通过域名(huawei.com)能够访问IP 地址为2002::1/64 的主机。在SwitchA 上配置SwitchB 和SwitchC 的静态IPv6 DNS 表项,使得SwitchA 能够使用域名(SwitchB 和SwitchC)对设备进行管理。配置思路...

关于STM32空闲中断_weixin_30292745的博客-程序员秘密

在使用串口接受字符串时,可以使用空闲中断(IDLEIE置1,即可使能空闲中断),这样在接收完一个字符串,进入空闲状态时(IDLE置1)便会激发一个空闲中断。在中断处理函数,我们可以解析这个字符串。需要注意的是,IDLE标志位需要软件清零,否则由于会不断进入中断,而使正常程序无法运行。当再次收到数据时(即RXNE再次置1),等到空闲便会重新进入中断。在STM32F4中,IDLE标志位清零的过程是...

ARC 100 C - Linear Approximation题解---三分法_weixin_30448603的博客-程序员秘密

题目链接:https://arc100.contest.atcoder.jp/tasks/arc100_a分析:比赛时做这题想到一个瞎搞的方法就是在平均数上下波动一下取最小值,然后大佬yjw学长说这就是个严格单调单峰函数直接三分法就好了,虽然之前就听过则还是第一次打三分法设有最大值函数f(x)定义域为\([l,r]\),我们在定义域内找两个点\(lmid,rmid(lmid&lt;rm...

MFC MoveWindow后控件不见了_YYDataV数据可视化大屏的博客-程序员秘密

确定MoveWindow后控件没有跑到窗口外面去,不知为何显示不了。执行:GetDlgItem(IDC_STATIC_1)-&gt;InvalidateRect(rect);Invalidate();就好了。

推荐文章

热门文章

相关标签