数据结构 - 1 顺序表

去编程就是去理解。
----Kristen Nygaard

数据结构和算法学习前言

有人说, 计算机的根本在于数据结构与算法, 这话不假。
现今计算机的发展趋势是体积越来越小, 而运算速度和存储能力越来越快。 而提升运算速度和存储 能力的一大办法就是研发更好的数据结构和算法。
从计算机的发展历史看来, 计算机的存储能力的发展速度比运算速度的发展速度要快很多, 所以现在人们对于程序内存的占用相对没有对于程序运行效率那么关注。
实现一件事可以有很多方法, 选择正确的方法, 我们可以更快更好的来完成一件事, 算法正是做事的方法, 每当我学习计算机领域前辈们发明的那些算法和数据结构时, 我无不为他们的智慧所折服。
当我们知道, 利用平衡树, 在一亿个数据里查找某个数据时, 我们只需要找不到30次, 我们会不会为平衡树的效率所惊叹?
算法和数据结构在计算机领域无处不在, 比如说用在路由转发的路径向量算法和路由选择算法, 谁又知道这些究竟为我们节省了多少时间呢? 可以说, 没有数据结构和算法, 也就没有现代如此高速的计算机。
计算机界的前辈们, 的确是一些很牛很牛的人, 他们使很多看似很难解决或者没法解决的问题, 变得如此美妙和神奇。


”如果, 如果我是说如果, 你是一个对编程无比爱好的人, 你学数据结构的目的, 既不是为了工作为了钱, 也不是为了学位和考试, 而只是为了更好地去感受编程之美。 啊, 你应该得到我的欣赏, 我想我非常愿意与你成为朋友----因为我自己也没有如此纯粹地去学习和应用它。“

线性表

生活中线性表无处不在, 譬如火车车厢, 譬如排队, 都是线性表

线性表是零个或多个元素组成的有限序列。
线性表分为顺序表和链表。

对于线性表来说:

  1. 元素是有顺序的, 第一个元素无前驱, 最后一个元素无后继。
  2. 线性表的元素数量是有限的。

顺序表

顺序表是线性表的子集, 对于顺序表来说用一段物理地址连续的存储单元依次存储数据元素, 通常使用数组存储, 并在数组上完成数据的操作。
一般分为静态顺序表动态顺序表:

  1. 静态顺序表: 使用定长数组存储
  2. 动态顺序表: 使用动态开辟内存的数组存储, 比如说vector

首先呈上老师的代码:

#include <stdio.h>
#include <malloc.h>

#define LIST_MAX_LENGTH 10

/**
 * Linear list of integers. The key is data.
 */
typedef struct SequentialList {
    int actualLength;

    int data[LIST_MAX_LENGTH]; //The maximum length is fixed.
} *SequentialListPtr;

/**
 * Output the list.
 */
void outputList(SequentialListPtr paraList) {
    for(int i = 0; i < paraList->actualLength; i ++) {
        printf("%d ", paraList->data[i]);
    }// Of for i
    printf("\r\n");
}// Of outputList

/**
 * Output the memeory for the list.
 */
void outputMemory(SequentialListPtr paraListPtr) {
    printf("The address of the structure: %ld\r\n", paraListPtr);
    printf("The address of actualLength: %ld\r\n", &paraListPtr->actualLength);
    printf("The address of data: %ld\r\n", &paraListPtr->data);
    printf("The address of actual data: %ld\r\n", &paraListPtr->data[0]);
    printf("The address of second data: %ld\r\n", &paraListPtr->data[1]);
}// Of outputMemory

/**
 * Initialize a sequential list. No error checking for this function.
 * @param paraListPtr The pointer to the list. It must be a pointer to change the list.
 * @param paraValues An int array storing all elements.
 */
SequentialListPtr sequentialListInit(int paraData[], int paraLength) {
	SequentialListPtr resultPtr = (SequentialList*)malloc(sizeof(SequentialList));
	for (int i = 0; i < paraLength; i ++) {
		resultPtr->data[i] = paraData[i];
	}// Of for i
	resultPtr->actualLength = paraLength;

	return resultPtr;
}//Of sequentialListInit

/**
 * Insert an element into a sequential linear list.
 * @param paraListPtr The pointer to the list. It must be a pointer to change the list.
 * @param paraPosition The position, e.g., 0 stands for inserting at the first position.
 * @param paraValue The value to be inserted.
 */
