数据结构-线性表基本操作

线性结构的特点:
线性结构是最简单最直接的数据关系,数据元素之间一一对应。

线性表的概念

线性表是由n个类型相同数据元素的有限序列。

线性表的特点:

同一性:线性表是由同类数据元素组成的,每一个a必须是同一数据对象

有穷性:线性表是由有限个数据元素组成,表长度就是表中数据元素的个数

有序性:线性表中相邻数据元素之间存在着序偶关系

抽象数据类型的使用:

由于抽象数据类型定义了相应模型上的基本 运算集,可如同使用整形类型的加减乘除运算集合一样,只要列出线性表抽象数据类型LinearList 就可以直接使用其上的基本运算集

抽象数据类型的使用:

抽象数据类型一经定义,就可以多次使用
在实际问题中可利用线性表抽象数据类型的9种基本运算的组合实现对线性表进行合并、分拆、排序等多种需求。

1、线性结构的特点

线性结构是最简单、最基本的结构,数据元素间是一一对应关系。

2、线性表定义

是由n个数据元素的有限序列。除第一个和最后一个元素以外,其余的每个元素都只有唯一的直接前驱和直接后继。

3、线性表抽象数据类型定义

线性表ADT包括抽象数据类型的名称及数据元素、结构关系、基本操作集合三部分。

线性表的顺序存储结构

节点顺序存,节点线性化

类型和变量的区别:
例如:两室一厅就是一个类型的定义,是一个类型是一个规格,这样301,302 这种门牌号都可以使具有这种规格的空间,这就是变量。

自定义类型定义了一种规格,如顺序表的数据类型定义SeqList

typedef  struct
{
	ElemType elem[MAXSIZE]   //线性表占用的数组空间
	int last;				//线性表的最后一个元素在数组中的位置下标
	
}SeqList;

(2)变量是规格类型的具体空间,两种定义方式

  • 将L定义为 Seql list:类型的变量,如 Seqlist L 将顺序表定义为一个变量。使用的时候我们
    可通过属性访问方式L.elem[i-1]访问顺序表中序号为i的元素ai。

  • 将L定义为指向 Seqlist类型的指针变量,如 SeqList *L 可通过指针访问方式L->elem[i-1]访问顺序表中序号为i的元素ai。

类型是一种规格的定义,而变量是一种空间的定义。

线性表的基本运算

增删改查

在上面的定义中,我们通过一个结构体,进行了一个简单线性表的定义,我们在C语言或者C++z中可以通过一个结构体来进行定义,在Java中没有结构体,我么可以通过一个类来进行线性表的表示。

使用Java语言先定义一个线性表 ,然后我们再定义其中的基本操作

Java JDK中有ArrayList和LinkedList两个类很好的实现了顺序存储和链式存储。因此学习数据结构的最好方式是去研究JDK源码。

我们可以看一下Java中ArrayList和LinkedList的区别:

  1. ArrayList和LinkedList可想从名字分析,它们一个是Array(动态数组)的数据结构,一个是Link(链表)的数据结构,此外,它们两个都是对List接口的实现。ArrayList是数组队列,相当于动态数组;LinkedList为双向链表结构,也可当作堆栈、队列、双端队列

  2. 当随机访问List时(get和set操作),ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。

  3. 当对数据进行增加和删除的操作时(add和remove操作),LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。

  4. 从利用效率来看,ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。

下面使用Java实现一个顺序表

