Data Structures and Algorithms (three) - list

Data Structures and Algorithms (C) - A list of
  iwehdio the blog garden: https://www.cnblogs.com/iwehdio/

1, the definition of the list

  • Static and dynamic:

    • Static and dynamic operation:
      • Static: only reads the contents of the data structure and composition generally unchanged.
      • Dynamic: needs to be written, local or global data structures will change.
    • Static and dynamic data elements stored and organized way:
      • Static: overall space data created or destroyed, the same physical storage of data elements and their logical order of words. Efficient operation of the static, dynamic operation is relatively inefficient. The neighbor.
      • Dynamic: Oh, for the data elements that too much physical space allocation and recovery. Logically adjacent recording elements of the physical address of each other, is formed integrally on the logic. Efficient operation of the dynamic and static operation is relatively inefficient. As the list.
  • List: a typical structure of the dynamic memory.

    • Each element called nodes (node).
    • Each node coupled to each other by a pointer or reference, to form a linear sequence of logically.
    • Call each other each other adjacent nodes predecessor and successor. If the predecessor and successor exists, then there must be unique.
    • No predecessor nodes to be the first, not the end of the subsequent node is called. It is considered that the presence of a sentinel first precursor called the head, the end of the subsequent presence of a sentinel called tail.
    • Head rank may be considered, first, the end of the tail node are -1,0, n-1, n.
    • When access is not possible using a rank access cycle, the use cycle access position. I.e. a reference to another article using the node, find a particular node.
  • Elements of the list ADT Interface:

  • List of nodes: ListNode template class.

    #define Posi(T) ListNode<T>*  //定义指向列表节点的数据类型(节点位置)
    template <typename T>
    struct ListNode{
        T data;           //数值内容
        Posi(T) pred; //前驱
        Post(T) succ; //后继
        ListNode() {} //针对头尾哨兵的无参构造
        ListNode(T e, Posi(T) p=null, Posi(T) s=null)
            : data(e), pred(p), succ(s) {}    //默认构造器
        Posi(T) insertAsPred(T const& e); //前插入
        Posi(T) insertAsSucc(T const& e); //后插入   
    }
  • List of ADT Interface:

  • List: List template class:

    #include "ListNode.h" //引入列表节点类
    template <typename T>
    class List {
    private:  int _size;
              Posi(T) header; Posi(T) trailer;    //头尾哨兵
    protected:    /*内部函数*/
    public:       /*构造函数、析构函数、对外的接口函数等*/
    }
  • List of initialization function:

    template <typename T>
    void List<T>::init() {
        header = new ListNode<T>; //创建头尾哨兵节点
        trailer = new ListNode<T>;
        header -> succ = trailer; //互联元素
        header -> pred = null;
        trailer -> pred = header;
        trailer -> succ = null;
        _size = 0;        //记录规模
    }

2, the operation unordered list

  • Rank follow visit:

    • Imitate rank list may follow the access vector (subscript operator by overloading).

    • But the efficiency is relatively low, the time complexity is O (n).

    • achieve:

      template <typename T>
      T List<T>::operator[](Rank r) const {
          Posi(T) p = first();    //从首节点出发
          while(0 < r++) p = p->succ;     //顺数第r个节点
          return p ->data;
      }
  • Find operation:

    • Definition: (possibly tail Sentinel) the n true precursor found in the last of the specified node is equal to e p.

    • achieve:

      template <typename T>
      Posi(T) List<T>::find(T const& e, int n, Posi(T) p) const {
          while(0 < n--)  //从右到左逐个比较,直到命中或越界
              if(e == (p = p->pred)->data) return p;
          return null;
      }
  • Insert operation (previously inserted for example):

    • Create a new node e, p and inserted as a precursor.

    • Create a new node e, p is the precursor of the original predecessor, successor is e. Original set subsequent precursor is p e, p is new precursors e.

    • achieve:

      template <typename T>
      Posi(T) List<T>::insertBefore(Posi(T) p, T const& e){
          _size++;
          return p->insertAsPred(e);  //把e当作p的前驱插入
      }
      
      template <typename T>
      Posi(T) ListNode<T>::insertAsPred(T const& e){
          Posi(T) x = new ListNode(e, pred, this);    //创建新节点e,前驱是p的原前驱,后继是e
          pred->succ = x;     //p的原前驱的后继是e
          pred = x;           //p的新前驱是e
          return x;   //返回新节点的位置
      }
  • Based on the configuration of replication:

    • Create a control list, and then passed from node p n the beginning of the end item so inserted as a node.

    • achieve:

      template <typename T>
      void List<T>::copyNodes(Post(T) p, int n){
          init();     //初始化空列表
          while(n--){
              //insertAsLast(p->data)实际上就是insertBefore(trailer, p->data)
              insertAsLast(p->data);
              p = p->succ;
          }
      }
  • Delete operations:

    • P node at the incoming to be deleted.

    • The new successor assignment precursor of p is p original successor, the successor to the new assignment of the original precursor p precursor of p.

    • achieve:

      template <typename T>
      T List<T>::remove(Posi(T) p){
          T e = p->data;
          p->pred->succ = p->succ;    //将p的前驱的新后继赋值为p的原后继
          p->succ->pred = p->pred;    //将p的后继的新前驱赋值为p的原前驱。
          delete p;
          _size--;
          return e;   //返回被删除的值
      }
  • Destructor operation:

    • First, remove all visible nodes, then remove the head and tail Sentinel.

    • Delete to delete the first visible node by node repeatedly until the scale of 0 to achieve.

    • achieve:

      template <typename T>
      List<T>::~List()    //列表析构
      {
          clear();
          delete header;
          delete trailer;
      }
      
      template <typename T>
      int List<T>::clear(){
          int oldSize = _size;
          while(0 < _size){
              remove(header->succ);
          }
          return oldSize;
      }
  • The only of the list:

    • Delete unordered list of duplicate nodes.

    • From the start of the first node, and so to find out whether there are duplicate nodes in its predecessor. Making extended backwards, the predecessor node always searching without repetition, so that you only need to search than the node if there are identical entries in the precursor.

    • achieve:

      template <typename T>
      int List<T>::dedupicate(){
          if(_size < 2) return 0;
          int oldSize = _size;
          Posi(T) o = first();    //从首节点开始
          Rank r = 1;
          while(trailer != (p = p->succ)){
              Posi(T) q = find(p->data, r, p);    //在p的r个真前驱中,有没有雷同的
              q ? remove(q) : r++;    //如果有雷同的就移除前驱中雷同的项,否则将不雷同的前驱向后扩展一项
          }
          return oldSize - _size;     //返回被删除的元素数
      }
  • The only ordering of the list:

    • Delete duplicate ordered list of nodes.

    • Since the order, any similarity is invariably close in a section.

    • p points to the first node of each segment, with the same subsequent deleted. If not identical successor appears, the p point to the successor.

    • achieve:

      template <typename T>
      int List<T>::uniquify(){
          if(_size < 2) return 0;
          int oldSize = _size;
          ListNodePosi(T) p = first();    //p初始化为首节点,p为每个区段的首节点
          ListNodePosi(T) q;  //q为各个区段中p的后继
          while(trailer != (q->succ)){    //考察紧邻的节点对
              if(p->data != q->data){
                  p = q;
              } else {
                  remove(q);
              }
          }
          return oldSize - _size;
      }

      The time complexity is O (n).

  • Find an ordered list of actions:

    • Exactly the same disorder vector search algorithm, and no improvement in efficiency, which is a feature accessed by circulation of the list decision.