void sequentialListInsert(SequentialListPtr paraListPtr, int paraPosition, int paraValue) {
    // Step 1. Space check.
    if (paraListPtr->actualLength >= LIST_MAX_LENGTH) {
        printf("Cannot insert element: list full.\r\n");
        return;
    }//Of if

    // Step 2. Position check.
    if (paraPosition > paraListPtr->actualLength) {
        printf("Cannot insert element: the position %d is bigger than the list length %d.\r\n", paraPosition, paraListPtr->actualLength);
        return;
    }//Of if

    // Step 3. Move the remaining part.
    for (int i = paraListPtr->actualLength; i > paraPosition; i --) {
        paraListPtr->data[i] = paraListPtr->data[i - 1];
    }//Of for i

    // Step 4. Insert.
    paraListPtr->data[paraPosition] = paraValue;

    // Update the length.
    paraListPtr->actualLength ++;
}// Of sequentialListInsert

/**
 * Test the insert function.
 */
void sequentialInsertTest() {
	int i;
	int tempArray[5] = {3, 5, 2, 7, 4};

    printf("---- sequentialInsertTest begins. ----\r\n");

	// Initialize.
    SequentialListPtr tempList = sequentialListInit(tempArray, 5);
    printf("After initialization, the list is: ");
	outputList(tempList);

	// Insert to the first.
    printf("Now insert to the first, the list is: ");
	sequentialListInsert(tempList, 0, 8);
	outputList(tempList);

	// Insert to the last.
    printf("Now insert to the last, the list is: ");
	sequentialListInsert(tempList, 6, 9);
	outputList(tempList);

	// Insert beyond the tail.
    printf("Now insert beyond the tail. \r\n");
	sequentialListInsert(tempList, 8, 9);
    printf("The list is:");
	outputList(tempList);

	// Insert to position 3.
	for (i = 0; i < 5; i ++) {
		printf("Inserting %d.\r\n", (i + 10));
		sequentialListInsert(tempList, 0, (i + 10));
		outputList(tempList);
	}//Of for i

    printf("---- sequentialInsertTest ends. ----\r\n");
}// Of sequentialInsertTest

/**
 * Delete an element from a sequential linear list.
 * @param paraListPtr The pointer to the list. It must be a pointer to change the list.
 * @param paraPosition The position, e.g., 0 stands for inserting at the first position.
 * @return The deleted value.
 */
int sequentialListDelete(SequentialListPtr paraListPtr, int paraPosition) {
    // Step 1. Position check.
    if (paraPosition < 0) {
        printf("Invalid position: %d.\r\n", paraPosition);
        return -1;
    }//Of if

    if (paraPosition >= paraListPtr->actualLength) {
        printf("Cannot delete element: the position %d is beyond the list length %d.\r\n", paraPosition, paraListPtr->actualLength);
        return -1;
    }//Of if

    // Step 2. Move the remaining part.
	int resultValue = paraListPtr->data[paraPosition];
    for (int i = paraPosition; i < paraListPtr->actualLength; i ++) {
        paraListPtr->data[i] = paraListPtr->data[i + 1];
    }//Of for i

    // Step 3. Update the length.
    paraListPtr->actualLength --;

	// Step 4. Return the value.
	return resultValue;
}// Of sequentialListDelete

/**
 * Test the delete function.
 */
void sequentialDeleteTest() {
	int tempArray[5] = {3, 5, 2, 7, 4};

    printf("---- sequentialDeleteTest begins. ----\r\n");

	// Initialize.
    SequentialListPtr tempList = sequentialListInit(tempArray, 5);
    printf("After initialization, the list is: ");
	outputList(tempList);

	// Delete the first.
    printf("Now delete the first, the list is: ");
	sequentialListDelete(tempList, 0);
	outputList(tempList);

	// Delete to the last.
    printf("Now delete the last, the list is: ");
	sequentialListDelete(tempList, 3);
	outputList(tempList);

	// Delete the second.
    printf("Now delete the second, the list is: ");
	sequentialListDelete(tempList, 1);
	outputList(tempList);

	// Delete the second.
    printf("Now delete the 5th, the list is: ");
	sequentialListDelete(tempList, 5);
	outputList(tempList);

	// Delete the second.
    printf("Now delete the (-6)th, the list is: ");
	sequentialListDelete(tempList, -6);
	outputList(tempList);

    printf("---- sequentialDeleteTest ends. ----\r\n");

	outputMemory(tempList);
}// Of sequentialDeleteTest