首先定义一个线性表,并定义线性表中的插入删除的相关的操作。


    package com.shunxubiao;
    
    /***
     * 
     * @author lei
     *
     */
    public class MyArrayList {
    	
    	//定义一个用来保存数据的数组
    	private Object arr[];	
    	//定义一个空数组,用来初始化空数组
    	private Object[] DEFAULT_EMPTY = {};
    	//数组的初始容量,我们可以参照ArrayList源码,数组的初始容量为10
    	private  static final int DEFAULT_SIZE = 10;
    	//数组的大小,也就是数组的最大容量
    	private int maxSize;
    	//定义线性表的大小,线性表的当前个数
    	private int size;
    	
    	//带参构造方法,提供能构造指定容量的空列表
    	
    	public MyArrayList(int inittalSize){
    		if (inittalSize > 0) {
    			this.arr = new Object[inittalSize];
    			this.maxSize = inittalSize;
    		}else if (inittalSize == 0) {
    			this.arr = DEFAULT_EMPTY;
    		}else {
    			throw new IllegalArgumentException("不能为负,非法容量"+inittalSize);
    		}
    	}
    	
    	//空参构造,用来初始化一个空数组
    	public MyArrayList(){
    		this.arr = DEFAULT_EMPTY;
    	}
    	   
    	
    }

    
    //往线性表中指定位置插入数据
	//在指定位置插入元素,首先就是需要判断插入位置是否正确,然后判断数组长度是否越界,
	//如果已经满了我们需要重新增加数组的长度,一般是增加1.5倍长度,ArrayList JDK源码中也是增加1.5倍的数组长度。
	//然后移动数组元素,空出需要插入的位置,最后把数据插入到数组中。


    //在数组的指定位置插入元素。
	public void insert(int i,Object elem){
		//首先判断数组插入的位置是否合法
		if (i < 0) {
			new IllegalArgumentException("插入位置不合法");
		}
		if(i > size){
			new IllegalArgumentException("插入位置越界,当前数组的大小为:"+size);
		}
		
		Object oldArr[];
		Object newArr[];//用来存放扩容后的容量
		//如果当前线性表中数组为满的,需要增加数组的存储空间
		if (i == maxSize) {		
			oldArr = arr;			
			newArr = new MyArrayList[(int) (maxSize*1.5)];
			//把旧数组中的元素赋值到新的数组中
			for (int j = 0; j < newArr.length; j++) {
				newArr[j] = oldArr[j];
			}			
			maxSize = (int) (maxSize*1.5);
			arr = newArr;
		}
		
		//如果插入的位置是最后一个元素,不需要移动元素
		if (i == size) {
			arr[i] = elem;
			size++;
			return;
		}
		
		//如果插入的不是最后一个位置,需要移动元素,先移动位置,空出带插入位置元素
		for (int j = size;j > i;j--) {
			arr[j] = arr[j-1];
		}
		//移动完之后,插入元素
		arr[i] = elem;
		size++;
		
		//查看数组中的元素
		for (int j = 0; j < arr.length; j++) {
			System.out.print("  " +arr[j]);
		}
		
	}
 

时间复杂度分析:

最好情况:在线性表的末尾插入,(i = size)元素后移的语句将不再执行,时间复杂度为O(1)

最坏情况:在表头插入,(即i=0)元素后移的语句将执行n次,时间复杂度为O(n)

平均情况:n/2

因此,线性表插入算法的时间复杂度为O(n)

    
    //移除指定位置的元素
	public void remove(int i,Object elem){
		//首先判断移除的位置时候合法
		if (i < 0) {
			new IllegalArgumentException("插入位置为负,不合法");
		}
		if (i > size) {
			new IllegalArgumentException("移除位置超越数组长度,当前长度为:"+size);
		}
		
		//判断是否是移动的最后一个元素,如果是最后一个元素不需要移动元素
		if (i == size-1) {
			arr[i] = null;
			size--;
			return;
		}
		
		//一般情况的处理
		arr[i] = null;
		//移动元素
		for (int j=i; j<size-1;j++) {
			arr[j] = arr[j+1];
		}
		arr[size-1]=null;//最后一个元素为空
		size--;
		
		//查看数组中的元素
		if (arr != null) {
            System.out.println("");
            for (int j = 0; j < arr.length; j++) {
                System.out.print(" " + arr[j]);
            }
        }
		
	}

时间复杂度分析:

最好情况:在线性表的末尾移除,(i = size)元素后移的语句将不再执行,时间复杂度为O(1)