3, insertion sort and selection sort

  • Select Sort:

    • Select all the elements in the list of the largest in the end, and then select the location precursor remaining elements of the largest in the end, repeatedly executed. That is, every time the maximum value of the remaining selected set.

    • Sort bubble sort is an option, but due to a time for position Swap adjacent elements, resulting in low efficiency.

    • Improvement of the: sequence into a random sequence prefix and suffix ordered sequences U L, where L is greater than or equal elements of U element. In each iteration, selecting the largest element in U, L and move it to the forefront.

    • achieve:

      template <typename T>
      void List<T>::selectionSort(Posi(T) p, int n){
          Posi(T) head = p->pred;
          Posi(T) tail = p;
          for(int i=0; i<n; i++)  
              tail = tail->succ;  //待排序区间为(head,tail)
          //从待排序区间内找出最大者,将其从原位置删除并插入tail的位置,然后将tail前移,,待排序区间宽度-1
          while(1 < n){
              //insertBefore()和remove()虽然可以认为时O(1)时间,但由于使用了动态内存分配,会使效率大大降低。实际上更倾向于进行节点数据域的交换
              insertBefore(tail, remove(selectMax(head->succ, n)));
              tail = tail->pred;
              n--;
          }
      }
      
      template <typename T>   //获取起始于p的n个元素的最大值,画家算法
      Posi(T) List<T>::selectMax(Posi(T) p, int n){
          Posi(T) max = p;    //初始化p为最大
          for(Posi(T) cur=p; 1<n; n--){
              //后续节点与max逐一比较,!lt(a,b)比较器表示a不小于(not less than,即>=)b时
              if(!lt((cur=cur->succ)->data, max->data){
                  max = cur;
              }
          }
          return max;
      }
    • Time complexity is always Θ (n ^ 2), not the best and worst case. However, compared with the bubble sort operation moving element is greatly reduced.

  • Insertion sort:

    • The entire sequence into an ordered sequence of prefix [0, r), and the suffix sequence disorder [r, n-), then the first r elements into the appropriate positions in the ordered sequence of the prefix, the prefix that still ordered ordered sequence and scale plus one.

    • The difference between the selected sorting: Sort the selection element is always smaller than in disordered portion ordered part, and the insertion sort is no such limit; and thus selecting the maximum value for the operation target sorting disordered portion, the insertion sort operation object disordered portion and the junction portion of the ordered element.

    • achieve:

      template <typename T>
      void List<T>::insertionSort(Posi(T) p, int n){
          for(int r=0; r<n; r++){     //r实际上就是有序前缀序列的长度
              //每次在search()返回的位置插入,然后删除原位置上的节点
              insertAfter(search(p->data, r, p), p->data);
              p = p->succ;
              remove(p->pred);
          }
      }
    • Time complexity: preferably O (n), the worst O (n ^ 2), the average complexity is O (n ^ 2).

    • On the reverse: The first two elements of big small.

      • If the reverse order of the number of a, b is a reverse order (a> b), we will add a corresponding b. That is, an element corresponding to the reverse order of the number, as compared to its mind right and reverse the number of small roles in reverse order.
      • For insertion sort, log on to characterize the reverse list of the number of comparisons to be carried out. At best, the list of the order, reverse order number 0. The worst case, the list is in reverse, reverse to the number n ^ 2. The time complexity is inserted time plus the time comparison, the comparison time is preferably 0, the worst is O (n ^ 2); insertion time O (n). Somehow the complexity is preferably O (n), the worst O (n ^ 2).
      • The time complexity of insertion sort depends on the number of reverse input sequence, the input is sensitive.


Reference: Data Structures and Algorithms (Tsinghua C ++ description): https://www.bilibili.com/video/av49361421


iwehdio the blog garden: https://www.cnblogs.com/iwehdio/

Guess you like

Origin www.cnblogs.com/iwehdio/p/12290282.html