/**
 * Locate an element in the list.
 * @param paraListPtr The pointer to the list.
 * @param paraValue the indicated value.
 * @return The position of the value, or  -1 indicating not exists
 */
int locateElement(SequentialListPtr paraListPtr, int paraValue) {
	for (int i = 0; i < paraListPtr->actualLength; i ++) {
		if (paraListPtr->data[i] == paraValue) {
			return i;
		}// Of if
	}//Of for i

	return -1;
}// Of locateElement

/**
 * Get an element in the list.
 * @param paraListPtr The pointer to the list.
 * @param paraPosition The given position.
 * @return The position of the value, or  -1 indicating not exists
 */
int getElement(SequentialListPtr paraListPtr, int paraPosition) {
    // Step 1. Position check.
    if (paraPosition < 0) {
        printf("Invalid position: %d.\r\n", paraPosition);
        return -1;
    }//Of if

    if (paraPosition >= paraListPtr->actualLength) {
        printf("Cannot delete element: the position %d is beyond the list length %d.\r\n", paraPosition, paraListPtr->actualLength);
        return -1;
    }//Of if

	return paraListPtr->data[paraPosition];
}// Of locateElement

/**
 * Clear elements in the list.
 * @param paraListPtr The pointer to the list.
 * @return The position of the value, or  -1 indicating not exists
 */
int clearList(SequentialListPtr paraListPtr) {
	paraListPtr->actualLength = 0;
}// Of clearList

/**
 The entrance.
 */
void main() {
	sequentialInsertTest();
	sequentialDeleteTest();
}// Of main

运行结果:

---- sequentialInsertTest begins. ----
After initialization, the list is: 3 5 2 7 4
Now insert to the first, the list is: 8 3 5 2 7 4
Now insert to the last, the list is: 8 3 5 2 7 4 9
Now insert beyond the tail.
Cannot insert element: the position 8 is bigger than the list length 7.
The list is:8 3 5 2 7 4 9
Inserting 10.
10 8 3 5 2 7 4 9
Inserting 11.
11 10 8 3 5 2 7 4 9
Inserting 12.
12 11 10 8 3 5 2 7 4 9
Inserting 13.
Cannot insert element: list full.
12 11 10 8 3 5 2 7 4 9
Inserting 14.
Cannot insert element: list full.
12 11 10 8 3 5 2 7 4 9
---- sequentialInsertTest ends. ----
---- sequentialDeleteTest begins. ----
After initialization, the list is: 3 5 2 7 4
Now delete the first, the list is: 5 2 7 4
Now delete the last, the list is: 5 2 7
Now delete the second, the list is: 5 7
Now delete the 5th, the list is: Cannot delete element: the position 5 is beyond the list length 2.
5 7
Now delete the (-6)th, the list is: Invalid position: -6.
5 7
---- sequentialDeleteTest ends. ----
The address of the structure: 12463664
The address of actualLength: 12463664
The address of data: 12463668
The address of actual data: 12463668
The address of second data: 12463672

在此我使用C++的泛型来实现顺序表极其各种操作

静态顺序表

头文件及定义
#include <iostream>
#include <stdarg.h>
#include <vector>
#define remilia int
#define isMyWife main

using namespace std;

template<class ElemType, int MAX_SIZE>
class SequentialList {
	private:
		// 数据的存储容器 
		ElemType data[MAX_SIZE];
		
		// 数组的实际元素数量 
		int actualLength;
		
	public:
		SequentialList(ElemType elem[], int paramsCount);
		SequentialList();
		virtual ~SequentialList();
		
		// 获得顺序表长 
		int getActualLength(); 
		bool isEmpty();
		bool isFull();
	
		// 输出顺序表所有元素 
		void outputList();
		
		// 在顺序表末尾插入一个元素 
		void pushBack(ElemType& elem);
		
		// 在线性表指定位置插入一个元素 
		void sequentialListInsert(int paraPosition, int paraValue);
		
		// 删除指定位置的元素 
		int sequentialListDelete(int paraPosition);
		
		// 根据值定位线性表中的元素 
		vector<int> locateElement(int paraValue);
		
		// 根据索引获取元素 
		int getElement(int paraPosition);
		