最坏情况:在表头移除,(即i=0)元素后移的语句将执行n次,时间复杂度为O(n)

平均情况:n-1/2

因此,线性表插入算法的时间复杂度为O(n)

    
    
    //清空数据
    public void clear() {
    if (arr != null) {
    for (int i = 0; i < size; i++) {
    arrs[i] = null;
    }
    }
    size = 0;
    }

上面是最一种线性表的操作,下面再看一下线性表中对两个顺序表的合并操作。

【编写算法】:有两个顺序表LA和LB,其元素均为递增有序排列,编写算法,将两个有序表合并成一个递增有序的顺序表LC

【算法思路】

  • 1)初始化:LC为空表,设LC表的指示器k=0

  • 设两个指示器i,j分别指向表LA和LB的当前位置,初值均为0。

  • 2)比较循环:将LA.elem[]和LB.elem[]两元素进行比较,较小元素放入表LC中,且该表的指示器和G表的指示器k均加1移向下一个位置。如此下去,直到LA或LB表中一个表处理完毕为止。都是当前位置的元素做比较。

  • 3)复制循环:将未处理完的表中剩余元素通过循环逐一复制到LC表中。

【算法分析】由于两个待归并的表LA、LB本身就是有序表,且表LC的建立采用的是尾插法建表,插入时不需要移动元素,所以算法的时间复杂度O(LA->last+LB->last)

上面的代码,我们依旧使用Java进行实现。

我们首先定义一个线性表的结构,也就是定义一个线性表的类,线性表中定义一个数组然后定义一个指向数组最后一个元素的变量,提供该类的初始化有参构造方法。

SeqList.java


    package com.hebing;
    
    public class SeqList {
    	
    	public int[] array1;
    	public int last;	
    	
    	public SeqList(int[] array1) {
    		this.array1=array1;
    		if(array1!=null) {//判断是否为空
    			last=array1.length;
    		}
    	}   
    }

然后写线性表的合并方法,定义一个合并的类,我们按照上面的算法思路实现这个合并类。定义一个空表C 用来存放合并后的类。然后对表A和表B中的元素依次判断放到表C中。

Combine.java


    package com.hebing;
    
    public class Combine {
    	
    	public void Combine(SeqList A,SeqList B,SeqList C) {
    		int a=0,b=0,c=0;
    		
    		while(a<A.last&&b<B.last) {
    			if(A.array1[a]<B.array1[b]) {
    				C.array1[c++]=A.array1[a++];
    			}else {
    				C.array1[c++]=B.array1[b++];
    			}
    		}
    		
    		while(a<A.last) {
    			C.array1[c++]=A.array1[a++];
    		}
    		
    		
    		while(b<B.last) {
    			C.array1[c++]=B.array1[b++];
    		}
    		C.last=c;
    	}
    	
    }

测试方法:


    package com.hebing;
    
    import java.util.ArrayList;
    
    public class test {
    	
    	public static void main(String[] args) {
    		SeqList a = new SeqList(new int[] { 5,6,9 ,11}); 
    		SeqList b = new SeqList(new int[] { 2,8,10}); 
    		SeqList c = new SeqList(new int[a.array1.length + b.array1.length]);
    		
    		Combine cob=new Combine();
    		cob.Combine(a, b, c);
    		
    		  for(int i=0;i<c.array1.length;i++) {
    			  System.out.print(c.array1[i]+" ");
    		  }
    		  		  
    		  
    	}
    
    }

线性表的链式存储

上面学习的顺序存储结构是:一组连续单元依次存放表中各个元素
顺序存储结构的特点:便于随机存取,不适合动态的变化。

逻辑上相邻的元素在物理存储位置上也相邻。链式存储结构中,逻辑上相邻的元素在物理存储上不一定相邻。因此设计出结点来对应线性表的元素及元素之间的关系。结点包括两部分 :结点本身数据信息,元素之间的关联关系。线性表采用链式方式将结点链接起来的存储结构称为链表。

