Data Structures (一) : 数据结构知识总结(线性结构)

常用数据结构的实现及其重要操作

线性结构

1. 线性表

       a. 顺序表(定长)
       
	   b. 链表(变长)

以下给出链表的一些基本操作:

Ⅰ. 链表倒置(建议画图理解)
ListNode* reverseList(ListNode* head) {
	ListNode* pre = NULL;  // 注意这里的置空
	while (head) {
		ListNode* tmp = head->next;
		head->next = pre;
		pre = head;
		head = tmp;
	}
	return pre;
}
Ⅱ. 判断链表是否有圈 (双指针)
bool hasCycle(ListNode* head) {
	if (head == NULL || !head->next)
		return -1;
	if (head->next->next == head)
		return true;
	bool flag = false;
	ListNode* fast = head;
	ListNode* slow = head;

	while (fast->next->next && slow->next) {  // 注意这里的边界判断,防止越界
		fast = fast->next->next;
		slow = slow->next;

		if (fast == slow)
		{
			flag = true;
			break;
		}
	}
	return flag ? true : -1;
}
Ⅲ. 合并两个有序链表
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
	// 非递归解法
	ListNode* preHead = new ListNode(-1);
	ListNode* pre = preHead;
	
	while (l1 && l2) {
		if (l1->val < l2->val)
		{
			pre->next = l1;
			l1 = l1->next;
		}
		else
		{
			pre->next = l2;
			l2 = l2->next;
		}
		pre = pre->next;
	}
	
	pre->next = l1 == nullptr ? l2 : l1;
	return preHead->next;
}
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
	// 递归解法
	if (l1 == NULL)
		return l2;
	if (l2 == NULL)
		return l1;
	if (l1->val < l2->val) {
		l1->next = mergeTwoLists(l1->next, l2);
		return l1;
	}
	else {
		l2->next = mergeTwoLists(l1, l2->next);
		return l2;
	}
}
Ⅳ. 删除链表倒数第n个元素
ListNode* removeNthFromEnd(ListNode* head, int n) {
	ListNode* fast = head;
	ListNode* slow = head;
	ListNode* prev = head;
	
	for (int i = 0; i < n - 1; i++)  // 双指针思想:让快指针先走 n-1 步
		fast = fast->next;
		
	while (fast) {
		prev = slow;
		slow = slow->next;
		fast = fast->next;
	}

	if (slow->next == NULL) {     // 待删结点为尾结点
		prev->next = NULL;
	}
	else {
		prev->next = slow->next;  // 待删结点不为尾结点
	}
	
	delete slow;
	return head;
}
Ⅴ. 返回链表的中间结点
ListNode* middleNode(ListNode* head) {
	ListNode* fast = head;
	ListNode* slow = head;
	
	while (fast && fast->next) {  // 注意此处的判断条件有两个(分别对应偶数和奇数)且顺序不可颠倒
		fast = fast->next->next;
		slow = slow->next;
	}
	
	return slow;
}

2. 栈(限制访问端口的线性表)

       a. 顺序栈的实现
template<class T>
class stack {
private:
    int maxSize;  // 栈的最大值
    int top;      // 栈顶位置   
    T* st;        // 存放栈元素的数组
public:
    stack(int size) :maxSize(size), top(-1) { st = new T[size]; }  // 给定长度的实例
    
    stack() :top(-1){}
    
    ~stack() { delete[] st; }
    
    void clear() {                // 清空栈的内容
        top = -1;
    }

    bool Push(const T item) {     // 入栈操作
        if (top == maxSize - 1) {
            cout << "No place for a new item!" << endl;
            return false;
        }
        else {
            st[++top] = item;
            return true;
        }
    }

    bool Push_f(const T item) {   // 若执意入栈,则先扩大size
        if (top == maxSize - 1) {
            T* newSt = new T[maxSize * 2];
            for (int i = 0; i <= top; i++) {
                newSt[i] = st[i];
            }
            maxSize = maxSize * 2;
            st = newSt;
        }
        st[++top] = item;
        return true;
    }

    bool Pop(T& item) {           // 出栈操作
        if (top == -1) {
            cout << "Stack is empty!" << endl;
            return false;
        }
        else {
            item = st[top--];
            return true;
        }
    }

    bool Top(T& item) {           // 取栈顶元素
        if (top == -1) {
            cout << "Stack is empty!" << endl;
            return false;
        }
        else {
            item = st[top];
            return true;
        }
    }
};
       b.链式栈的实现(待更新...)

3. 队列(限制访问端口的线性表)

       a.顺序队列的实现
   
说明: 为解决队列插入时的”假溢出“现象,我们采用取余的方法构造逻辑上的环形队列,即增加一个空间,
      使得下标 x 的后继位置为 (x + 1) % maxSize , 此处的 maxSize 为 实际的元素个数加一
      简而言之,两个重要的判断条件是:
      A. 队列满时 (rear + 1) / maxsize == front
      B. 队列空时 rear == front
template<class T>
class Queue {
private:
    int maxSize;   // 队列数组的大小
    int front;     // 对头元素下标
    int rear;      // 队尾元素下标
    int* queue;    // 存放队列元素的数组
public:
    Queue(int size) {
        maxSize = size + 1;               // 注意此处多出一个空间, 区分队列空与满(待说明...)
        queue = new T[size + 1];
        front = rear = 0;
    }

    ~Queue() { delete[]queue; }           // 析构函数

    void clear() {                        // 清空队列
        front = rear;                     // 注意此处的条件:首尾相遇意味着队列为空
    }

    bool EnQueue(const T item) {
        if ((rear + 1) % maxSize == front) {
            cout << "Queue is full!" << endl;
            return false;
        }
        else {
            queue[rear] = item;           // 正常情况下queue[rear]没有值,是待填充的
            rear = (rear + 1) % maxSize;  // 注意 ++ 操作的改变
            return true;
        }
    }

    bool DeQueue(T& item) {               // 返回并删除队首
        if (front == rear) {
            cout << "Queue is empty!" << endl;
            return false;
        }
        item = queue[front];
        front = (front + 1) % maxSize;    // 注意 ++ 操作的改变
        return true;
    }

    bool GetFront(T& item) {              // 返回但不删除队首
        if (front == rear) {
            cout << "Queue is empty!" << endl;
            return false;
        }
        item = queue[front];
        return true;
    }
};
       b.链式队列的实现(待补充...)

4. 字符串

       KMF模式匹配
      
       1. Next 数组的实现

Next 数组实现

       2. 匹配算法主体的实现

匹配算法实现

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值