		// 清除顺序表 
		void clearList();
};
构造方法
template <class ElemType, int MAX_SIZE>
SequentialList<ElemType, MAX_SIZE>::SequentialList(ElemType elem[], int paramsCount) {
	if (paramsCount > MAX_SIZE) {
		throw "参数过多...";	
	}
	
	for (int i = 0; i < paramsCount; i++) {
		this -> pushBack(elem[i]);
	}
}

template <class ElemType, int MAX_SIZE>
SequentialList<ElemType, MAX_SIZE>::SequentialList() {
	this -> actualLength = 0;
}
顺序表的整表输出
template <class ElemType, int MAX_SIZE>
void SequentialList<ElemType, MAX_SIZE>::outputList() {
	for (int i = 0; i < this -> actualLength; i++) {
		printf("%d ", this -> data[i]);
	}	
	
	putchar('\n');
}
顺序表尾插
template <class ElemType, int MAX_SIZE>
void SequentialList<ElemType, MAX_SIZE>::pushBack(ElemType& elem) {
	if (!isFull()) {
		this -> data[this -> actualLength++] = elem;
	} else {
		throw "容量已满, 插入失败...";
	}
}
根据索引获取元素

顺序查找, 找到对应索引位置的元素后返回即可

template <class ElemType, int MAX_SIZE>
int SequentialList<ElemType, MAX_SIZE>::getElement(int paraPosition) {
	if (paraPosition >= actualLength || paraPosition < 0) {
		throw "参数非法... 原因: 获取位置大于已有位置或是获取位置小于0";
	}	
		
	return this -> data[paraPosition];
}
根据元素定位索引

顺序查找哪些元素和给定的元素值相同, 相同则把索引存在vector里, 最后返回, 如果没有找到, 则vector长度为0

template <class ElemType, int MAX_SIZE>
vector<int> SequentialList<ElemType, MAX_SIZE>::locateElement(int paraValue) {
	vector<int> v;
	v.clear();
	
	for (int i = 0; i < this -> actualLength; i++) {
		if (this -> data[i] == paraValue) {
			v.push_back(i);
		}
	}	
	
	return v;
}
插入元素

在插入元素时, 需要将插入位置所在的元素起, 它自身以及它后面的所有元素后移一位
在这里插入图片描述

template <class ElemType, int MAX_SIZE>
void SequentialList<ElemType, MAX_SIZE>::sequentialListInsert(int paraPosition, int paraValue) {
	// 判断越界情况 
	if (paraPosition < 0 || isFull() || paraPosition > this -> actualLength) {
		throw "参数非法, 插入失败... 原因: 插入位置大于已有元素数量或是容量已满或是插入位置小于0";
	}
	
	// 后移元素 
	for (int i = actualLength - 1; i >= paraPosition; i--) {
		this -> data[i + 1] = this -> data[i];
	}
	
	this -> data[paraPosition] = paraValue;
	this -> actualLength++;
}
删除元素

删除元素只需要将要删除的位置后面的元素全部前移一位即可
在这里插入图片描述

template <class ElemType, int MAX_SIZE>
int SequentialList<ElemType, MAX_SIZE>::sequentialListDelete(int paraPosition) {
	if (paraPosition > this -> actualLength || paraPosition < 0) {
		throw "参数非法, 删除失败... 原因: 删除位置大于已有元素数量或删除位置小于0";
	}	
	
	int temp = this -> data[paraPosition];
	
	for (int i = paraPosition; i < actualLength - 1; i++) {
		this -> data[i] = this -> data[i + 1]; 
	}
	
	this -> actualLength--;
	return temp;
}
清空表

只需要将表真实长度赋值为0

template <class ElemType, int MAX_SIZE>
void SequentialList<ElemType, MAX_SIZE>::clearList() {
	this -> actualLength = 0;
}
其他方法
template <class ElemType, int MAX_SIZE>
int SequentialList<ElemType, MAX_SIZE>::getActualLength() {
	return this -> actualLength;
}

template <class ElemType, int MAX_SIZE>
bool SequentialList<ElemType, MAX_SIZE>::isEmpty() {
	return this -> actualLength == 0;	
}