链式存储结构中结点包括两部分不仅包括结点本身信息,还要包括关联关系部分。线性表采用链式方式将结点链接起来的存储结构称为链表。

链式存储结构分为单链表、循环单链表、双向链表和静态链表。

  • 从链接方式看,可分为单链表、循环链表和双向链表
  • 从实现角度看,可分为动态链表和静态链表。
  1. 单链表结构

链表中的结点包括数据域和指针域两个域

数据域data用来存储结点的值

指针域next用来存储结点本身的信息,邻接关系由后继指针指示其位置。

线性链表(单链表):

用一组任意的存储单元存放线性表的结点,每个结点的唯一后继依靠一个结点指针维持。

(这组存储单元可以是连续的也可以是不连续的、甚至是零散的存储在内存的任何位置。即链表结点的逻辑顺序和物理顺序不一定相同。)

  • 头指针H指向第一个结点。
  • 最后一个结点的指针域为“空”(NULL)

**注意: 链表中头指针,头结点,首结点的关系
链表中头指针指向单链表开始(H)
带头结点的链表中,头指针指向头结点,头结点指向首结点。
无头结点的链表中,头指针指向首结点。
**

单链表的基本运算

链表是一种重要的数据结构,在Java中,HashMap等集合的底层结构都是链表结构。

链表以结点作为存储单元,这些存储单元可以是不连续的。每个结点由两部分组成:存储的数值+前序结点和后序结点的指针。即有前序结点的指针又有后序结点的指针的链表称为双向链表,只包含后续指针的链表为单链表

链表是一种线性表但是并不会按顺序来存储元素

Java中单链表采用Node实体类类标识,其中data为存储的数据,next为下一个节点的指针:


    package com.lianbiao;
    
    /**
     * 链表结点的实体类
     *
     */
    
    public class Node {
    	Node next = null;//下一个结点
    int data;//结点数据
    
    public Node(int data){
    this.data = data;
    }
    
    }
  1. 往链表中插入元素

网链表中插入元素有两种方法,一种是采用头插法。一种是采用尾插法,头插法就是每次网表头插入元素,尾插法就是从表单额末尾依次插入元素。

采用尾插法,必须增加一个节点用来指示链表的末尾节点。

用Java实现尾插法建立链表:

	/**链表的根结点*/
    
	Node root = null;
        
    /**
     * 链表添加结点:
     * 找到链表的末尾结点,把新添加的数据作为末尾结点的后续结点
     * @param data
     */
    public void addNode(int data){
        Node newNode = new Node(data);
        if(root == null){
            root = newNode;
            return;
        }
        Node temp = root;
        while(temp.next != null){
            temp = temp.next;
        }
        temp.next = newNode;
    }

  1. 删除链表中的数据

删除链表中的数据,有两种方式进行删除,首先我们可以删除指定位置上的元素。我们还可以按值删除链表中的元素。

首先
按值删除链表中的元素。

删除结点,主要是查找删除结点的前驱结点。然后改变前驱结点的指向就可以了。


    public boolean deleteNodeData(int data){
    	Node curNode = root;
    	
    	if (curNode != null && curNode.data == data) {
			root = curNode.next;
			return true;
		}
    	
    	if (curNode != null ) {    		
    		while(curNode.next.data != data){
    			curNode = curNode.next;
    		}    		
    		curNode.next = curNode.next.next;
		}
    	
    	return true;
    }

按位置删除链表中的元素


    public boolean deleteNode(int index){
        if(index<1 || index>length()){//待删除结点不存在
            return false;
        }
        if(index == 1){//删除头结点
            root = root.next;
            return true;
        }
        Node preNode = root;
        Node curNode = preNode.next;
        int i = 1;
        while(curNode != null){
            if(i==index){//寻找到待删除结点
                preNode.next = curNode.next;//待删除结点的前结点指向待删除结点的后结点
                return true;
            }
            //当先结点和前结点同时向后移
            preNode = preNode.next;
            curNode = curNode.next;
            i++;
        }
        return true;
    }


  1. 求单链表的长度操作

