精华内容
下载资源
问答
  • 双向链表既然是比单链表多了如可以反向遍历查找等的数据结构,那么也就需要付出一些小的代价。 3.15总结回顾 84 3.16结尾语 85 如果你觉得上学读书是受罪,假设你可以活到80岁,其实你最多也就吃了20年苦。用人生...
  • 可以用于提高读写效率的数据结构很多,这里我先给你介绍三种常见、也比较简单的数据结构它们分别是哈希表、有序数组和搜索树。 哈希表 是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的值...
    索引的出现是为了提高查询效率,但是实现索引的方式却有很多种,所以这里也就引入了 索引模型的概念。可以用于提高读写效率的数据结构很多,这里我先给你介绍三种常见、也比较简单的数据结构,它们分别是哈希表、有序数组和搜索树。
     

    哈希表

    是一种以键 - 值(key-value)存储数据的结构,我们只要输入待查找的值即 key,就可以找到其对应的值即 Value。哈希的思路很简单,把值放在数组里,用一个哈希函数把 key 换算成一个确定的位置,然后把 value 放在数组的这个位置。 不可避免地,多个 key 值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表。
     
    哈希表这种结构适用于只有等值查询的场景,比如 Memcached 及其他一些NoSQL 引擎。 有序数组在等值查询和范围查询场景中的性能就都非常优秀。有序数组索引只适用于静态存储引擎,比如你要保存的是 2017 年某个城市的所有人口信息,这类不会再修改的数据。
     

    二叉搜索树

    每个节点的左儿子小于父节点,父节点又小于右儿子。这样如果你要查 ID_card_n2 的话,按照图中的搜索顺序就是按照 UserA -> UserC -> UserF -> User2 这个路径得到。这个时间复杂度是 O(log(N))。 当然为了维持 O(log(N)) 的查询复杂度,你就需要保持这棵树是平衡二叉树。为了做这个保证,更新的时间复杂度也是 O(log(N))。 树可以有二叉,也可以有多叉。多叉树就是每个节点有多个儿子,儿子之间的大小保证从左到右递增。二叉树是搜索效率最高的,但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。你可以想象一下一棵 100 万节点的平衡二叉树,树高 20。一次查询可能需要访问 20 个数据块(逐层加载,一层加载一个节点)。在机械硬盘时代,从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。也就是说,对于一个 100 万行的表,如果使用二叉树来存储,单独访问一个行可能需要 20 个 10ms 的时间,这个查询可真够慢的。
     
    为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么,我们就不应该使用二叉树,而是要使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。
     
    以 InnoDB 的一个整数字段索引为例,这个 N 差不多是 1200。这棵树高是 4 的时候,就可以存 1200 的 3 次方个值,这已经 17 亿了。考虑到树根的数据块总是在内存中的,一 个 10 亿行的表上一个整数字段的索引,查找一个值最多只需要访问 3 次磁盘。其实,树的第二层也有很大概率在内存中,那么访问磁盘的平均次数就更少了。N 叉树由于在读写上的性能优点,以及适配磁盘的访问模式,已经被广泛应用在数据库引擎中了。
     
     
    展开全文
  • C#数据结构

    2013-12-10 11:49:54
    便选择一个适合于某个特定问题的数据结构。这些问题就是数据结构这门课程所 要研究的主要问题。本章首先说明学习数据结构的必要性和本书的目的,然后解 释数据结构及其有关概念,接着讨论算法的相关知识,最后简单...
  • 大话数据结构

    2019-01-10 16:35:22
    双向链表既然是比单链表多了如可以反向遍历查找等的数据结构,那么也就需要付出一些小的代价。 3.15总结回顾 84 3.16结尾语 85 如果你觉得上学读书是受罪,假设你可以活到80岁,其实你最多也就吃了20年苦。用人生...
  • 大话数据结构 程杰

    2018-09-01 10:06:43
    双向链表既然是比单链表多了如可以反向遍历查找等的数据结构,那么也就需要付出一些小的代价。 3.15总结回顾 84 3.16结尾语 85 如果你觉得上学读书是受罪,假设你可以活到80岁,其实你最多也就吃了20年苦。用人生...
  •  python解析XML常见的有三种方法:一是xml.dom.*模块,它是W3C DOM API的实现,若需要处理DOM API则该模块很适合,注意xml.dom包里面有许多模块,须区分它们间的不同;二是xml.sax.*模块,它是SAX API的实现,这个...
  • 大话数据结构-程杰

    2014-07-13 23:45:52
    双向链表既然是比单链表多了如可以反向遍历查找等的数据结构,那么也就需要付出一些小的代价。 3.15 总结回顾 84 3.16 结尾语 85 如果你觉得上学读书是受罪,假设你可以活到80岁,其实你最多也就吃了20年苦。用...
  • ArrayList,LinkedList,HashTable三者是JAVA中的三种常见的数据结构,当然它们的性能不同的差异,比如数据查找速度,增加或删除数据的速度,内存空间占用等等,这将在下篇博客中体现,这篇博客只是大致应用数据结构...

    ArrayList,LinkedList,HashTable三者是JAVA中的三种常见的数据结构,当然它们的性能有不同的差异,比如数据查找速度,增加或删除数据的速度,内存空间占用等等,这将在下篇博客中体现,这篇博客只是大致应用数据结构知识来自己实现三种数据结构的基本功能,包含一些简单的增查改删功能。

    ArrayList:

    public  class ArrayList {
    
    
    	private int counts;  				//数组实际填充大小
    	private int stepcount;				//数组将溢出时的扩充步长
    	Object[] data =new Object[10];   	//默认数组长度为10
    	
    //无参的构造方法,默认扩充步长为100
    	public ArrayList(){
    		stepcount=100;
    	}
    
    //带初始数组长度与扩充步长的构造方法
    	public ArrayList(int initlen,int stepcount){
    		 data=new Object[initlen];
    		this.stepcount=stepcount;
    		
    	}
    		
    	
    //给数组添加新数据
    	public void add(Object obj){
    		
    		if(counts>=data.length){          	 //判断有无溢出,溢出则增加数组长度stepcount,并将原数组数据放入新数组
    				Object[] data2=new Object[data.length+stepcount];
    				for(int i=0;i<data.length;i++){
    						data2[i]=data[i];
    			}
    			data=data2;
    		}
    		data[counts++]=obj;
    	}
    	
    //获得指定数组位置的内容
    	public Object get(int index){
    		if(index<0||index>data.length){
    			System.out.println("超出数组限定范围");
    			return null;
    		}
    		return data[index];
    	};
    //删除指定位置的元素
    	public void remove(int index){
    		Object[] data2 = new Object[data.length-1];
    		for (int i=0;i<index;i++){
    			data2[i]=data[i];
    		}
    		for (int i=index+1;i<data.length;i++){
    			
    			data2[i-1]=data[i];
    		}
    		data=data2;
    		Object obj =data[index];
    		
    		
    	}
    //获得数组大小
    	public int size(){
    		return counts;
    		
    	}
    //在指定位置插入元素
    	public void insert(Object obj,int index){
    		Object[] data2 =new Object[data.length+1];  //新建一数组才可从数组中间插入,此时新数组长度需至少加一
    		for(int i=0;i<index;i++){
    			data2[i]=data[i];
    		}
    		data2[index]=obj;
    		for(int i=index+1;i<data2.length;i++){
    			data2[i]=data[i-1];
    		}
    			
    		data=data2;
    		
    	}
    	
    }

    LinkedList:

     

    public class MyLinkList implements List {
    	//声明根节点
    	private Node root=null
    	private Node tail,tempt;
    	private int total;
    	
    	//给链表添加元素
    	public void add(Object obj) {
    		
    		Node newnode =new Node();
    		if (root==null){
    			newnode.data=obj;
    			root=newnode;
    			tail=newnode;
    		}
    		else{
    			tail.next=newnode;
    			newnode.data=obj;
    			tail=newnode;
    		}
    		total++;
    		
    	}
    	//获取链表指定位置元素(为便于习惯,默认从一开始)
             public Object  get(int index) {
    		if(index==0){
    			return null;
    		}
    		if(index-1==0){
    			return root.data;
    		}
    		else {
    			tempt=root;
    			for(int i=1;i<index;i++){
    				 tempt=tempt.next;
    			}
    			return tempt.data;
    		}
    		
    	}
    	//删除某指定链表元素
    	public void remove(int index) {
    		
    		if(index-1==0){
    			root=root.next;
    		}
    		else {
    				tempt=root;
    			for(int i=1;i<index-1;i++){
    				 tempt=tempt.next;
    			}
    			tempt.next=tempt.next.next;
    		}
    		total--;
    		
    	}
            //获得链表的大小
    	public int size() {
    		return total;
    	}
            //给链表指定位置插入某元素
    	public void insert(Object obj, int index) {
    
    		Node insertNode =new Node();
    		insertNode.data=obj;
    		if(index-1==0){
    			insertNode.next=root;
    			root=insertNode;
    		}
    		else {
    				tempt=root;
    			for(int i=1;i<index-1;i++){
    				 tempt=tempt.next;
    				
    			}
    			insertNode.next=tempt.next;
    			tempt.next=insertNode;
    		}
    		total++;
    	}
    	//该链表内部类实现对Node的定义
    	 class Node{
    		 Object data;
    		 Node next;
    		 Node(Node next,Object data){
                          this.next=next;
                          this.data=data;
                       }
    	}
    
    }
    
      HashTable:
    public class MyHashTable{
       private Object[] saveKey;    //存关键字的数组
       private int size;            //数组大小
       
       
     //无参的构造函数
      public MyHashTable(){             
         saveKey= new Object[16];	//默认数组长度是16	
          size = 0;
      }
     //带参数的构造函数
      public MyHashTable(int  arraylenght,int size){
    	  saveKey=new Object[arraylenght];
    	  this.size=size;
    	  
      }
     //哈希函数
      public int hash(Object  obj){                                       
            return Math.abs(obj.hashCode())%saveKey.length;
      }
      //处理冲突的哈希函数
      public int hashForCollision(Object  obj){                                    
          int newhash = Math.abs(obj.hashCode())%(saveKey.length-1);//这里调用里JDK里自有的hashcode方法后实现映射
         
          if(newhash%2==0){
              return newhash + 1;
          }
       return newhash;
      }
      //判断哈希表里面是否已有某对象
      public boolean contains(Object obj){                  
          int i = hash(obj);
          
          while (saveKey[i] != null){
               if(saveKey[i].equals(obj)){
                   return true;
               }
            i = (i + hashForCollision(obj))%saveKey.length;
    
          }
       return false;
      }
      //添加新元素
      public void add(Object obj){
           //先判断是否需要扩容,若已有数据占原数组一半,则扩容
           if(size>=saveKey.length/2){
                this.rehash();
           }
          int i = hash(obj);//获取其哈希值
         while(saveKey[i] != null){  
             if(obj.equals(saveKey[i])){
                  return;
             }              //判断该索引处是否已占用,若占用则调用hashforcollision生成新地址
           i = (i + hashForCollision(obj))%saveKey.length;
    
         }
        saveKey[i] = obj;
        size ++;
      }
      //扩大哈希表为原表的四倍,并把原来的哈希表添加到新表中
       public void rehash(){                             
           MyHashTable ht = new MyHashTable();
           ht.saveKey = new String[this.saveKey.length * 4];
           for(int i = 0; i < this.saveKey.length; i ++){
                   if((this.saveKey[i] != null)){
                       ht.add(this.saveKey[i]);
                  }
           }
         this.saveKey = ht.saveKey;
         this.size = ht.size;
       }
       //删除某个元素
      public void remove(Object obj){                    
             if(this.contains(obj)){
                  int i = this.getIndex(obj);
                  this.saveKey[i] = null;
             }
      }
      //得到某对象在哈希表中的位置
      public int getIndex(Object obj){               
        int i = this.hash(obj);
    
        while(this.saveKey[i] != null){
           if(this.saveKey[i].equals(obj)){
               return i;
           }
         i = (i + this.hashForCollision(obj))%this.saveKey.length;
    
       }
      return -1;
      }
      //获取哈希表中某元素
      public Object  get(Object obj){
    	  if(this.contains(obj)){
              int i = this.getIndex(obj);
              return saveKey[i] ;
         }
    	  return null;
      }
    //输出哈希表中所有元素
      public void print(){                       
         for(int i = 0; i < saveKey.length; i ++){
            System.out.println(i+":"+saveKey[i]);
        }
      }
    //哈希表存储元素的个数
    public int size(){          
       return this.size;
     }
    //哈希表的长度
    public int length(){          
        return this.saveKey.length;
     }
     以上三个实现的数据结构都经过测试,能实现其所写功能。
    展开全文
  • 双向链表既然是比单链表多了如可以反向遍历查找等的数据结构,那么也就需要付出一些小的代价。 3.15总结回顾 84 3.16结尾语 85 如果你觉得上学读书是受罪,假设你可以活到80岁,其实你最多也就吃了20年苦。用人生...
  • 双向链表既然是比单链表多了如可以反向遍历查找等的数据结构,那么也就需要付出一些小的代价。 3.15 总结回顾 84 3.16 结尾语 85 如果你觉得上学读书是受罪,假设你可以活到80岁,其实你最多也就吃了20年苦。用人生...
  • 排序算法多种多样,在之前章节中我们已经学习了常见的排序算法,各特点,我们先对它们进行执行效率的比较。 算法名称 时间复杂度 是否原地 是否稳定 冒泡排序 O(n2)O(n^2)O(n2) ✔️ ✔️ ...

    摘要:

    快速排序有普适性、原地算法节省空间的优秀特质,当使用「三点取中」和「随机法」降低快排时间复杂度的退化概率后,快排在底层的排序实现中成为广泛应用的算法。

    为何是快排

    排序算法多种多样,在之前章节中我们已经学习了常见的几种排序算法,各有特点,我们先对它们进行执行效率的比较。

    算法名称 时间复杂度 是否原地 是否稳定
    冒泡排序 O(n2)O(n^2) ✔️ ✔️
    插入排序 O(n2)O(n^2) ✔️ ✔️
    选择排序 O(n2)O(n^2) ✔️
    归并排序 O(nlog(n))O(n\log\left(n\right)) ✔️
    快速排序 O(nlog(n))O(n\log\left(n\right)) ✔️
    桶排序 O(n)O(n) ✔️
    计数排序 O(n)O(n) ✔️
    基数排序 O(n)O(n) ✔️

    从图表中来看,桶排序、计数排序和基数排序无疑在时间复杂度上具有较大优势,但这三种算法对排序数据有特殊要求,对于底层排序实现这种需要对数据具有普适性的情况,明显是不适合的。

    退而求其次,时间复杂度次之的是归并排序和快速排序,快速排序时间复杂度并不稳定,有退化为 O(n2)O(n^2) 的可能,而且也不是稳定的排序算法,按理应该选择归并排序,但归并排序有个劣势——不是原地算法。归并排序的空间复杂度是 O(n)O(n),也就是说当需要排序的数据大小为 100 M 时,还需要额外申请 100 M 的空间,这个缺点导致了快排走上 C 位。

    快排的优化

    快排虽然走上 C 位,但想成为真正的明星还需要包装一番。快排的时间复杂度并不那么稳定,究其原因是在快排选取分区点时很难理想化地将排序数据均分,当分区极其不平衡时,时间复杂度的退化在所难免,所以要解决快排时间复杂度退化的问题就要解决如何取分区点的问题。

    三点取中法

    三点取中法就是从排序数据中取三个位置的数据,一般来说是第一个、最后一个和中间一个数据,然后比较三个数据,使用中间的一个数作为分区点数据。这种方法实现简单,但当数据规模较大时,三点可能已经无法满足使分区尽量平衡的要求,需要五点取中甚至十点取中,所以这种方法在遭遇大规模数据时有其弊端。

    随机数法

    通过随机的方式获取分区点,虽然不能完全避免分区极度不平衡的情况,但能够将这种概率降低,降低时间复杂度退化的可能。

    因为算法的实现使用递归的方式,所以快排不仅存在时间复杂度退化的问题,还要避免递归导致的栈内存溢出问题。解决这个问题可以通过限制递归深度,也可以自己在堆上实现方法栈以突破内存限制。

    合适的数据遇到合适的算法

    虽然使用快排可以实现底层的排序方法,但当数据规模较小时使用快排可能会降低执行效率。虽然 O(nlog(n))O(n\log\left(n\right)) 在时间复杂度的通常意义上来说比 O(n2)O(n^2) 的更加优秀,但这是忽略常量、系数等的理想情况下,当数据规模较小的时候,常量、系数及低阶项都有影响时间复杂度的可能。

    例如,100+10log(10)&gt;10100+10\log\left(10\right)&gt;10。这样情况肯定会存在,在工业上实现排序方法时,也会对不同的数据规模应用不同类型的排序算法,这样可以提高排序方法的执行效率。

    Java 中的应用

    Java 中的 Collection 子类就实现了排序方法,我们一起探寻一番平时常用的 List 排序方法的秘密,需要注明此处分析的是 JDK 1.8 源码。

    因为 JDK 1.8 引入了 default 关键字,可以允许在 interface 中定义默认的方法实现(感觉 Abstract Class 的功能被削弱),在 List 中有 sort 方法的默认实现。

    default void sort(Comparator<? super E> c) {
      Object[] a = this.toArray();
      Arrays.sort(a, (Comparator) c);
      ListIterator<E> i = this.listIterator();
      for (Object e : a) {
        i.next();
        i.set((E) e);
      }
    }
    

    Arrays.sort 暴露了其实 List 使用的是 Arrays 的排序方法,继续跟进。

    public static <T> void sort(T[] a, Comparator<? super T> c) {
      if (c == null) {
        sort(a);
      } else {
        if (LegacyMergeSort.userRequested)
          legacyMergeSort(a, c);
        else
          TimSort.sort(a, 0, a.length, c, null, 0, 0);
      }
    }
    

    LegacyMergeSort.userRequested 来自启动参数 java.util.Arrays.useLegacyMergeSort,可以让用户通过启动参数使用旧的排序方式。默认情况下是使用 TimSort,也是一种排序算法。接着分析一下 legacyMergeSort 方法,毕竟一看名字就知道是我们熟悉的归并排序。

    private static void legacyMergeSort(Object[] a) {
      Object[] aux = a.clone();
      mergeSort(aux, a, 0, a.length, 0);
    }
    
    private static void mergeSort(Object[] src,
                    Object[] dest,
                    int low,
                    int high,
                    int off) {
      int length = high - low;
    
      // Insertion sort on smallest arrays
      if (length < INSERTIONSORT_THRESHOLD) {
        for (int i=low; i<high; i++)
          for (int j=i; j>low &&
                ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
            swap(dest, j, j-1);
        return;
      }
    
      // Recursively sort halves of dest into src
      int destLow  = low;
      int destHigh = high;
      low  += off;
      high += off;
      int mid = (low + high) >>> 1;
      mergeSort(dest, src, low, mid, -off);
      mergeSort(dest, src, mid, high, -off);
    
      // If list is already sorted, just copy from src to dest.  This is an
      // optimization that results in faster sorts for nearly ordered lists.
      if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
        System.arraycopy(src, low, dest, destLow, length);
        return;
      }
    
      // Merge sorted halves (now in src) into dest
      for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
        if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
          dest[i] = src[p++];
        else
          dest[i] = src[q++];
      }
    }
    

    legacyMergeSort 对排序数组克隆之后调用 mergeSort 方法,mergeSort 方法的主体部分和常规的归并排序一样,也是获取中间点,然后分区,分区再进行归并排序,对分区数组合并时进行排序。

    int destLow  = low;
    int destHigh = high;
    low  += off;
    high += off;
    int mid = (low + high) >>> 1;
    mergeSort(dest, src, low, mid, -off);
    mergeSort(dest, src, mid, high, -off);
    
    // Merge sorted halves (now in src) into dest
    for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
      if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
        dest[i] = src[p++];
      else
        dest[i] = src[q++];
    }
    

    不过在合并排序的时候增加了一步判断,当前一个分区的最大数不大于后一个分区最小数时两个分区已经自然有序,所以直接按前后顺序拼接两个数组即可,避免了循环比较合并数组。

    // If list is already sorted, just copy from src to dest.  This is an
    // optimization that results in faster sorts for nearly ordered lists.
    if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
      System.arraycopy(src, low, dest, destLow, length);
      return;
    }
    

    对于递归的终止条件也进行了不同的处理,当分区数据规模小于 INSERTIONSORT_THRESHOLD (这个常量表示启用插入排序的阀值)时,使用插入排序对数据排序处理并终止递归。

    int length = high - low;
    
    // Insertion sort on smallest arrays
    if (length < INSERTIONSORT_THRESHOLD) {
      for (int i=low; i<high; i++)
        for (int j=i; j>low &&
              ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
          swap(dest, j, j-1);
      return;
    }
    

    总结

    快排虽然存在缺点,但使用三点取中法、随机法解决分区不平衡问题,使用限制递归深度、自定义实现方法栈解决递归过深问题后,在实际生产中被广泛应用,不过为了提高排序方法的执行效率一般会根据数据规模的变化采用适合的排序算法。


    文章中如有问题欢迎留言指正
    数据结构与算法之美笔记系列将会做为我对王争老师此专栏的学习笔记,如想了解更多王争老师专栏的详情请到极客时间自行搜索。

    展开全文
  • 我们知道符合条件的数据结构栈、队列和其它。 <p><strong>2.非线性结构其逻辑特征是一个节点元素可以多个直接前驱或多个直接后继。 那么,符合条件的数据结构图、树和其它。 嗯~了解一下就行...
  • ISAPI 筛选器可以截取甚至修改传入和传出的数据。ISAPI 筛选器可以应用于很多方面,包括: • 身份验证和授权。 • 记录和监视。 • HTTP 压缩。 • URL 重写。 虽然 ISAPI 筛选器可用于执行 URL 重写,但本文...
  • 问题1-16:在教材1.7.2节提到协议有三个要素,即语法、语义和同步。语义是否已经包括了同步意思? 问题1-17:为什么协议不能设计成100%可靠? 问题1-18:什么是因特网摩尔定律? 第2章 物理层 问题2-1:...
  • Python数据内容

    2019-09-13 01:40:53
    Python字符串教程字符串作为python中最为常见的种结构,它最典型的特征就是引号,无论是单引号,或是双引号,还是引号,它们都是字符串。""" 字符串str...
        

    Python字符串教程

    字符串作为python中最为常见的一种结构,它最典型的特征就是有引号,无论是单引号,或是双引号,还是三引号,它们都是字符串。

    """

       字符串string, 从左向右从0开始,从右向左-1,-2。

    """

    a = "abcdef"

    print(a[2])

    print(a[-2])

     

    """

       字符串的基本操作, python中的字符串是不可变的,会拷贝一份进行修改,原string不变

       切割,并没有slice函数直接中括号,中间使用**冒号**隔开 [起始:结束:步长]

    """

    print(a[0:3])   # abc

    print(a[0:5:2]) # ace 或者是省略直接写冒号

    print(a[::2])   # ace 步长为2表示隔着读取

    print(a[1:4:2])   # bd 从b开始读取

    print(a[::-2])   # fdb 步长为负数表示从右到左,倒着读

    print(a[-1:-4:-2])   # fd 步长为负数表示从右到左,倒着读

    print("===========================")

     

    """

       a.capitalize()  字符串**首字母**进行大写

       a.title()  字符串**每个单词的首字母**进行大写

      a.startswith()  字符串是否以某个字串开始

      a.endswith()  字符串是否以某个字串结尾

       a.lower()  字符串所有字母进行小写

       a.upper()  字符串所有字母进行大写

    """

    b = "hello world"

    print(a.capitalize())

    print(b.title())

    print(a.startswith("ab"))

    print(a.endswith("ab"))

    print(a.lower())

    print(a.upper())

    print(a.islower())

    print(a.isnumeric())

     

    """

       a.ljust(self, width, fillchar) 字符串进行左对齐,字符串占用的长度和需要填充的字符

       a.rjust(self, width, fillchar) 字符串进行右对齐,字符串占用的长度和需要填充的字符

       a.center(self, width, fillchar) 字符串进行居中,字符串占用的长度和需要填充的字符

       a.lstrip(char) 删除字符串左边的字符,不写参数的话去除的是左边空格,相当于左边trim()

       a.rstrip(char) 删除字符串右边的字符,不写参数的话去除的是右边空格,相当于右边trim()

       a.strip(char) 删除字符串两边的字符,不写参数的话去除的是两边空格,相当于java的trim()

    """

    a = "abcdef"

    print(a.ljust(10"0"))  # abcdef0000

    print(a.rjust(10"0"))  # 0000abcdef

    print(a.center(10"0"))  # 00abcdef00

    print(a.lstrip("0"))

    print(a.rstrip("0"))

    print(a.strip("0"))

     

    """

      a.partition("b") 将字符串以"b"字,分割,如果b在中间且只有一个b,那么返回一个数组[前,"b",后]

       a.splitlines()   将字符串逐行分割,返回一个list,非数组,按需求进行选择方法

       a.isalpha()      字符串是否全是字母,不论大小写,返回bool

       a.isdigit()      字符串是否全是数字,返回bool

       a.isalnum()      前两个的集合体al + num,判断字符串是否包含数字或者字母或者混合也行

       a.isspace()      字符串是否只包含空格

      a.join(["xxx","yyy"])     list中每个元素的后面都插入a字符串

     

    """

    b = "ab\ncd\nef"

    print(a.partition("b")[1])  # ('a', 'b', 'cdef') -> b

    print(b.splitlines())  # ['ab', 'cd', 'ef']

    print(a.isalpha())

    print(a.isdigit())

    print(a.isalnum())

    print(a.isspace())

    print("x".join(["1""2""3"]))  # 1x2x3

    print("".join(["1""2""3"]))  # 123  将list迅速转换为一个字符串

     

    # "abcbdbebf" -> "acdef"

    c = "abcbdbebf"

    d = c.split("b")  # 去除字符串中所有的b,返回一个list

    result = "".join(d)  # list转换为字符串

    print(result)

     

    """

       a.ljust(self, width, fillchar) 字符串进行左对齐,字符串占用的长度和需要填充的字符

       a.rjust(self, width, fillchar) 字符串进行右对齐,字符串占用的长度和需要填充的字符

       a.center(self, width, fillchar) 字符串进行居中,字符串占用的长度和需要填充的字符

       a.lstrip(char) 删除字符串左边的字符,不写参数的话去除的是左边空格,相当于左边trim()

       a.rstrip(char) 删除字符串右边的字符,不写参数的话去除的是右边空格,相当于右边trim()

       a.strip(char) 删除字符串两边的字符,不写参数的话去除的是两边空格,相当于java的trim()

    """

    a = "abcdef"

    print(a.ljust(10"0"))  # abcdef0000

    print(a.rjust(10"0"))  # 0000abcdef

    print(a.center(10"0"))  # 00abcdef00

    print(a.lstrip("0"))

    print(a.rstrip("0"))

    print(a.strip("0"))

     

    """

      a.partition("b") 将字符串以"b"字,分割,如果b在中间且只有一个b,那么返回一个数组[前,"b",后]

       a.splitlines()   将字符串逐行分割,返回一个list,非数组,按需求进行选择方法

       a.isalpha()      字符串是否全是字母,不论大小写,返回bool

       a.isdigit()      字符串是否全是数字,返回bool

       a.isalnum()      前两个的集合体al + num,判断字符串是否包含数字或者字母或者混合也行

       a.isspace()      字符串是否只包含空格

      a.join(["xxx","yyy"])     list中每个元素的后面都插入a字符串

     

    """

    b = "ab\ncd\nef"

    print(a.partition("b")[1])  # ('a', 'b', 'cdef') -> b

    print(b.splitlines())  # ['ab', 'cd', 'ef']

    print(a.isalpha())

    print(a.isdigit())

    print(a.isalnum())

    print(a.isspace())

    print("x".join(["1""2""3"]))  # 1x2x3

    print("".join(["1""2""3"]))  # 123  将list迅速转换为一个字符串

     

    # "abcbdbebf" -> "acdef"

    c = "abcbdbebf"

    d = c.split("b")  # 去除字符串中所有的b,返回一个list

    result = "".join(d)  # list转换为字符串

    print(result)

     

     

     

    Python数组教程

    数组,一般科班出身的同学会叫它数组,因为在C里面我们是这么叫的,但是有些人更愿意直接叫他列表或list,叫起来更直接,它最典型的特征就是它的中括号[],基本看到这个就八九不离十了,他就是数组。

    """

       list列表元素的修改操作

    """

    a_list = [1,2,3,4]

    a_list[2] = "双击666"

    print(a_list)

     

    """

       查询list元素 (in, not in, index, count)

       为了避免index方法找不到的报错,解决方案:

       1, 先判断是否in,然后再list.index进行获取

       2, 判断count非零即真,-1等负数也是真,再进行获取

    """

    if in a_list:

       print("存在")

    if 88 not in a_list:

        print("不存在list中")

     

    print(a_list.index(2))  # 查询某个元素的index, 找不到的话不返回-1,直接报错

    print(a_list.count(2))  # 查询某一个元素出现的次数

     

    if a_list.count(22):

       print("22元素存在可以安全的获取索引:%d" % a_list.index(22))

    else:

       print("元素不存在列表中")

     

     

    """

       list删除元素

       del 是一个内置函数,并不是属性, del 函数直接销毁对象

       pop 是属性,pop()默认删除最后一个,pop(1)删除索引为1的元素,并且返回该元素

       remove 是属性, pop是知道索引进行删除,remove是知道obj进行删除

       clear 清空为[]

    """

    b_list = [1234]

    del b_list[2]   # del b_list的话会直接删除b_list整个list,销毁对象,再print的话就话undefined

    print(b_list)

     

    print(b_list.pop(0))

    b_list.remove(2)    # remove不存在的元素会抛异常报错

    b_list.clear()

    print(b_list)

     

    """

       list元素的排序

       sort() 默认无参数是从小到大

       reversed(list) 整个列表直接反过来,返回值是一个新的list

    """

    import random

     

    a_list = []

    for in range(10):

       a_list.append(random.randint(0200))

    print(a_list)

    a_list.sort()

    print(a_list)

     

    a_list.sort(reverse=True)   # 降序,从大到小

    print(a_list)

     

    new_list = reversed(a_list)     # [12,10,7,9] -> [9,7,10,12]

    print(new_list)

     

     

    """

       一个学校,三个办公室, 八位老师进行随机分配办公室

    """

    school = [[], [], []]

    teacher_list = list("ABCDEFGH")

     

    for name in teacher_list:

       index = random.randint(0,2)

       school[index].append(name)

    print(school)

     

     

     

    Python元组教程

    元组没什么好说的,和数组几乎一模一样,但是它不可以被修改,也就是说,所有适用于数组修改的方法,它统统都没有。元组的主要特征是一对小括号()。元组也有点比较特殊的地方,如果是单元素,一定要注意加上逗号,注意看下面的特例。

    """

       字符串表示:"", '', """"""

      list表示:[], 可修改

       元组的表示:(), 元组的元素不能进行修改,

       元组中如果只有一个元素的话,后面加上逗号表明是一个tuple,否则就是元素真实类型

    """

    a_tuple = (13.14"Hello"True)

    empty_tuple = ()

    empty_tuple2 = tuple()

     

    # 特例

    b_tuple = (1)    # type = int

    c_tuple = (1,)    # type = tuple

     

    """

       访问元组tuple

       查询的话和list一样使用count, index

    """

    print(a_tuple[2])

    # a_tuple[1] = "哈哈" 元组的元素不能重新赋值和修改,因为tuple是不可变的

     

    print(a_tuple.count(1))    # 元组中1对象出现的次数是2, 因为Ture在计算机眼中就是1

    print(a_tuple.index(3.14))

      

     

     

    Python字典教程

    字典这个东西在我们的现实生活中就是作查询用的,靠一个字查询到这个字的全部意思。那在python里面也差不多这个意思。一个索引词对应一个值 A: aaaaa,字典的特征有两个,第一个就是一个索引对应一个值,用冒号进行对应,第二个特征就是大括号{}。

    """

       字典数据类型dictionary表示方法: 花括号{}

    """

     

    a_dict = {"name""张三""age"20"id""007"}

    print(a_dict)

    b_dict = {}

    c_dict = dict()

     

     

    """

       字典的常见操作

       字典的key必须是**不可变**,可以是任意类型,元组也可以为key,因为元组是不可变的

       注意字典的key必须不可变但是可以重复, 重复的话获取的是最后一个

    """

    d_dict = {(1,2,3): "元组value01",

             "name""张三",

             "info": {"address""石家庄""country""中国"},

             (1,2,3): "元组value02"}

     

    print(d_dict[(1,2,3)])

    print(d_dict["info"]["country"])

     

    """

       字典修改元素的value, 前提是key存在,

       添加元素: 否则就会新增一个key-value

       删除元素:del python内置函数可以用在list, tuple和字典都可以用

    """

    d_dict["name"] = "李四"

    d_dict["name2"] = "王五"  # name2 不存在, 直接就会添加进去

    del d_dict["name2"]

    d_dict.clear()

    print(d_dict)

     

    """

       len() 字典的长度

       keys()  返回字典中所有的key的集合, 转化为list类型

       values() 返回字典中所有的value的集合, 转化为list类型

       items()  返回的是一对对key-value以元组的形式

    """

    print(len(a_dict))

    print(list(a_dict.keys()))    # dict_keys(['name', 'age', 'id']) -> ['name', 'age', 'id']

    print(list(a_dict.values()))

    print(list(a_dict.items())[1][1])     # [('name', '张三'), ('age', 20), ('id', '007')]

     

    """

       python3中取消了字典的has_key方法,使用的是setdefault

       使用的是setdefault("key", "找不到的默认值"), 找不到的话会修改添加新的key到字典中

       get(key, 默认值) 和setdefault的作用基本一样, 但是不会添加新的key,原来dict不会变

    """

    if "name" in a_dict:

       print("有一个key为name的。")

    else:

       print("字典中没有一个key叫做name")

     

    print(a_dict.setdefault("name1""name的默认值"))    # 找不到name1, 添加进去

    print(a_dict)

    print(a_dict.get("name2""name的默认值"))    # 找不到name2, 但是不会添加进去

    print(a_dict)

     

     

    """

       字典的遍历,

    """

    a_dict = {"name""张三""age"20"id""007"}

     

    for key in a_dict.keys():

       print(key)

     

    for value in a_dict.values():

       print(value)

     

    for item in a_dict.items():     # 遍历字典的元素,返回一个个元组(),()

       print(item)

     

    for key, value in a_dict.items():     # 遍历字典的键值对

       print(key, "->", value)

     

    str1 = "xxx"

    str2 = "yyy"

    print(str1, str2)   # print多个变量, 第二个参数默认是一个空格:xxx yyy

    print(str1, "--->", str2)   # xxx ---> yyy

     

    """

       enumerate(list / tuple等带有索引的数据结构)可以获得index

    """

    a_list = ["张三""李四""王五"]

    a_tuple = ("张三""李四""王五")

     

    for index, temp in enumerate(a_list):

       print(index, "-->", temp)

     

     

    Python集合(SET)教程

    Set是python里面比较特殊的一个集合,它也是由大括号{}做成的,但是呢,它里面的元素排列和数组一样,这样{1,2,4,6},set最特别的地方它里面的元素是不可以重复且没有顺序的,这也就间接告诉我们,他不可以直接用中括号进行取值,它可以为list进行去重。

    """

       集合set表示花括号{}, 无序不可重复,重读的话只保留一份,python自动去重操作

       add() 添加到set中, 相当于list中的append

       update(可迭代对象), 类似于list中的extend, 将可迭代的最小单元add到set中

    """

    a_set = {1,3,5,7,3}

    print(a_set)       # {1, 3, 5, 7} 去重操作

     

    b_set = set()

    c_set = {}  # 指的是空的字典,并不是集合set类型

     

    a_set.add(11)

    a_set.update("abcd")

    print(a_set)

     

    """

       set中的删除

       remove(obj), set无序,只能根据obj进行删除,找不到obj的话异常

       pop(), 因为set无序, 删除的并不是最后一个,而是随机的删除一个元素

       discard(), 元素存在删除, 不存在则不会发生异常

    """

    a_set.remove(1)

    a_set.pop()

    a_set.discard(111)   # set中的discard安全一点,不会异常

    print(a_set)

     

    """

       多个set集合的操作, 交集并集主要用在多个set的去重

       & -> 交集

       | -> 并集

    """

    set1 = {1,2,3,4}

    set2 = {3,4,5,6}

    print(set1 & set2)

    print(set1 | set2)

     

    # 去重的话讲list转换为set的话直接迅速, 不需要手动判断

    a_list = [1343456]

    print(set(a_list))

     

    # 利用set集合的特点,进行多个list的去重, 将每一个list转换为set求交集即可,一行代码搞定

    b_list = [1234]

    c_list = [345]

    print(set(b_list) | set(c_list))

     

     

    """

       字符串, list, 元组, 字典等运算符公共方法

    """

    print([1,2] + [3,4])    # [1, 2, 3, 4]

    print([1,2] * 4)        # [1, 2, 1, 2, 1, 2, 1, 2]

    print(in [1,2,3])     # True

    print(not in [1,2,3]) # False

    640?wx_fmt=png

    展开全文
  • C++常见面试问题解答

    2020-02-11 04:43:49
    把一组数据结构和处理它们的方法组成对象,把相同行为对象归纳为类,通过类封装隐藏内部细节,通过类继承实现特化、泛化,通过多态实现基于对象类型动态分派。 2、面向对象和基于对象区别? 面向对象的三...
  • 数据存储--栈

    2017-05-09 17:38:00
    常见的三种数据存储类型:栈、队列和优先队列。其不同于数组类型,类似链表、数等。它们适用于数据库应用中作数据记录,方便作一些增删改,而本次所述的这三种,通常用作算法辅助工具。并且不像数组中是通过下标...
  • o 3.11 为什么 sizeof 返回值大于结构的期望值, 是不是尾部填充? o 3.12 如何确定域在结构字节偏移? o 3.13 怎样在运行时用名字访问结构域? o 3.14 程序运行正确, 但退出时却 ``core dump''了,...

空空如也

空空如也

1 2 3 4 5 ... 14
收藏数 267
精华内容 106
关键字:

常见的数据结构有三种它们是

数据结构 订阅