template <class ElemType, int MAX_SIZE>
bool SequentialList<ElemType, MAX_SIZE>::isFull() {
	return this -> actualLength == MAX_SIZE;	
}
测试删除
void sequentialListDeleteTest(SequentialList<int, 200> s) {
	// 随机种子 
	srand(time(NULL));
	
	// 随机生成测试样本 
	for (int i = 0; i <= 20; i++) {
		s.pushBack(rand());
	}
	
	printf("目前顺序表中的值有:");
	s.outputList();
	putchar('\n');
	
	// 随机生成测试删除点位 
	for (int i = 0; i <= 10; i++) {
		int idx = rand() % 10 + 1;
		
		// 确保测试点位合法 
		if (idx < s.getActualLength()) {
			// 先获取值 
			printf("被删除的点位是:%d, 它的值:%d\n", idx, s.getElement(idx));
			// 删除 
			s.sequentialListDelete(idx);
			// 输出删除后结果进行对照 
			printf("删除后的结果是:");
			s.outputList();
		}
	}
}
一组样本输出结果
目前顺序表中的值有:9310 18509 25831 25622 23806 28315 26042 22954 6749 18797 21679 26055 25947 11195 12340 26414 21376 32631 31422 21908 16517

被删除的点位是:5, 它的值:28315
删除后的结果是:9310 18509 25831 25622 23806 26042 22954 6749 18797 21679 26055 25947 11195 12340 26414 21376 32631 31422 21908 16517
被删除的点位是:4, 它的值:23806
删除后的结果是:9310 18509 25831 25622 26042 22954 6749 18797 21679 26055 25947 11195 12340 26414 21376 32631 31422 21908 16517
被删除的点位是:1, 它的值:18509
删除后的结果是:9310 25831 25622 26042 22954 6749 18797 21679 26055 25947 11195 12340 26414 21376 32631 31422 21908 16517
被删除的点位是:3, 它的值:26042
删除后的结果是:9310 25831 25622 22954 6749 18797 21679 26055 25947 11195 12340 26414 21376 32631 31422 21908 16517
被删除的点位是:3, 它的值:22954
删除后的结果是:9310 25831 25622 6749 18797 21679 26055 25947 11195 12340 26414 21376 32631 31422 21908 16517
被删除的点位是:1, 它的值:25831
删除后的结果是:9310 25622 6749 18797 21679 26055 25947 11195 12340 26414 21376 32631 31422 21908 16517
被删除的点位是:10, 它的值:21376
删除后的结果是:9310 25622 6749 18797 21679 26055 25947 11195 12340 26414 32631 31422 21908 16517
被删除的点位是:5, 它的值:26055
删除后的结果是:9310 25622 6749 18797 21679 25947 11195 12340 26414 32631 31422 21908 16517
被删除的点位是:5, 它的值:25947
删除后的结果是:9310 25622 6749 18797 21679 11195 12340 26414 32631 31422 21908 16517
被删除的点位是:2, 它的值:6749
删除后的结果是:9310 25622 18797 21679 11195 12340 26414 32631 31422 21908 16517
被删除的点位是:3, 它的值:21679
删除后的结果是:9310 25622 18797 11195 12340 26414 32631 31422 21908 16517
测试插入
void sequentialListInsertTest(SequentialList<int, 200> s) {
	// 随机种子 
	srand(time(NULL));
	
	// 随机生成测试样本 
	for (int i = 0; i <= 20; i++) {
		s.pushBack(rand());
	}
	
	printf("目前顺序表中的值有:");
	s.outputList();
	putchar('\n');
	
	// 随机生成测试插入点位 
	for (int i = 0; i <= 10; i++) {
		int idx = rand() % 10 + 1;
		// 随机生成值 
		int elem = rand();
		 
		// 确保测试点位合法 
		if (idx < s.getActualLength()) {
			// 先获取值 
			printf("被插入的点位是:%d, 它之前的值:%d, 插入:%d\n", idx, s.getElement(idx), elem);
			// 插入 
			s.sequentialListInsert(idx, elem);
			// 输出插入后结果进行对照 
			printf("插入后的结果是:");
			s.outputList();
		}
	}
}
一组样本结果
插入后的结果是:10274 10793 20114 13644 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:3, 它之前的值:13644, 插入:31931
插入后的结果是:10274 10793 20114 31931 13644 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:4, 它之前的值:13644, 插入:19115
插入后的结果是:10274 10793 20114 31931 19115 13644 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:2, 它之前的值:20114, 插入:11818
插入后的结果是:10274 10793 11818 20114 31931 19115 13644 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:7, 它之前的值:19181, 插入:31913
插入后的结果是:10274 10793 11818 20114 31931 19115 13644 31913 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:3, 它之前的值:20114, 插入:17146
插入后的结果是:10274 10793 11818 17146 20114 31931 19115 13644 31913 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:2, 它之前的值:11818, 插入:32497
插入后的结果是:10274 10793 32497 11818 17146 20114 31931 19115 13644 31913 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:7, 它之前的值:19115, 插入:6922
插入后的结果是:10274 10793 32497 11818 17146 20114 31931 6922 19115 13644 31913 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:9, 它之前的值:13644, 插入:25708
插入后的结果是:10274 10793 32497 11818 17146 20114 31931 6922 19115 25708 13644 31913 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:4, 它之前的值:17146, 插入:13749
插入后的结果是:10274 10793 32497 11818 13749 17146 20114 31931 6922 19115 25708 13644 31913 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
被插入的点位是:7, 它之前的值:31931, 插入:9589
插入后的结果是:10274 10793 32497 11818 13749 17146 20114 9589 31931 6922 19115 25708 13644 31913 19181 7052 26712 11376 28005 7357 30377 10814 6280 3315 9929 5428 29343 2828 28584 14428 14869 8987
完整代码
#include <iostream>
#include <stdarg.h>
#include <vector>
#include <ctime>
#define remilia int
#define isMyWife main