在顺序表中,线性表的长度是它的属性,数组定义时就已确定

在单链表中,整个链表由“头指针”来表示,单链表的长度在从头到尾遍历的过程中统计计数得到

【算法思路】采用“数”结点的方法求出单链表的长度。即从“头”开始“数”用指针p依次指向各个结点,一直“数”到最后一个结点(p->nextNUL),从而得到单链表的长度

  • 顺链头开始,计数器j初值为0
  • 当前指针ρ指向链表L的首元结点 p=L->next
  • p依次往后(计数j+)直到表尾(p==NULL)

求表长度的操作就是计算单链表中数据结点的个数,需要从第一个结点开始顺序访问表中的每一个结点,为此需要设置一个计数器变量,每访问一个结点,计数器加1,直到访问出空节点为止。

java代码实现


    /**
     * 求链表的长度
     * @return
     */
    public int length(){
        int length = 0;
        Node curNode = root;
        while(curNode != null){
            length++;
            curNode = curNode.next;
        }
        return length;
    }

  1. 输出链表中的数据

    /**
     * 打印结点
     */
    public void printLink(){
        Node curNode = root;
        while(curNode !=null){
            System.out.print(curNode.data+" ");
            curNode = curNode.next;
        }
        System.out.println();
    }

  1. 反转链表

在反转指针前一定要保存下个结点的指针


/**
     * 反转链表,在反转指针前一定要保存下个结点的指针
     */
    public void reserveLink(){
        Node curNode = root;//根结点
        Node preNode = null;//前一个结点
        while(curNode != null){
            Node nextNode = curNode.next;//保留下一个结点
            curNode.next = preNode;//指针反转
            preNode = curNode;//前结点后移
            curNode = nextNode;//当前结点后移
        }
        root = preNode;
    }

  1. 反向输出链表

反向输出链表有三种方式

  • 方式一:先反转链表,再输出链表,需要链表遍历两次
  • 方式二:把链表中的数字放入栈中再输出,需要维护额外的栈空间
  • 方式三:依据栈的思想,通过递归来实现,就是将先执行的数据压如栈中,再一次出栈
	
	//反转链表
    public void reservePrt(Node node){
        if(node != null){
            reservePrt(node.next);
            System.out.print(node.data+" ");
        }
    }

  1. 在不知道头结点的情况下删除指定结点

删除结点的重点在于找出其前结点,使其前结点的指针指向其后结点,即跳过待删除结点,

1、如果待删除的结点是尾结点,由于单链表不知道其前结点,没有办法删除
2、如果删除的结点不是尾结点,则将其该结点的值与下一结点交换,然后该结点的指针指向下一结点的后续结点


    public boolean deleteSpecialNode(Node n){
    if(n.next == null){
    return false;
    }else{
    //交换结点和其后续结点中的数据
    int temp = n.data;
    n.data = n.next.data;
    n.next.data = temp;
    //删除后续结点
    n.next = n.next.next;
    return true;
    }
    }

总结:

  • 1.单链表主要的有点是,不需要对数据元素的最大个数进行预设,可以无限量地存储数据元素。
  • 2.单链表插入和删除时,不需要移动大量的数据元素,可提高效率。

单链表主要的缺点是,每个节点中需要有一个指针,因此单链表的空间利用率略低于顺序表,

数据结构中常见面试题总结

1. 单链表

(1)编程实现一个单链表搜的建立/测长/打印。

如果实现单链表,我们首先需要做的就是实现一个结点的定义,在C语言或者是C++语言中,我们使用的是结构体进行定义的,在Java中我们常使用类来实现链表结点的定义,

我们可以定义一个Node类,来表示链表中的结点。首先定义Node类,在Node类中,我们需要定义存放结点值的变量以及指向下一个结点的结点。

Node.Java类


    package ListStudy;

	//定义一个用于表示结点的类
	public class Node {
    int data; //表示结点数据的变量
    Node next=null; //定义一个指向自己的指针

    //定义带参构造方法

    public Node(int data) {
        this.data = data;
    }
    }

定义完链表之后,我们需要定义实现链表中的方法,主要是实现链表的插入结点方法,测试链表的长度,打印链表中的值等方法,

MyLinkedList.java 链表方法类


    package ListStudy;

	/**
 	* 在该类中定义链表的基本操作
 	*/
	public class MyLinkedList {
    	//首先定义链表的头结点,链表的头结点默认为空
    	Node head = null;

	    /**
	     * 定义链表中添加结点的方法
	     * 在本例中采用的是尾插法建立单链表的方法
	     * @param data
	     */
	    public void addNode(int data){
	        Node newNode = new Node(data);//首先根据值建立一个结点,然后做插入位置的判断
	
	        //首先判断插入的位置,如果头结点为空则此时需要把元素插入到头结点上
	        if (head == null){
	            head = newNode;
	            return;
	        }
	        //如果头结点不为空则执行下面的语句
	        //首先定义一个结点变量用来表示头结点的值
	        Node temp = head;
	        while(temp.next != null){
	            temp = temp.next;
	        }
	        temp.next = newNode;
	
	    }

	    /**
	     * 打印链表中的结点
	     */
	
	    public void  printLink(){
	        //首先定义一个结点指向头结点,从头往后打印
	        Node temp = head;
	        while(temp != null){
	            //如果指向头结点的临时变量不为空,就继续把指向头结点的指针向下移动
	            System.out.println(temp.data + " ");
	            temp = temp.next;
	        }
	        System.out.println();
	    }
	
	    /***
	     * 求建立链表的长度
	     */
	    public int length(){
	        int length = 0;//定义一个变量用来记录链表的长度
	        Node temp = head;//定义一个变量用来指向头结点
	
	        while(temp != null){
	            length++;
	            temp = temp.next;
	        }
	        return length;
	
	    }
	
	}


上面定义完链表中结点的表示,以及链表中新增,求长,打印的方法之后,我们需要进行测试,测试方法如下:

testLink.Java 测试方法类


	    package ListStudy;
		
		public class testLink {
		    public static void main(String[] args) {
		        MyLinkedList myLinkedList = new MyLinkedList();
		
		        myLinkedList.addNode(1);
		        myLinkedList.addNode(2);
		        myLinkedList.addNode(3);
		        System.out.println("所建立链表的长度为"+myLinkedList.length());
		        myLinkedList.printLink();
		    }
		}


(2)编程实现单链表删除结点

删除链表中的结点的方法,有按照值删除的方法和按照链表位置删除的方法

要删除结点,只需要找到要删除结点前面的结点就行

我们继续在上面链表方法类MyLinkedList中添加操作链表的方法。。

书写按值查找和按照索引位置进行查询的方法


	    //首先按照指定的值删除结点
	    public boolean deleteNode(int value) {
	        //建立临时结点,指向当前结点,首先从头结点kaishi
	        Node temp = head;
	        //首先判断第一个结点是不是我们要找的结点,如果第一个结点就是需要寻找的结点,直接把下一个结点赋值给head结点
	        if (temp != null && temp.data == value) {
	            head = temp.next;
	            return true;
	        }
	
	        //如果第一个结点不是我们要找的值,则执行下面的判断
	
	        if (temp != null) {
	            //因为删除结点的时候,我们需要找到删除结点的前驱结点,所以我们就需要判断下一个结点的值是不是我们要找的值
	            while (temp.next.data != value) {
	                temp = temp.next;
	            }
	            //找到之后,我们需要把目标结点的下一个结点赋值给目标结点的上一个结点
	            temp.next = temp.next.next;
	        }
	
	        return true;
	
	    }
	
	    //上面删除链表中值是按照值来进行删除的,下面我们按照链表中值的索引位置来进行删除
	    public boolean deleteNode2(int index){
	        //首先判断索引的位置是否合法
	        if (index < 1 || index > length()){
	            return false;
	        }
	
	        //如果删除结点是头结点,则直接把头结点的下一个结点赋值给头结点
	        if (index == 1){
	            head = head.next;
	            return true;
	        }
	        //把头结点赋值给一个临时结点
	        Node preNode = head;
	        Node curNode = preNode.next; //把头结点的下一个结点当做当前结点
	        int i = 2;
	        while(curNode != null ){
	            if (i == index){
	                //寻找到待删除结点
	                preNode.next = curNode.next;
	                return true;
	            }
	            //把当前结点和当前结点的后续结点同时向下移动
	            preNode = preNode.next;
	            curNode = curNode.next;
	            i++;
	        }
	        return true;
	    }