using namespace std;

template<class ElemType, int MAX_SIZE>
class SequentialList {
	private:
		// 数据的存储容器 
		ElemType data[MAX_SIZE];
		
		// 数组的实际元素数量 
		int actualLength;
		
	public:
		SequentialList(ElemType elem[], int paramsCount);
		SequentialList();
		virtual ~SequentialList();
		
		// 获得顺序表长 
		int getActualLength(); 
		bool isEmpty();
		bool isFull();
	
		// 输出顺序表所有元素 
		void outputList();
		
		// 在顺序表末尾插入一个元素 
		void pushBack(ElemType elem);
		
		// 在线性表指定位置插入一个元素 
		void sequentialListInsert(int paraPosition, int paraValue);
		
		// 删除指定位置的元素 
		int sequentialListDelete(int paraPosition);
		
		// 根据值定位线性表中的元素 
		vector<int> locateElement(int paraValue);
		
		// 根据索引获取元素 
		int getElement(int paraPosition);
		
		// 清除顺序表 
		void clearList();
};

template <class ElemType, int MAX_SIZE>
SequentialList<ElemType, MAX_SIZE>::~SequentialList() {
	
}

template <class ElemType, int MAX_SIZE>
SequentialList<ElemType, MAX_SIZE>::SequentialList(ElemType elem[], int paramsCount) {
	if (paramsCount > MAX_SIZE) {
		throw "参数过多...";	
	}
	
	for (int i = 0; i < paramsCount; i++) {
		this -> pushBack(elem[i]);
	}
}

template <class ElemType, int MAX_SIZE>
SequentialList<ElemType, MAX_SIZE>::SequentialList() {
	this -> actualLength = 0;
}

template <class ElemType, int MAX_SIZE>
int SequentialList<ElemType, MAX_SIZE>::getActualLength() {
	return this -> actualLength;
}

template <class ElemType, int MAX_SIZE>
bool SequentialList<ElemType, MAX_SIZE>::isEmpty() {
	return this -> actualLength == 0;	
}

template <class ElemType, int MAX_SIZE>
bool SequentialList<ElemType, MAX_SIZE>::isFull() {
	return this -> actualLength == MAX_SIZE;	
}

template <class ElemType, int MAX_SIZE>
void SequentialList<ElemType, MAX_SIZE>::pushBack(ElemType elem) {
	if (!isFull()) {
		this -> data[this -> actualLength++] = elem;
	} else {
		throw "容量已满, 插入失败...";
	}
}

template <class ElemType, int MAX_SIZE>
void SequentialList<ElemType, MAX_SIZE>::outputList() {
	for (int i = 0; i < this -> actualLength; i++) {
		printf("%d ", this -> data[i]);
	}	
	
	putchar('\n');
}

template <class ElemType, int MAX_SIZE>
int SequentialList<ElemType, MAX_SIZE>::getElement(int paraPosition) {
	if (paraPosition >= this -> actualLength || paraPosition < 0) {
		throw "参数非法... 原因: 获取位置大于已有位置或是获取位置小于0";
	}	
		
	return this -> data[paraPosition];
}

template <class ElemType, int MAX_SIZE>
vector<int> SequentialList<ElemType, MAX_SIZE>::locateElement(int paraValue) {
	vector<int> v;
	v.clear();
	
	for (int i = 0; i < this -> actualLength; i++) {
		if (this -> data[i] == paraValue) {
			v.push_back(i);
		}
	}	
	
	return v;
}

template <class ElemType, int MAX_SIZE>
void SequentialList<ElemType, MAX_SIZE>::sequentialListInsert(int paraPosition, int paraValue) {
	// 判断越界情况 
	if (paraPosition < 0 || isFull() || paraPosition > this -> actualLength) {
		throw "参数非法, 插入失败... 原因: 插入位置大于已有元素数量或是容量已满或是插入位置小于0";
	}
	
	// 后移元素 
	for (int i = actualLength - 1; i >= paraPosition; i--) {
		this -> data[i + 1] = this -> data[i];
	}
	
	this -> data[paraPosition] = paraValue;
	this -> actualLength++;
}

template <class ElemType, int MAX_SIZE>
int SequentialList<ElemType, MAX_SIZE>::sequentialListDelete(int paraPosition) {
	if (paraPosition > this -> actualLength || paraPosition < 0) {
		throw "参数非法, 删除失败... 原因: 删除位置大于已有元素数量或删除位置小于0";
	}	
	
	int temp = this -> data[paraPosition];
	
	for (int i = paraPosition; i < actualLength - 1; i++) {
		this -> data[i] = this -> data[i + 1]; 
	}
	
	this -> actualLength--;
	return temp;
}

template <class ElemType, int MAX_SIZE>
void SequentialList<ElemType, MAX_SIZE>::clearList() {
	this -> actualLength = 0;
}

void sequentialListDeleteTest(SequentialList<int, 200> s) {
	// 随机种子 
	srand(time(NULL));
	
	// 随机生成测试样本 
	for (int i = 0; i <= 20; i++) {
		s.pushBack(rand());
	}
	
	printf("目前顺序表中的值有:");
	s.outputList();
	putchar('\n');
	
	// 随机生成测试删除点位 
	for (int i = 0; i <= 10; i++) {
		int idx = rand() % 10 + 1;
		
		// 确保测试点位合法 
		if (idx < s.getActualLength()) {
			// 先获取值 
			printf("被删除的点位是:%d, 它的值:%d\n", idx, s.getElement(idx));
			// 删除 
			s.sequentialListDelete(idx);
			// 输出删除后结果进行对照 
			printf("删除后的结果是:");
			s.outputList();
		}
	}
}

void sequentialListInsertTest(SequentialList<int, 200> s) {
	// 随机种子 
	srand(time(NULL));
	
	// 随机生成测试样本 
	for (int i = 0; i <= 20; i++) {
		s.pushBack(rand());
	}
	
	printf("目前顺序表中的值有:");
	s.outputList();
	putchar('\n');
	
	// 随机生成测试插入点位 
	for (int i = 0; i <= 10; i++) {
		int idx = rand() % 10 + 1;
		// 随机生成值 
		int elem = rand();
		 
		// 确保测试点位合法 
		if (idx < s.getActualLength()) {
			// 先获取值 
			printf("被插入的点位是:%d, 它之前的值:%d, 插入:%d\n", idx, s.getElement(idx), elem);
			// 插入 
			s.sequentialListInsert(idx, elem);
			// 输出插入后结果进行对照 
			printf("插入后的结果是:");
			s.outputList();
		}
	}
}

remilia isMyWife() {
	SequentialList<int, 200> s;
	sequentialListInsertTest(s);
	
	return 0;
}

动态顺序表

动态顺序表的操作和静态顺序表大体相同, 只是动态顺序表在容量不足时, 需要手动扩容, 我们可以使用realloc来完成这个操作, 将容器改为指针, 并且加入一个变量存储容量, 受vector启发, 我们可以将容量扩为两倍

private:
	ElemType* data;
	int capacity;
void resize() {
	if (this -> actualLength == this -> capacity) {
		size_t newCapacity = !(this -> capacity) ? 1 : 2 * this -> capacity;
		this -> data = (ElemType*) realloc(sizeof(ElemType) * newCapacity);
		this -> capacity = newCapacity;
	} 
}

除了顺序表之外, 链表也是线性表。 在此先不做讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值