(3)编程实现单链表的排序操作。

(4)编程实现单链表的逆序

(5)给一个单链表,不知道结点N的值,怎么样只遍历一次就可以求出中间结点,写出算法

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是可以用C++语言实现的代码: ```c++ #include <iostream> using namespace std; #define MaxSize 100 // 定义线性表的最大长度 typedef struct { int data[MaxSize]; // 用数组存储数据元素 int length; // 顺序表的当前长度 } SqList; // 定义顺序表类型 void InitList(SqList &L) { // 初始化顺序表 L.length = 0; } void InputList(SqList &L) { // 从键盘输入顺序表的数据元素 int n, i; cout << "请输入顺序表的长度:"; cin >> n; cout << "请输入" << n << "个正整数:" << endl; for (i = 0; i < n; i++) { cin >> L.data[i]; } L.length = n; } void PrintList(SqList L) { // 输出顺序表的数据元素 int i; for (i = 0; i < L.length; i++) { cout << L.data[i] << " "; } cout << endl; } void Intersection(SqList La, SqList Lb, SqList &Lc) { // 求两个顺序表的交集 int i, j, k; k = 0; for (i = 0; i < La.length; i++) { for (j = 0; j < Lb.length; j++) { if (La.data[i] == Lb.data[j]) { // 如果找到相同元素 Lc.data[k] = La.data[i]; // 将其存入新的顺序表中 k++; break; // 跳出内层循环,查找下一个元素 } } } Lc.length = k; // 新的顺序表的长度为k } int main() { SqList La, Lb, Lc; InitList(La); InitList(Lb); InitList(Lc); cout << "请输入第一个顺序表:" << endl; InputList(La); cout << "请输入第二个顺序表:" << endl; InputList(Lb); Intersection(La, Lb, Lc); cout << "两个顺序表的交集为:"; PrintList(Lc); return 0; } ``` 在这个程序中,我们定义了一个结构体 `SqList` 表示顺序表,包含一个数组 `data` 存储数据元素,以及一个整数 `length` 表示当前顺序表的长度。我们通过 `InitList` 函数对顺序表进行初始化,通过 `InputList` 函数从键盘输入顺序表的数据元素,通过 `PrintList` 函数输出顺序表的数据元素。最重要的是 `Intersection` 函数,它实现了求两个顺序表的交集,具体思路如下: 1. 定义一个整数 `k`,表示新的顺序表的长度,初始化为0。 2. 从第一个顺序表的第一个元素开始,依次与第二个顺序表的所有元素进行比较。 3. 如果找到相同元素,则将其存入新的顺序表中,并将 `k` 加1,然后跳出内层循环查找下一个元素。 4. 内层循环结束后,继续从第一个顺序表的下一个元素开始查找。 5. 最后,新的顺序表的长度为 `k`,即为两个顺序表的交集的长度。 我们在 `main` 函数中调用 `InitList` 函数对三个顺序表进行初始化,调用 `InputList` 函数从键盘输入前两个顺序表的数据元素,然后调用 `Intersection` 函数求两个顺序表的交集,最后调用 `PrintList` 函数输出新的顺序表的数据元素,即为两个顺序表的交集。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值